Ryo's blog

标签 · Backend

首页

关于

归档

BackendGolang

Golang Memory Model

一、背景1.1 一个 Code Review 引发的思考一个同学在 Golang 项目里面用 Double Check(不清楚的同学可以去百度搜下,Java中比较常见)的方式实现了一个单例。具体实现如下: var ( lock sync.Mutex instance *UserInfo ) func getInstance() (*UserInfo, error) { if instance == nil { //---Lock lock.Lock() defer lock.Unlock() if instance == nil { instance = &UserInfo{ ..

更多
BackendGolang

深入理解 Golang Stack

基础知识Linux 进程地址空间布局我们知道CPU有实模式和保护模式,系统刚刚启动的时候是运行在实模式下,然后经过一系列初始化工作以后,Linux会把CPU的实模式改为保护模式(具体就是修改CPU的CR0寄存器相关标记位),在保护模式下,CPU访问的地址都是虚拟地址(逻辑地址)。Linux 为了每个进程维护了一个单独的虚拟地址空间,虚拟地址空间又分为“用户空间”和“内核空间”。 虚拟地址空间更多相关可以看Linux内核虚拟地址空间这篇文章。 Golang 栈内存在虚拟地址空间哪个区域Golang 的内存管理是用的 TCMalloc(Thread-Caching Malloc)算法, 简单点说就是 Golang 是使用 mmap 函数去操作系统申请一大块内存,然后把内存按照 8Byte~32KB 6..

更多
BackendMiddlewareMySQL

MySQL Insert 死锁问题研究

背景不想看废话的,建议直接去最后看死锁的本质原因。 问题背景线上一个很简单结构的表,报insert死锁,这个表基本上只有insert操作,所以引出一个问题insert 和insert之间为什么会死锁? 顺便说下我们线上库的隔离级别都是RC,日志格式是ROW,我下面所有测试都是在RC下。 *** (1) TRANSACTION: TRANSACTION 2404187192, ACTIVE 0 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 8 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 118913019, OS thread handle 140411115681..

更多
BackendMySQL

MySQL DateTime和Timespan时区问题

一、背景最近负责一个数据传输的项目,其中一个需求就是能把一个DB里面的数据拉出来 ,然后回放到另外一个同构的DB。两个DB的服务不在一个时区(其实这不是重点),可能配置不同。之前有过类似的项目,当时是基建的同事负责做数据同步,同步过去以后DateTime、Timespan字段的时区信息都丢了。老板让我调研下问题根因,不要踩之前的坑。 最早的时候看了下同事写的当时MySQL时区信息丢失的问题总结文档,文档里面当时把DateTime和Timespan两个时区问题混为一起了,也没分析本质原因,导致我当时没看太明白,然后的武断的认为,之所以时区丢失了,是因为基础组件同步DateTime和TimeSpan的时候同步的是字符串,比如2021-11-27 10:49:35.857969这种信息,我们传输的时候,只要转Un..

更多
BackendMiddlewareEnvoy

Envoy 编译调试

Debian9 上编译调试主要参考Envoy官方的Bazel编译文档 下载bazelisk-linux-amd64 sudo wget -O /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 sudo chmod +x /usr/local/bin/bazel 安装依赖 sudo apt-get install \ autoconf \ automake \ cmake \ curl \ libtool \ make \ ninja-build \ patch \ ..

更多
BackendGolang

Golang RWMutext 代码走读

type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // 写的信号量 readerSem uint32 // 读的信号量 readerCount int32 // 等待写的个数 readerWait int32 // 等待读的个数 } // 加“读锁” // 对readerCount + 1 。 // 然后看 readerCount是不是小于0 // 小于0表示 正在加写锁,然后阻塞到rw.readerSem 这个信号上。 func (rw *RWMutex) RLock() { if atomic.AddInt32(..

更多
BackendMiddlewareRedis

Redis 高可用解决方案总结

一、主从复制什么是主从复制我们正常在项目中对redis进行应用,一般都不会是单点的。因为,单点的宕机即不可用,不能保证可用性。另外,单点redis读写指令都会打到同一个服务里面,也会影响性能。在通常的应用中,对redis的读操作远远多于写操作,所以,我们一般会选择“一主多从”的集群策略。 主中的数据有两个副本(replication)即从redis1和从redis2,即使一台服务器宕机其它两台服务也可以继续提供服务。 主中的数据和从上的数据保持实时同步,当主写入数据时通过主从复制机制会复制到两个从服务上。 只有一个主redis,可以有多个从 redis。 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求。 一个可以即是主又是从,如下图: 主从复制过程一般当slav..

更多
BackendMiddlewareRedis

Redis 源码分析(七) :skiplist

一、skiplist由来skiplist本质上也是一种查找结构,用于解决算法中的查找问题(Searching),即根据给定的key,快速查到它所在的位置(或者对应的value)。 我们在《Redis内部数据结构详解》系列的第一篇中介绍dict的时候,曾经讨论过:一般查找问题的解法分为两个大类:一个是基于各种平衡树,一个是基于哈希表。但skiplist却比较特殊,它没法归属到这两大类里面。 这种数据结构是由William Pugh发明的,最早出现于他在1990年发表的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》。对细节感兴趣的同学可以下载论文原文来阅读。 skiplist,顾名思义,首先它是一个list。实际上,它是在有序链表的基础..

更多
BackendMiddlewareRedis

Redis 源码分析(六) :quciklist

一、什么是quicklist由于考虑到链表adlist的附加空间相对太高,prev和next指针就要占去 16 个字节 (64bit系统的指针是8个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。 quicklist是一个3.2版本之后新增的基础数据结构,是redis自定义的一种复杂数据结构,将ziplist和adlist结合到了一个数据结构中。主要是作为list的基础数据结构。在3.2之前,list是根据元素数量的多少采用ziplist或者adlist作为基础数据结构,3.2之后统一改用quicklist,从数据结构的角度来说quicklist结合了两种数据结构的优缺点,复杂但是实用: 链表在插入,删除节点的时间复杂度很低;但是内存利用率低,且由于内存不连续容易产生内存碎片..

更多
BackendMiddlewareRedis

Redis 源码分析(五) :ziplist

一、前言ziplist是redis节省内存的典型例子之一,这个数据结构通过特殊的编码方式将数据存储在连续的内存中。在3.2之前是list的基础数据结构之一,在3.2之后被quicklist替代。但是仍然是zset底层实现之一。 二、存储结构压缩表没有数据结构代码定义,完全是通过内存的特殊编码方式实现的一种紧凑存储数据结构。我们可以通过ziplist的初始化函数和操作api来倒推其内存分布。 #define ZIP_END 255 #define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl))) // 获取ziplist的bytes指针 #define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint..

更多
BackendMiddlewareRedis

Redis 源码分析(四) :intset

一、什么是intsetintset是Redis内存数据结构之一,用来实现Redis的Set结构(当集合元素不大于设定值并且元素都是整数时,就会用intset作为set的底层数据结构),它的特点有: 元素类型只能为数字。 元素有三种类型:int16_t、int32_t、int64_t。 元素有序,不可重复。 intset和sds一样,内存连续,就像数组一样。 二、数据结构定义typedef struct intset { uint32_t encoding; // 编码类型 int16_t、int32_t、int64_t uint32_t length; // 长度 最大长度:2^32 int8_t contents[]; // 柔性数组 } intset; enco..

更多
BackendMiddlewareRedis

Redis 源码分析(三) :dict

一、什么是dictdict (dictionary 字典),通常的存储结构是Key-Value形式的,通过Hash函数对key求Hash值来确定Value的位置,因此也叫Hash表,是一种用来解决算法中查找问题的数据结构,默认的算法复杂度接近O(1),Redis本身也叫Remote Dictionary Server(远程字典服务器),其实也就是一个大字典,它的key通常来说是String类型的,但是Value可以是String、Set、ZSet、Hash、List等不同的类型,下面我们看下dict的数据结构定义。 二、Redis Dict数据结构 从上图可以看出与dict相关的关键数据结构有三个,分别是: dict是Redis中的字典结构,包含两个dictht。 dictht表示一个Hash表。 dic..

更多
BackendMiddlewareRedis

Redis 源码分析(二) :ADList

概述ADList(A generic doubly linked list)是 redis 自定义的一种双向链表,广泛运用于 redisClients 、 redisServer 、发布订阅、慢查询、监视器等。(注:3.0及以前还会被运用于list结构中,在3.2以后被quicklist取代)。 链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。 链表在Redis 中的应用非常广泛,比如列表键的底层实现之一就是链表。当一个列表键包含了数量较多的元素,又或者列表中包含的元素都是比较长的字符串时,Redis 就会使用链表作为列表键的底层实现。 链表结构是 Redis 中一个常用的结构,它可以存储多个字符串 它是有序的 能够存储2的32次方减一个节点(超过 40..

更多
BackendMiddlewareRedis

Redis 源码分析(一) :sds

什么是sds字符串是Redis中最为常见的数据存储类型,其底层实现是简单动态字符串sds(simple dynamic string),是可以修改的字符串。 它类似于Java中的ArrayList,它采用预分配冗余空间的方式来减少内存的频繁分配。 数据结构// 3.0及以前 struct sdshdr { // 记录buf数组中已使用字节数量 unsigned int len; // 记录buf数组中未使用的字节数量 unsigned int free; // 字节数组,存储字符串 char buf[]; }; // >=3.2 struct __attribute__ ((__packed__)) sdshdr5 { unsigned cha..

更多
BackendMiddlewareMySQL

MySQL 索引那些事

1. MySQL 常见几种索引类型1.1 普通索引,是最基本的索引,它没有任何限制。它有以下几种创建方式: (1)直接创建索引 CREATE INDEX index_name ON table(column(length)) (2)修改表结构的方式添加索引 ALTER TABLE table_name ADD INDEX index_name ON (column(length)) (3)创建表的时候同时创建索引 CREATE TABLE `table` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `conten..

更多
BackendMiddlewareMySQL

MyISAM和InnoDB区别和应用场景

什么是MyISAM 和InnoDB MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM所改良。虽然性能极佳,但却有一个缺点:不支持事务处理(transaction)。 InnoDB,是MySQL的数据库引擎之一,为MySQL AB发行binary的标准之一。InnoDB由Innobase Oy公司所开发,2006年五月时由甲骨文公司并购。与传统的ISAM与MyISAM相比,InnoDB的最大特色就是支持了ACID兼容的事务(Transaction)功能,类似于PostgreSQL。 MyISAM:它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,而且..

更多
BackendGolang

Golang 内存对齐问题

什么是内存对齐?CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)。 假设CPU访问粒度是4,也就是一次性可以读取内存中的四个字节内容;当我们不采用内存对齐策略,如果需要访问A中的b元素,CPU需要先取出0-3四个字节的内容,发现没有读取完,还需要再次读取,一共需要进行两次访问内存的操作;而有了内存对齐,参考左图,可一次性取出4-7四个字节的元素也即是b,这样就只需要进行一次访问内存的操作。所以操作系统这样做的原因也就是所谓的拿空间换时间,提高效率。 为什么要内存对齐?会了关于结构体内存大小的计算,可是为什么系统要对于结构体数据进行内存对齐呢,很明显所占用的空间大小要更多。原..

更多
BackendMiddlewareConsul

服务发现之Consul

consul是一个可以提供服务发现,健康检查,多数据中心,Key/Value存储等功能的分布式服务框架 用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更”一站式”,内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等)。使用起来也较为简单。Consul用Golang实现,因此具有天然可移植性(支持Linux、Windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。 Consul 的使用场景 docker 实例的注册与配置共享 coreos 实例的注册与配置共享 vitess 集群 SaaS 应用的配置共享 与 confd ..

更多
Backend

分布式id几种生成方案

一、UUIDUUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。其目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。目前最广泛应用的UUID,是微软公司的全局唯一标识符(GUID),而其他重要的应用,则有Linux ext2/ext3文件系统、LUKS加密分区、GNOME、KDE、Mac OS X等等。另外我们也可以在e2fsprogs包中的UUID库找到实现。 UUID的标准形式包含32个16进制数字,以连字号分为五段,形式为8-4-4..

更多
BackendGolang

Go 执行Lua脚本和JS脚本测试

最近有个需求需要在Go项目里面执行动态脚本,github上有好几个lua执行解释器,但是有很多要不就很久没维护了,要不就没有什么文档,经过几个对比我最后用的是 https://github.com/yuin/gopher-lua。JS解析器用的github.com/robertkrimen/otto。 具体测试代码如下,给有需求的朋友参考。 github地址 package main import ( "fmt" "github.com/robertkrimen/otto" "github.com/yuin/gluamapper" "github.com/yuin/gopher-lua" "time" ) //function add(a, b) //return..

更多
BackendProtobufNetHTPP

测试Protobuf在Http传输测试

Demo:https://github.com/fanlv/ProtobufOnHttpGo 一、编写Proto文件syntax = "proto3"; // 生成go代码 //protoc --go_out=. user.proto // 生成oc代码 //protoc --objc_out=. user.proto package user; message LoginRequest { string username = 1; string password = 2; } message BaseResponse{ int64 code = 1; string msg = 2; } message User{ string uid = 1; string..

更多
BackendIO

高并发服务器IO模型

服务端IO模型总结 草稿 网络框架视角零、Nginx 一、Netty(主从Reactor)MainReactor负责客户端的连接请求,并将请求转交给SubReactor SubReactor负责相应通道的IO读写请求 非IO请求(具体逻辑处理)的任务则会直接写入队列,等待worker threads进行处理 二、GRPC-GO (Goroutine Per Connection)net.Listen -> Serve() -> lis.Accept() net库的accept -> 一个连接开个一个goroutine -> s.handleRawConn(rawConn) -> newHTTP2Transport(conn, authInfo) -> newH..

更多
BackendGolang

跨域请求的几种解决方案

需求背景最近做的Apigate优化,前端的同学要求能在配置后台页面上加上一键测试接口的功能,但是由于浏览器的同源策略防止跨域攻击,所以前端的页面默认是不能请求其他域名的接口。 方案一 Nginx配置代理location /proxy { if ($arg_url) { proxy_pass $arg_url?; } } 最开始为了简单就配置了一个简单的代理,通过url传入想要访问的接口例如: http://nginxserver/proxy?url=http://10.23.39.140:8080/app/list 这样前端需要什么测试什么接口只需要通过url传过来,Nginx会方向代理到对应的url上返回结果。 但是这个方法有个问题,url中的地址支持IP访问,不支持域名的..

更多
BackendHTTPNet

深入浅出HTTP

深入浅出HTTP一、什么是Http和TCP HTTP(HyperText Transfer Protocol)超文本传输协议,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。 TCP(T..

更多
BackendProtobufHTTPNet

Protobuf On HTTP 技术预研 (附代码)

Protobuf 技术预研Demo地址:https://github.com/fanlv/ProtobufOnHttp Demo地址:https://github.com/fanlv/ProtobufOnHttpGo 一、背景现在客户端与服务器通讯主要通过Json来做数据交互,本次调研主要比较Protobuf项目中使用的优缺点,和可行性。 二、Protobuf说明2.1 什么是ProtobufProtocolBuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。大部分IM通讯协议都是使用PB来传输。具体代表性的有支付宝、微信等App。 说白了,PB就是一种序列化协议,我们开发中想在什么场景中使用Protobuf做为数据交换的序列化协议,取决于自己的业务。 2.2 Pro..

更多
NoteBackendMiddlewareETCD

《ETCD实战》

背景ectd 常见问题 etcd 基础 etcd 实践 etcd v2 功能 etcd v2 存在的问题 第一,etcd v2 不支持范围查询和分页。分页对于数据较多的场景是必不可少的。在 Kubernetes 中,在集群规模增大后,Pod、Event 等资源可能会出现数千个以上,但是 etcd v2 不支持分页,不支持范围查询,大包等 expensive request 会导致严重的性能乃至雪崩问题。 第二,etcd v2 不支持多 key 事务。在实际转账等业务场景中,往往我们需要在一个事务中同时更新多个 key。 然后是 Watch 机制可靠性问题。Kubernetes 项目严重依赖 etcd Watch 机制,然而 etcd v2 是内存型、不支持保存 key 历史版本的数据库,只在内存中使用滑动..

更多
NoteBackendSystemComputer

《深入浅出计算机组成原理》

基础篇计算机的基本硬件组成 第一,广。组成原理中的概念非常多,每个概念的信息量也非常大。比如想要理解 CPU 中的算术逻辑单元(也就是 ALU)是怎么实现加法的,需要牵涉到如何把整数表示成二进制,还需要了解这些表示背后的电路、逻辑门、CPU 时钟、触发器等知识。 第二,深。组成原理中的很多概念,阐述开来就是计算机学科的另外一门核心课程。比如,计算机的指令是怎么从你写的 C、Java 这样的高级语言,变成计算机可以执行的机器码的?如果我们展开并深入讲解这个问题,就会变成《编译原理》这样一门核心课程。 第三,学不能致用。学东西是要拿来用的,但因为这门课本身的属性,很多人在学习时,常常沉溺于概念和理论中,无法和自己日常的开发工作联系起来,以此来解决工作中遇到的问题,所以,学习往往没有成就感,就很难有动力坚持下去。..

更多
NoteBackendMiddlewareMySQL

《MySQL实战45讲》

binlog && redo log什么是 binlog binlog 是逻辑日志,记录的是这个语句的原始逻辑/变化,比如“给 ID=2 这一行的 c 字段加 1 ”。 binlog 是追加写,不会覆盖之前的数据,可以提供完整的数据归档的能力。 什么是 redo log redo log 是物理日志,记录的是“在某个数据页上做了什么修改”; redo log 提供 crash-safe 能力。 一般只有4G ,4个文件,循环复写。 binlog 和 redo log 不同点因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插..

更多