一、Sentinel哨兵

哨兵模式每个主从节点都存有全量的数据,如果发生故障由哨兵执行故障转移来保证redis高可用。

1.1 Sentinel节点存储的信息

1.1.1 masters字典:

保存了所有被监视的的主节点信息,键为主服务器名字,字典值为主节点的“实例结构”;

实例结构存储的信息可以是主节点、从节点或者其他Sentinel。包含信息包括runid、name、flags(master、slave)、slaves字典等。

1.1.2 主节点实例结构中的slaves字典

存储的这个主服务器的从节点信息,键为从节点ip:port,值为从节点的实例结构。如果有从节点新增或者更新后,Sentinel监测到会更新slaves字典信息。

1.1.3 主节点实例结构中的Sentinel字典

存储了除了当前的Sentinel节点之外的其他所有监视主节点的Sentinel节点,键ip:port,值为Sentinel的实例结构。

1.2 Sentinel集群中与各节点的连接(异步连接)

1.2.1 与主节点存在命令连接和订阅连接(订阅__sentinel__:hello频道)
  1. 命令连接通过info命令获取主服务的本身信息、从节点信息
  2. 当Sentinel发现新的从服务器节点后,会创建与从节点的命令连接和订阅连接,默认10秒一次使用info命令获取从节点信息,根据这些信息对从节点实例结构进行更新;主节点下线或者故障转移时,Sentinel向所有从服务器发送info命令频率会上升到一秒一次
  3. Sentinel会每两秒一次发送publish命令,此命令向__sentinel__:hello频道发布信息。信息发布之后,其他订阅此频道的Sentinel节点(包括本节点)都能收到消息,这些消息可以在Sentinel节点之间传递信息,根据收到的消息更新Sentinel字典中其他Sentinel节点的实例结构;
  4. 当发现其他的Sentinel节点时,会创建命令连接(相互都有命令连接),不需要订阅连接,因为Sentinel可以在主从节点的订阅频道中获取信息。

连接状态:

slqlite和redis的优缺点 redis cluster和sentinel_服务器

1.3 检测主节点下线

1.3.1 主观下线
  1. Sentinel节点通过命令连接向Sentinel、主、从节点发送ping命令,如果在配置时间阈值内没有返回有效回复,则判断节点主观下线。
  2. Sentinel判断主节点主观下线后,会向其他监视此节点的Sentinel节点发送命令(SENTINEL is-master-down-by-addr)询问,当从其他Sentinel节点接收到足够数量(配置文件阈值)的下线判断后,Sentinel会将此主节点判断为客观下线。
1.3.2 选举领头Sentinel(Raft算法实现)

当主节点客观下线后,Sentinel需要选举出一个领头Sentinel来对节点进行故障转移;

  1. 任何一个监视主节点的Sentinel节点都有可能成为领头Sentinel。每个Sentinel中有配置纪元记录选举信息,先到先得的规则,一个节点选举完之后不会再更改,其他选举请求会被拒绝;(配置纪元里计数器每次选举加一,为了记录当前节点经历了几次选举
  2. 如果一个Sentinel节点支持数量超过半数,则成为领头Sentinel;
  3. 如果给定时限内没有选举出,则过段时间进行下一轮选举,直到选出头节点。
1.3.3 故障转移
  1. 主节点下线后,选出一个从服务器(状态正常、网络正常、最近通信过、复制偏移量最大、运行runid最小的);
  2. 发送slave no one然后每秒一次(之前是十秒一次)发送info命令获取信息直到role信息有slave变为master则表示从节点升级为主节点;
  3. 然后向原来主节点下的所有从节点发送slaveof命令让其复制新的主节点数据;
  4. 原来主节点再次上线后Sentinel会向其发送slaveof命令让它变为新主节点的从节点。

二、Cluster集群

Cluster集群中数据分片存储,每个有效的的主节点处理一部分槽,数据则根据一致性hash算法以key的hash值为基础落到不同的槽中,也就是分布到不同的节点中。Cluster集群支持主从节点的故障转移,在能保证高可用的同时具备高吞吐量的优势。

2.1 命令

#节点列表
cluster nodes
#将ip port加入当前节点所在集群
cluster meet ip port
#分派槽
cluster addslots 0 1 2 ... 10
#集群信息
cluster info
#设置从节点
cluster replicate node_id
cluster meet实现:

命令执行后,当前节点A会与新节点B互相握手,成功后将新节点B信息创建clusterNode增加到clusterState.nodes字典中,B节点也会将A节点信息放到B的clusterState.nodes字典中,并且A节点使用流言协议(gossip协议)将新节点信息传播给其他节点,让其他节点和B节点握手。

2.2 集群数据结构

2.2.1 集群中每个节点会存一个clusterNode结构

clusterNode保存了当前节点的状态,比如创建时间、节点名字、ip、端口、配置纪元、clusterLink(客户端连接信息)、slots[16384/8]二进制位数组、numslots(节点负责处理哪些槽和槽数量)、fail_reports下线报告list(记录其他节点对该节点的下线报告);

clusterNode.slots[16384/8]二进制位数组

例如索引i位值为1,则表示当前节点处理槽i。查询节点负责某个槽或者将某个槽指派给节点负责的时间复杂度为O(1);

集群中节点会将自己负责的clusterNode.slots数组通过消息发送给其他节点,并且每个节点在收到数组后会在clusterState.nodes(clusterNode数组)中找到对应的节点clusterNode更新里面的slots信息。所以每个节点中都知道哪个节点分派了哪些槽

2.2.2 集群中每个节点会存一个clusterState结构

clusterState保存了myself指针、当前节点视角下集群状态、集群中处理槽的节点数量、集群所有节点对应的clusterNode结构的字典nodes、clusterNode *slots[16384]数组记录每个槽对应的节点指针。

clusterState.slots[16384]clusterNode数组

指向clusterNode数组,可以O(1)复杂度查看某个槽是否分派并且分派给了哪个节点。

clusterState.slots_to_keys zskiplist跳跃表

记录了所有数据库键key和槽号的关系,score是槽号,可以方便的操作某个槽对应的所有数据库键。

2.3 槽指派

集群数据库分为16384个槽slot,所有槽都放在节点中处理时,集群处于上线状态ok,相反如果有任何一个槽未处理集群处于下线状态fail。

槽重定向

如果接受命令的服务器,经过key的计算后发现槽指派的是当前节点,则执行命名,如果hash值对应的槽是其他节点,则根据clusterState.slots中槽对应的clusterNode中的ip 端口号通过moved错误返给客户端,客户端接收到moved错误需要重新向返回的ip:port对应的节点再次发送命令。

重新分片

如新增节点,将部分槽分派给新节点,不需要集群下线,redis-trib将需要迁移的槽对应的键值全部迁移到新节点,如果迁移过程中源节点找不到key,则会向客户端返回ASK错误指引客户端去目标节点(新节点)中查看。

2.4 故障处理

集群中的每个节点可以设置从节点来复制主节点信息,主节点下线后,集群会选从节点替代主节点处理槽,并且替代主节点其他工作。

2.4.1 故障检测

各节点之间会定时发送PING消息,如果规定时间内没有返回PONG消息,那么发送ping消息的节点则会认为目标节点疑似下线并且在在clusterState.nodes找到对应的clusterNode将状态标为疑似下线。节点间根据消息交换各节点状态信息,如果主节点A通过消息得知主节点B认为主节点C进入疑似下线状态时,主节点A会在自己的clusterState.nodes找到对应的clusterNode将B节点的下线报告加到fail_reports属性中。如果集群中半数以上负责槽处理的主节点认为节点x下线,那么x节点被标记为下线FAIL状态,并向集群中广播x下线消息。

2.4.2 故障转移
  1. 下线主节点的一个从节点被选中执行slave no one成为新主节点(通过选举完成,见2.3.2.1)
  2. 新主节点会撤销下线主节点的槽指派并且将这些槽全部指向自己
  3. 新的主节点向集群中广播一条pong消息告诉其他节点自己成为主节点并且告诉其他节点自己负责处理的槽。
  4. 新主节点开始接收和自己负责处理槽有关的命令,故障转移完成。
2.4.2.1 主节点选举
  1. 当从节点发现自己复制的主节点下线状态时,会向集群中广播一条CLUSTEMSG_TYPE_FAILOVER_AUTH_REQUEST消息要求所有接收到消息并具有投票权(负责处理槽)的主节点向此从节点投票;
  2. 未向其他从节点投票的主节点收到消息后向发送消息的从节点投票返回CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息;
  3. 从节点根据自己收到多少CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息统计自己收到多少票;当投票数大于半数时,当前从节点当选为新的主节点,主节点进行 2.3.2故障转移步骤2的后续操作;
  4. 如果一个配置纪元中没有从节点收到足够的支持投票,则进入下一个新的配置纪元再次进行选举。

2.5 消息传递

cluster集群中消息传递有两种方式

gossip协议传播和广播模式

meet、ping、pong命令都可以传递信息给其他节点。
gossip协议:

节点从列表中找两个未发送过该消息的节点(包括主、从节点,如果从上次发送消息的时间到现在大于设置时间阈值的一半也会发送消息保证消息的更新)发送消息,集群较大时传播到整个集群有延迟。比如cluster meet命令新增节点后,使用gossip协议将新 节点信息传播到整个集群中。

广播模式:

广播到所有节点,及时通知。比如故障转移从节点代替主节点完成后,会广播pong信息到其他节点。