1 主从复制

现在从服务器上绑定主服务器。

replicaof <服务器 A 的 IP 地址> <服务器 A 的 Redis 端口号>

开启第一次同步

  1. 第一阶段:建立链接、协商同步
    • 从 -> 主服务器发送psync命令。第一次同步时从节点不知道主节点 runid,所以传 ?,offset-1,表示请求全量同步。
    • 主 -> 从服务器返回 FULLRESYNC(全量复制) 。两个参数:主服务器的 runlD 和 offset 。
  2. 第二阶段:主服务器同步数据给从服务器
    • 主 执行bgsave命令生成RDB文件 -> 从服务器收到RDB文件后,先清空再载入RDB。
    • 为了主从一致性,主服务器在下面这三个时间间隙中将收到的写操作命令,写入到replication buffer 缓冲区里:
      • 主服务器生成RDB文件期间;
      • 主服务器发送RDB文件给从服务器期间;
      • 「从服务器」加载RDB文件期间。
  3. 第三阶段:主服务器发送新写操作命令给从服务器
    • 从服务器完成RDB的载入后,会回复一个确认消息给主服务器。
    • 接着,主服务器将 replication buffer 缓冲区里的写操作发送给从服务器,完成一致性要求。

至此,主从服务器的第一次同步的工作就完成了。主从服务器在完成第一次同步后,双方之间就会维护一个 TCP 连接。后续主服务器可以通过这个连接继续将写操作命令传播给从服务器。

从服务器经理

如果绑的是从服务器,会把目标服务器当作"经理"。实质就是为了防止主服务器同步压力过大,让从服务器也可以传递同步行为。变成了 主 -> 从 -> 从 演变成了树状结构,那由经理同步的自然是要比经理本身慢一拍的。

增量复制

当主从之间网络波动,重连后怎么同步呢?全量复制开销过大。所以采用增量复制,将新增加的同步。肯定需要一个队列来维护增量,并且像这种可能超量写入的肯定采用环形队列,mySQL的redo log也有类似循环设计。还需要一个指针,并且主服务器记自己写的地方,而从服务器记自己读的地方。
在Redis中分别为repl_backlog_bufferreplication offset

那么,判断复制那些就很简单了,如果从服务器能在缓存区找到自己的指针记录的写操作,同步即可。找不到说明已经被覆盖,时间过于久远,需要全量同步。理所当然,可以通过优化缓存区来减少全量同步

2 哨兵机制

主从复制为了防止主宕机,但总不能24小时看着把,哨兵就是自动化主从节点切换的机制。

判断主服务器挂了

  1. 主观下线:没连上,但不知道是挂了还是网络波动
  2. 客观下线:大家都连不上(投票),大抵是真挂了。所以哨兵是要集群部署的,一般3个。

由提出主观下线的哨兵发起投票,票数过半则通过视为客观下线(第一次投票),且由发起者请求成为Leader负责主从切换(第二次投票)。

这里存在并发问题,两个哨兵同时发现客观下线,同时竞争Leader,所以投票默认给自己一票,并且本轮投票周期内只投一次票。也就是先到先得。

一般这种选举制都采用奇数,这样易判定过半。当哨兵挂的过半会出现,第一次投票过了,第二次投票无法通过的情况。

主从故障转移

  1. 步骤一:选出新主节点
    • 先筛选掉网络差的,down-after-milliseconds 10次
    • 优先级排序选择,小在前
    • 哪个复制内容多
    • ID小的
    • SLAVEOF no one 命令去提示选中的节点升级为主节点,每秒INFO监督,返回master说明升级成功
  2. 步骤二:将从节点指向新主节点
    • SLAVEOF 命令去提示从节点链接新主节点
  3. 步骤三:通知客户的主节点已更换
    • 发布者/订阅者机制来实现通知客户端。switch-master频道。(这个是哨兵自己的消息订阅)
  4. 步骤四:将旧主节点变为从节点
    • SLAVEOF 发给原来的主节点(假如他上线了)让他也变成从节点。

哨兵集群

Redis的分布订阅机制,__sentinel__:hello频道实现哨兵集群的自动化发现与订阅。

获取从节点信息:主节点知道所有「从节点」的信息,哨兵会每10秒向主节点发送INFO命令来获取所有「从节点」的信息。

3 Cluster 集群

哨兵虽然解决了主从问题,但还是单体的,没有解决切片储存。cluster就是一个专门用于切片的集群架构。

分片过程

先用CRC16算法生成16bit的数,对16384取模。所有的key都分为这16384个槽中的一个。切片就是分配这个槽位。

MOVED重定向

客户端数据读写 -> 某Redis节点 ,如果该的槽不是在该节点上(发生扩容,主从切换),返回MOVED重定向错误,并携带目标节点的IP和port端口。

ASK 重定向

MOVED采用在迁移完成的情况,客户收到后会改路由表,下次找该槽点会去新节点。而ASK是迁移中,ASK提示客户端,这次你的key在其他节点,临时重定向,客户端不会改路由表。

Gossip协议

分享方式是周期性的随机选择一些节点,并把信息传递给这些节点。

  1. meet消息:通知新节点加入。
  2. ping消息:每秒会向集群中其他节点发送ping消息,带着已知的两个节点的地址、槽、状态信息、最后一次通信时间等
  3. pong消息:当接收到ping、meet消息时,作为响应消息回复。消息中同样带有自己已知的两个节点信息。
  4. fail消息:当节点判定集群内另一个节点下线时,会向"集体"广播一个fail消息,其他节点接收到fail消息之后把对应节点更新为下线状态。

故障节点切换

依旧是主客观下线。

  1. 如果主观下线会在ping里放一个pfail并有限广播。
  2. 如果发现pfail的数量到半数以上,由发现者全体广播fail,提示所有节点该节点客观下线。
  3. 故障恢复:如果下线节点的是主节点,则需要在它的从节点中选一个替换它,流程如下:
    • 资格检查
    • 准备选举时间
    • 发起选举
    • 选举投票:只有持有槽的主节点才有票