自动化运维、大数据、Docker

Memcached 与Redis (3): Redis 的集群与复制

1. Redis 集群
1.1 集群节点

加入集群:

节点使用cluster meet 命令来尝试握手, 若成功, 则加入到相应的集群中.

ClusterNode

节点使用ClusterNode 来记录自己的状态, 并为集群中所有其它节点创建相应的clusterNode.

ClusterNode{ ctime, name, flags, configEpoch, ip, port, clusterLink};
ClusterLink{ ctime, fd, sndbuf, rcvbuf, ClusterNode*};
ClusterState{ mySelf, currentEpoch; state, size, dict* nodes}.

flags 记录着Node 的角色加状态信息.
fd 代表tcp 描述符.
sndbuf 和rcvbuf 作为缓冲区 ,保存着从其它Node 发送和接收到的消息.
ClusterState 是以该Node 的视角来看, 集群目前所处的状态.

1.2 slot

以分片的方式来保存DB中的键值对, 分为16384个slot.
当所有16384个槽都有节点处理时,集群处理OK上线状态.否则为fail.
记录当前Node 被指派的槽信息: clusterNode{ char slots; int numslots};

其中, slots 二进制位为1时代表处理相应数值的槽.

节点会在集群内相互传播槽指派信息.

记录着集群中所有槽的指派信息: clusterState{ clusterNode * slots[16384]};.
通过查看state.slots[i] 的值, 即可得到负责处理槽i 的Node.

可以在online 状态下进行重新分片动作.

1.3 在集群中执行命令

接收命令的Node 会计算出key 属于那个槽,

当该槽并未被指派给自己时, 会向客户端返回MOVED 错误, 指引客户端redirect 至正确的Node.

计算key 所属槽的: slot_number(key) = CRC16(key) & 16383;

集群的客户端会与多个Node创建�TCP 链接, redirect 命令通过转换TCP 来完成命令的发送.

如果与想要redirect 的节点还未建立TCP 链接, 会先建立后再进行转向.
集群模式下的redis-cli 客户端会隐藏MOVED 错误而自动完成redirect.
而单机模式下的客户端因为无法进行redirect, 会打印出MOVED错误.

Node 只能使用0号数据库, 而单机服务器并无该限制.

记录槽和键的对应关系: clusterState{ zskiplist *slot_to_keys}.

1.4 ASK 错误

在重新分片期间, 可能会出现槽的键值同时分布在源和目的节点中的情况.
若源节点发现键已不在自身上, 则向客户端返回ASK错误, 来指引客户端转向正在导入槽的目标节点.

1.5 复制与故障转移.

master 和slave

master负责处理槽;
slave �会复制master 的数据, 并在master 下线后, 代替它继续进行处理.

设置slave节点: cluster replicate .

接收者设置自己的clusterNode *slaveof属性为node_id, 同时修改flags.
此时会开始从master 进行数据复制的动作: slaveof .

clusterNode{ clusterNode *slaves, numslaves}.

记录着正在复制该master的slave信息

故障检测

定期发送PING 消息, 若规定时间内没有返回, 则将节点标记为probable fail(PFAIL).
若集群中, 若半数以上处理槽的master 都将某节点设置为PFAIL, 则该节点将被标记为FAIL, 同时进行广播.

故障转移

如果slave 发现master 已下线, 则开始进行故障转移.

选举新的master

集群的配置纪元为自增计数器, 每一次故障转移会进行自增.
每个处理槽的master 都有一票, 第一个向master 要求投票的slave 将获得master 的投票.
收集到大于N/2个投票的slave 会成为新的 master.

1.6 消息

PING消息.

默认每秒发送一次.
过程: 从已知节点列表中随机选出五个节点, 对其中的最长时间没有发送过PING 的节点发送该消息, 来检测其是否在线.

PONG消息.

对MEET 和PING 的响应.
或者用于让其它节点刷新对自己状态的认识

如: 故障转移后新的master.

PUBLISH消息.

节点收到后, 会执行该命令, 然后向集群广播PUBLISH 消息.

2. 复制

复制分为: 初次复制和断线后复制.

2.1 旧版的实现

同步的实现.

master 在收到SYNC 命令后, 从后台生成RDB 文件, 并使用缓存记录从现在开始的所有写操作.
slave 接收并载入RDB 文件, 并接收执行缓存中记录的写操作.

命令传播.

在同步过后, master 会将其执行的更新命令发送给master, 说明其已达到一致状态.
由于执行SYNC 命令非常耗费资源, 所以在断线后复制时效率不佳.

2.2 新版的实现

完整重同步.

用于初次复制, 步骤等于SYNC.

部分重同步.

处理断线后重复制.
master 只用将断线期间的更新命令发送给slave, 并让其执行.

master 和slave 各自维护各自的replication offset, 并分别在传播和接收传播时加上N.

通过对比offset 的值来得知主从是否处于一致状态.

复制积压缓存区.

由master 负责维护的fixed-size 的FIFO 队列, 默认大小为1MB.
进行命令传播时, 将命令写入缓存区.
缓存区同时会为队列中每个字节记录相应的offset.
对于断线重连的slave, 若其offset 之后的数据仍然存在于缓存区, 则使用部分重同步, 否则就需要使用完全重同步.
根据slave 断线后重连的时长和master 的写命令频率来调整缓存区大小.

服务器运行ID.

对于断线重连的slave, 会将保存的master 的ID发送给重新连接到的master, 若相同,则可以尝试进行部分重同步.

2.3 心跳检测

replconf ACK .
用于检测主从服务器的网络连接状态.
辅助实现min-slaves 配置选项, 以防止master 在不安全状态下执行写命令.
检测命令丢失.

当master 发现slave 的offset 小于自己的offset, 会从复制积压缓存区中找出slave 缺失的数据并进行重发.

3. Sentinel

本质上是运行在特殊模式下的Redis 服务器.
sentinel 成为master 的客户端, 并创建两个指向master 的异步网络连接.

命令连接. 用于向master 发送命令, 并接收命令回复.

订阅连接. 订阅master 的sentinel:hello channel.

获取master 信息.

每隔10秒通过命令连接向master 发送INFO 命令, 然后通过分析返回�获取master 的状态.

本文转载自 title

赞(0) 打赏
蜷缩的蜗牛 , 版权所有丨如未注明 , 均为原创丨 转载请注明蜷缩的蜗牛 » Memcached 与Redis (3): Redis 的集群与复制
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏