1.概述
除了sentinel方式,redis集群是redis提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。
2.实现
2.1 节点
- 节点A向节点B发送MEET命令,节点B响应PONG,节点A将B添加到自己所属集群里面
- 节点A向节点B发送PING保存心跳
- 节点A通过Gossip协议将B信息传播给集群中的节点
2.2 槽指派
- clusterState结构:记录了当前节点的指针、集群的状态,集群节点的数量、集群节点名单
- clusterNode结构:保存了节点的ip、port、名称、slots[16483/8]数组记录负责哪些槽、numslots负责槽数量;
- slots数组索引i的二进制值=1,表明该节点处理槽i;
- slots数组索引i的二进制值=0,表明该节点不负责处理槽i;
- clusterNode.slots[16384/8],记录单个节点负责哪些槽位,当程序需要将节点的负责的槽信息发送给其他节点,将slots数组发送过去即可。
- clusterState.*slots[16384],每个数组项都是一个指向clusterNode结构的指针,所以只要知道了槽的数组下标,就可以通过clusterState.*slots找到对应的node节点信息,避免去clusterNode.slots遍历;
2.3 在集群中执行命令
- 节点通过返回moved命令,将客户端转向正在负责该槽的节点
- 计算属于哪个槽:通过CRC16(key)&16383计算出slots[i],如果slot[i]=myself,说明槽i是该节点负责,如果不等于myself,向客户端返回moved命令
- 集群节点只使用0号数据库,跟单机版的不同
2.4 重新分片
- 通过redis-trib对集群进行重新分片的操作
2.5 ask
- 如果节点A正在迁移槽i至节点B,那么当前节点A没能在自己的数据库中找到命令指定的数据库键时,节点A会向客户端返回一个ASK错误,指引客户端到节点B继续查找数据库键
2.6 复制和故障转移
- 故障检测
- 集群中的节点会定期向其他节点发送PING消息,如果PING没有在指定时间内返回PONG,那么会将接受PING的节点标记为疑似下线PFAIL。
- 如果在一个集群里,半数以上负责处理槽的主节点都认为某个节点x为疑似下线,那么这个主节点会被标记为下线FAIL,并且向集群广播该节点FAIL的消息。
- 故障转移
- 选中一个从节点;slaveof no one成为主节点;将槽指向自己;向集群广播PONG
- 主节点选举
- RAFT选举
2.7 消息
3.总结
- 集群中的16384个槽可以分别指派给集群中的各个节点,每个节点都会记录哪些槽指派给自己,哪些槽又被指派给了其他节点
- 节点在接收到一个命令请求时,会先检查这个命令请求要处理的键所在的槽是否由自己负责,如果不是的话,节点向客户端返回一个MOVED错误,MOVED错误携带的信息可以指引客户端转向正在负责相关槽的节点
- 对于redis集群的重新分片工作由redis-trib负责执行的,重新分片的关键是将某个槽的所有键值对从一个节点转移到另一个节点
- 如果节点A正在迁移槽i至节点B,那么当前节点A没能在自己的数据库中找到命令指定的数据库键时,节点A会向客户端返回一个ASK错误,指引客户端到节点B继续查找数据库键
- MOVED错误表示槽的负责权已经从一个节点迁移到了另一个节点,而ASK错误只是两个节点正在迁移槽过程中使用的一种临时措施
- 集群中的从节点用于复制主节点,并在主节点下线时,代替主节点继续处理命令请求
- 集群中的节点通过发送消息的方式进行通讯,常见的消息包括:MEET、PING、PONG、PUBLISH、FAIL