启动集群
修改配置文件,设置cluster-enabled yes
命令
cluster info:查看集群信息
cluster nodes:查看集群节点
cluster meet ip port:关联节点到集群中
cluster addslots <slot> ...:分配槽
cluster keyslot <key>:计算key所在槽
cluster getkeysinslot <slot> <count>:返回指定槽的count数据库键
cluster replicate <node_id>:对指定的node_id进行复制
cluster forget <downnodeid>:忘记节点
搭建集群
准备节点
集群节点在启动的时候,都会生成一个配置文件,由cluster-config-file参数定义,当集群内节点发生变化,如添加节点、节点下线、故障转移等,都会保存在配置文件中,集群配置文件在初始化时会生成节点id等相关信息,节点id是由40位16进制字符串组成,节点id在初始化时只创建一次,节点启动时,会到配置文件中获取这个节点id
节点握手
节点握手是指一批运行在集群模式下的节点通过Gossip(go:sip)协议进行通信,达到感知对方的过程
cluster meet <b_ip> <b_port>
1、节点A向节点B发送MEET消息
2、节点B收到MEET消息后返回PONG消息
3、节点A收到返回的PONG消息,说明节点B正常接收到MEET消息,节点A返回PING消息给节点B
4、节点B接收到PING消息,说明节点A已收到返回的PONG消息,握手成功
槽指派
1、redis集群通过分片的方式保存数据库中的键值对
2、数据库只能选择0
3、集群的整个数据库被分为16384个槽
4、当所有的槽都有节点在处理时,集群处于上线状态,有一个槽没有节点处理,则处于下线状态
5、使用redis-trib.rb设置集群
通信流程
1、集群中的每个节点都会单独开辟一个TCP通道,用于节点之间彼此通信,通信端口在基础端口上加10000
2、每个节点在固定周期内通过特定规则选择几个节点发送PING消息
3、接收到PING消息的节点用PONG消息作为响应
gossip协议,用于信息交换
meet:通知节点加入集群
ping:用于检测节点是否在线和交换彼此信息状态,ping消息发送封装了自身和部分其他节点的状态数据
pong:用于对ping、meet消息的回复,pong消息封装了自身状态数据
fail:节点下线,当一个节点判断另一个节点下线的时候,会向集群广播一个fail消息,其他 节点收到消息后将该节点状态更新为下线状态,fail消息封装的下线节点的id
节点选择:
集群内每个节点维护定时任务默认每秒执行10次,每秒会随机选取5个节点找出最久没有通信的节点发送ping消息,用于保证Gossip信息交换的随机性。每100毫秒都会扫描本地节点列表,如果发现节点最近一次接受pong消息的时间大于cluster_node_timeout/2,则立刻发送ping消息,防止该节点信息太长时间未更新。根据以上规则得出每个节点每秒需要发送ping消息的数量=1+10*num(node.pong_received>cluster_node_timeout/2),因此cluster_node_timeout参数对消息发送的节点数量影响非常大。当我们的带宽资源紧张时,可以适当调大这个参数,如从默认15秒改为30秒来降低带宽占用率。过度调大cluster_node_timeout会影响消息交换的频率从而影响故障转移、槽信息更新、新节点发现的速度。因此需要根据业务容忍度和资源消耗进行平衡。同时整个集群消息总交换量也跟节点数成正比。
在集群中发送命令
对数据库中的16384个槽都进行了分派之后,集群就会进入上线状态,此时就可以对集群进行操作。
当客户端向集群节点发送有关数据库键命令的时候,接收命令的节点根据客户端发送的键计算出所属那个槽,如果在当前节点中,那么由当前节点对命令进行处理,否则返回MOVED(moved <slot> <ip>:<port>
)错误,指引客户端指向正确的节点,并再次发送之前的命令
MOVED错误
当一个节点没有包含指定槽的时候,会返回moved <slot> <ip>:<port>
指引客户端指向正确的节点,并再次发送之前的命令
127.0.0.1:6379> get key
-> Redirected to slot [12539] located at 127.0.0.1:6381
"value"
127.0.0.1:6381>
ASK错误
如果查询的key正在迁移时,会返回ASK错误。
重新分片
1、对目标节点发送cluster setslot importing <source_id>命令,让目标节点准备导入槽的数据
2、对源节点发送cluser setslot migrating <target_id>命令,让源节点准备迁移指定槽的数据
3、源节点循环执行cluster getkeysinslot 命令,获取指定count个属于槽的键
4、在源节点上执行migrate <target_ip> <target_port> 0 keys …命令,把获取的键通过流水线机制批量迁移到目标节点(批量迁移3.0.6后版本支持)
5、重复3、4,直到槽上的所有数据迁移结束
6、向集群内的所有主节点发送cluster setslot node <target_id>命令,通知槽分配给目标节点。
故障检测
集群中的每个节点会定期的向其他节点发送PING消息以此来检查对方是否在线,如果在指定的时间内(cluster-node-timeout)没有返回PONG消息,那么发送节点将接收节点标记为疑似下线(probable fail)。通过Gossip消息传播,集群内的节点不断收到故障节点的下线报告,如果有超过一半数量的主节点将接收节点标记为疑似下线,那么接收节点被标记为已下线,对接收节点标记为已下线的节点会向集群广播一条关于该节点的fail消息,所有收到该fail消息的节点都会将该节点标记为已下线
故障发现
主观下线
1、a节点发送ping消息给b节点,b节点返回pong消息回复,a节点收到回复更新最近一次与b节点的通信时间
2、a节点发送ping消息给b节点,如果通信失败,则不会更新通信时间
3、a节点的定时任务会定时检测节点间的通信时间,如果发现与b节点的最后一次通信时间大于cluster-node-timeout,更新b节点的状态为主观下线(pfail)
客观下线
当某个节点判断另一个节点为主观下线,相应的节点状态会随着消息在集群内传播,当有半数以上持有槽的主节点判断该节点为主观下线,那么标记该节点为客观下线(fail)。
ps:如果包含pfail状态的节点是主节点,则进行处理,从节点则忽略
下线报告的有效期是cluster-node-timeout2,如果在cluster-node-timeout2时间内无法收集到一半以上槽节点的下线报告,那么之前的下线报告会过期
故障恢复
1、在已下线主节点的从节点中选举一个作为新的主节点
2、新的主节点撤销已下线主节点的槽指派,并将这个槽指派给自己
3、向集群中的其他节点广播一条PONG消息,让其他节点知道自己已成为新的主节点,并且可以处理已下线节点负责的槽
选举主节点
1、资格检查:参与选举的从节点与主节点的延迟时间小于cluster-node-timeout*cluster-slave-validity-factor
2、准备选举时间:当从节点符合故障转移资格后,更新触发选举故障时间。复制偏移量越大它的延迟就越低,选举时间在1秒内进行
3、发起选举:当从节点的定时任务检测到故障选举时间(failover_auth_time)到达后,发起选举,向集群广播FAILOVER_AUTH_REQUEST消息
配置纪元的作用:
3.1、标示集群内每个主节点的不同版本和当前集群的最大版本。
3.2、每次集群发生重要事件时,这里的事件指的是新加入的主节点(新加入的或者从节点转换而来的),从节点竞争选举,都会更新全局的配置纪元并赋值给相关主节点。用于记录这一关键事件。
配置纪元的应用场景:
1、新节点的加入
2、槽节点映射冲突检测
3、从节点投票选举冲突检测
4、选举投票:每个拥有槽的主节点都有一次选举的机会,如果接收节点没有给其他节点投过票,则把票投给该节点(返回FAILOVER_AUTH_ACK),否则忽略该请求
5、替换主节点:如果某个节点的投票数大于主节点数量的半数以上,该节点被选举为新的主节点
群,replicas 表示每个主节点有几个从节点