一、主从模式
- 主从服务初次同步过程
- SYNC与PSYNC两个命令的区别
情景:当主从服务同步完,这时从服务器宕机了一段时间,重新上线后必须要重新同步一下主服务器,两个命令区别就在于断线后重新复制阶段处理方式不同。
SYNC:从服务器重新向主服务器发起 SYNC命令,主服务器将所有数据再次生成RDB快照发给从服务器同步。
PSYNC:从服务器重新向主服务器发起 PSYNC命令,主服务器根据双方数据的偏差量判断是否是需要完整重同步还是仅将断线期间执行过的写命令发给从服务器。
鉴于PSYNC命令效率远高于SYNC,因此在redis 2.8版本后都开始使用PSYNC进行复制。
- PSYNC实现部分重同步三部分
-
记录偏移量
主从服务器维护一个复制偏移量。 当主服务器向从服务器发送N个字节数据后,会将自己的复制偏移量+N。从服务器收到主服务器N个字节大小后,也会将自己的复制偏移量+N。
-
复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个先进先出的字节队列,默认大小1mb。每当向从服务器发送写命令时,都会将这些数据存入这个队列。每个字节都会记录自己的复制偏移量。从服务器在重连时会将自己的复制偏移量发送给主服务器,如果该复制偏移量之后的数据存在于复制积压缓冲区中,则仅需要将之后的数据发送给从服务器即可。
-
记录服务器ID
执行主从同步时,主服务器会发送一个自己的服务器ID给从服务器,当从服务器断线重连时会判断当前主服务器ID是否为之前的ID,若一致则会执行部分重同步,若不一致则会执行完全重同步。
二、哨兵模式
主从模式不可实现高可用,因此在次基础上加入了sentinel系统作为监视器,基本原理就是一旦发现主服务器宕机无法工作时,会自动升级一个从服务器作为新的主服务器,以达到故障转移。同样为了达到高可用,sentinel系统也是以集群的方式。
工作过程:
- Sentinel与主服务器建立连接
sentinel服务器启动之后会创建与主服务器连接的命令,并订阅主服务器频道。
sentinel系统默认会每隔10秒向主服务器发送INFO命令,主服务器则会返回自身的信息和所有从服务器信息。
根据返回的信息sentinel若发现有新的从服务器连接了主服务器,则会向新从服务器发送连接命令与订阅命令。
- 判定主服务器是否下线
sentinel服务器每秒会向其连接的所有实例包括主服务器、从服务器、其他sentinel服务器发送PING命令,根据是否回复PONG命令来判断是否下线。
- 判定主观下线 实例在收到PING命令后,在规定时间内(down-after-milliseconds 配置项)未回复。则该实例将会被发起PING命令的sentinel服务器认定为主观下线。
- 判定客观下线 当实例被判定为主观下线后,为确保该实例真的下线,sentinel会向sentinel集群中的其他服务器确认,若sentinel服务器达到一定数量时(一般是N/2+1),那么该实例被判定为主观下线,需要故障转移。
- 选取领头Sentinel
当主服务器判定为客观下线后,sentinel集群会选举一个领头的sentinel来对下线的主服务器进行故障转移操作。选举基于RAFT一致性算法:
- 每个发现主服务器下线的sentinel会要求其他sentinel将自己设置为局部领头
- 接收到的sentinel可以接受 / 拒绝
- 如果有一个sentinel得到一半以上的支持,则此次选举中它为领头
- 如果在给定的时间内没有选举出领头,那么一段时间后重新选举,直到选举成功
- 选举新的主服务器
领头服务器会在从服务器中选取一个成为主服务器,规则:
选择健康的,排除断线以及没有回复INFO命令的
选择优先级配置高的、复制偏移量大的
挑选出新的主服务器后,领头服务器将会向新主服务器发送SLAVEOF NO ONE命令将他真正升级为主服务器,并且修改其他从服务器复制目标。将旧主服务器设为从服务器,达到故障转移。
三、Redis Cluster(簇、点)
该模式主要是解决主从、哨兵这些一主多从模式的性能瓶颈问题。在redis3.0后加入了cluster模式,采用去无心节点方式,集群通过分片方式保存数据库中的键值对。
节点
一个redis集群由多个节点组成,每个节点相互连接,保存自己与其他节点的信息。节点间通过gossip协议交换互相状态。
数据sharding(分片、分表)
redis cluster 整个数据库被分成16384个哈希槽,数据库中的每个键属于这些槽中的其中一个,集群中的每个节点可以存储0到16384个槽。
设置槽指派
通过命令 CLUSTER ADDSLOTS [slot......] 可以将一个或多个槽指派给某个节点。
例如:127.0.0.1:7777> CLUSTER ADDSLOTS 1 2 3 4 5 它表示将1,2,3,4,5号插槽指派给本地端口号为7777的节点负责
设置后节点将会把槽指派信息发送给其他集群,并更新信息。
计算属于哪个槽
def slot_number(key):
return CRC16(key) & 16383
计算哈希槽使用的是CRC16算法对key进行计算后与16383取模得到最终所属插槽。
sharding流程
- 客户端发起键值对操作指令,将任意分配给其中某个节点
- 节点计算出该键值所属插槽,并判断当前节点是否为该键所属插槽
- 是则直接执行操作命令
- 不是则向客户端返回moved错误,错误中将带着正确的节点地址和端口,客户端收到后可以直接转向正确节点。
redis cluster 高可用
redis 的每个节点都可以分为一个主节点与对应从节点。主节点负责处理槽,从节点复制某个主节点,并在主节点下线时,代替下线的主节点。
如何实现故障转移
与哨兵模式类似,redis每个节点会定期向其他节点发送ping命令,以此来检测对方是否在线。当检测到一个节点下线后,会设置为疑似下线。如果有半数以上的节点将某个主节点设为疑似下线,则该节点会被标记为下线状态,并开始故障转移。
- 通过RAFT算法从下线主节点的从节点中选出新的主节点
- 被选中的节点执行slaveof no one 命令,成为新节点
- 新主节点撤掉下线主节点的槽指派,并将槽指派给自己
- 新主节点向集群中广播自己成为了主节点
- 新的住系欸但开始接受和负责自己处理槽有关命令请求