Redis集群笔记
前言
该篇主要搬运作者之前记录的Redis集群笔记,内容包括:Redis主从、哨兵以及Redis集群。
主从
全量复制
从下图我们大致可以了解Redis全量复制的一个过程:
- Slave发送psync同步数据指令;
- Master接收命令后通过bgsave生成当前最新的一份rdb数据并发送给Slave,此时客户端针对修改指令Master会将其缓存一份至buffer中;
- Slave接收到Master的rdb数据后,清空老数据并开始加载主节点的rdb数据,加载完毕后再加载Master节点缓存在buffer中的数据;
部分复制
- 假设发生网络抖动,导致slave和master断开连接;
- master会将最近的命令的写一份到repl back buffer中;
- slave重新连接上master之后;
- slave会在此发送psync命令但是会带上offset(内存里的每一条数据都有一个偏移量,并且把最新那条数据offset传给master);
- master拿到offset会将它跟缓冲区里的偏移量最近比对,如果偏移量在缓存区中没有(缓存区一般只有1M,所以不可能所有数据都有)则会触发一次全量同步,如果有master就将偏移量之后的那些命令传给slave;
哨兵模式
哨兵架构下client端第一次从哨兵找出redis主节点,后续就直接访问redis的主节点,不会每次通过sentinel代理访问redis主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端(这里redis的client端一般都是实现了订阅功能,订阅sentinel发布的节点变动消息)
当master失效时,哨兵会从slave节点中选举出一个实例作为新的master节点(sentinel选举出来slave节点内部会将配置文件中的replicof配置删掉),sentinel维护了一个消息队列将新的master节点ip丢进消息队列,client监听到之后将新的master节点ip替换原先旧的master节点ip。
选举
当一个master服务器被某sentinel视为客观下线状态后,该sentinel会与其他sentinel协商的leader进行故障转移工作,每个发现master服务器进入客观下线的sentinel都可以要求其他sentinel选自己为sentinel的leader,选举是先到先得。同时每个sentinel每次选举都会自增配置选举周期,每个选举周期中只会选择一个sentinel的leader。如果所有超过一半的sentinel选举某sentinel作为leader。之后改sentinel进行故障转移操作,从存活的slave中选举出新的master,这个选举过程跟集群的master选举很类似。
哨兵集群只有一个哨兵节点,redis的主从也能正常运行以及选举master,如果master挂了,那唯一的那个哨兵节点就是哨兵leader了,可以正常选举新master。
集群
优势
- 首先哨兵模式存在访问瞬断,在哨兵架构下Master节点断开,哨兵集群会选举出一台slave节点作为Master节点,但是这期间是无法访问的。而redis集群架构当一个小的主从结构中的master断开,redis内部会有个选举机制将一台slave作为Master,但是区别的是客户端执行的命令会经过Hash slot路由到不同的小集群上,比如set readcount 1和incr likecount 1可能会路由到不同的master,这大大减少了访问瞬断的影响。
- 哨兵架构下master主节点的抗并发能力比较弱,集群架构下假设我一个小集群只能抗5w的并发,那么要求是20w,我只要在加3个集群就能实现。
- 哨兵架构一个master能分配的内存有限,但是在redis集群下数据分片存储到不同的redis小集群里面去,每个小集群存放的数据是不同的,这样我只要横向扩容就能实现存储一个比较大的数据,但是redis官方推荐不超高1000个节点。
Hash Slot
redis给一个大的集群指定了16384个slot,将slot分配给个个小集群,比如0-5000分配给第一个集群,5001-1000分配给第二个集群,剩下的分配给第三个集群。redis将key通过算法CRC16生成一个结果,再跟16384取余,将值根据cluster nodes
里面的集群信息分配到具体某个小集群上。因此Redis集群的数量是有上限的。
节点通信机制
redis cluster节点间采取gossip协议进行通信,gossip协议包含多种消息,包括ping,pong,meet,fail等等。
- meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通
信; - ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据(类似自己感知到的集群节点增加和移除,hash slot信息等);
- pong: 对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新;
- fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
选举
当slave发现自己的master变成fail状态时,变尝试进行failover,以期成为新的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程。
- slave发现自己的master变成fail
- 将自己记录的集群currentEpoch+1(就是选举的周期),并广播FILEOVER_AUTH_REQUEST信息
- 其他节点收到该信息之后,只有master节点会响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack,意思就是在一个选举周期里面只发一次ack,说白了就投一次票
- 尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
- slave收到超过半数master的ack后变成新Master(这里就解释了为什么至少需要3个主节点,如果只有2个,其中一个挂了,只剩下一个主节点是不能选举成功的),如果slave没有一个达到选举成功的标准则会将currentEpoch+1,重新发起选举,但是redis为了避免这个情况有一个延迟的机制。
- slave广播pong消息通知其他集群节点
从节点并不是在主节点一进入fail状态就马上尝试发起选举,而是有一定的延迟,一定的延迟能确保我们等待fail状态在集群中传播,如果slave立即尝试选举,其他master或许尚未意识到fail状态,可能会拒绝选举。
延迟计算公式:delay = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000msSLAVE_RANK
表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举。