redis cluster原理

1、节点间通信
redis cluster 节点之间采用Gossip协议进行通信,Gossip协议就是指节点彼此之间不断通信交换信息。当主从角色变化或新增节点,彼此通过ping/pong进行通信知道全部节点的最新状态并达到集群同步。
Gossip协议的主要职责就是信息交换,信息交换的载体就是节点之间彼此发送的Gossip消息,常用的Gossip消息有ping消息、pong消息、meet消息、fail消息
meet消息:用于通知新节点加入,消息发送者通知接收者加入到当前集群,meet消息通信完后,接收节点会加入到集群中,并进行周期性ping pong交换
ping消息:集群内交换最频繁的消息,集群内每个节点每秒向其它节点发ping消息,用于检测节点是在在线和状态信息,ping消息发送封装自身节点和其他节点的状态数据;
pong消息,当接收到ping meet消息时,作为响应消息返回给发送方,用来确认正常通信,pong消息也封闭了自身状态数据;
fail消息:当节点判定集群内的另一节点下线时,会向集群内广播一个fail消息;
2、消息解析流程
所有消息格式为:消息头、消息体,消息头包含发送节点自身状态数据(比如节点ID、槽映射、节点角色、是否下线等),接收节点根据消息头可以获取到发送节点的相关数据。

3、选择节点并发送ping消息:
Gossip协议信息的交换机制具有天然的分布式特性,但ping pong发送的频率很高,可以实时得到其它节点的状态数据,但频率高会加重带宽和计算能力,因此每次都会有目的性地选择一些节点; 但是节点选择过少又会影响故障判断的速度,redis集群的Gossip协议兼顾了这两者的优缺点,看下图:

不难看出:节点选择的流程可以看出消息交换成本主要体现在发送消息的节点数量和每个消息携带的数据量
流程说明:
A,选择发送消息的节点数量:集群内每个节点维护定时任务默认为每秒执行10次,每秒会随机选取5个节点,找出最久没有通信的节点发送ping消息,用来保证信息交换的随机性,每100毫秒都会扫描本地节点列表,如果发现节点最近一次接受pong消息的时间大于cluster-node-timeout/2 则立刻发送ping消息,这样做目的是防止该节点信息太长时间没更新,当我们宽带资源紧张时,在可redis.conf将cluster-node-timeout 15000  改成30秒,但不能过度加大;
B,消息数据:节点自身信息和其他节点信息;
4、集群扩容
 这也是分布式存储最常见的需求,当我们存储不够用时,要考虑扩容
       扩容步骤如下:
A,准备好新节点
B,加入集群,迁移槽和数据

1)、同目录下新增redis6382.conf、redis6392.conf两
启动两个新redis节点
./redis-server clusterconf/redis6382.conf &  (新主节点)
./redis-server clusterconf/redis6392.conf &   (新从节点)
2)、新增主节点
 ./redis-trib.rb add-node 192.168.1.111:6382 192.168.1.111:6379 
6379是原存在的主节点,6382是新的主节点
3)、添加从节点
redis-trib.rb add-node --slave --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.1.111:6392 192.168.1.111:6379 
    --slave,表示添加的是从节点
    --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2表示主节点6382的master_id
    192.168.1.111:6392,新从节点
    192.168.1.111:6379集群原存在的旧节点
4),重新分配哈希槽
redis-trib.rb reshard 192.168.1.111:6382   //为新主节点重新分配solt
How many slots do you want to move (from 1 to 16384)? 1000 //设置slot数1000
What is the receiving node ID? 464bc7590400441fafb63f2 //新节点node id
Source node #1:all //表示全部节点重新洗牌
Do you want to proceed with the proposed reshard plan (yes/no)? yes //是否同意所提议的洗牌计划
以redis cluster启动配置中的集群为基础,添加6679跟6680两个节点,其中6679作为主节点

可以看到,新加入的节点6679是主节点,分配了1000个哈希槽(并不是16383最后的一千个分给了新节点,而是中间的一部分),剩余的哈希槽另外三个master平均分配;
5、集群缩减节点
集群同时也支持节点下线,下线流程如下:

流程说明:
A,确定下线节点是否存在槽slot,如果有,需要先把槽迁移到其他节点,保证整个集群槽节点映射的完整性;
B,当下线的节点没有槽或本身是从节点时,就可以通知集群内其它节点(或者叫忘记节点),当下线节点被忘记后正常关闭。
主节点6382删除步骤:
1,./redis-trib.rb reshard 192.168.2.100:6679
  问我们有多少个哈希槽要移走,同样需要重新分配哈希槽,因为我们这个节点上刚分配了1000 个所以我们这里输入1000
2,最后
./redis-trib.rb del-node 192.168.1.111:6382 3e50c6398c75e0088a41f908071c2c2eda1dc900
此时节点下线完成……
6、故障转移
redis集群实现了高可用,当集群内少量节点出现故障时,通过故障转移可以保证集群正常对外提供服务。
当集群里某个节点出现了问题,redis集群内的节点通过ping pong消息发现节点是否健康,是否有故障,其实主要环节也包括了 主观下线和客观下线;
主观下线:指某个节点认为另一个节点不可用,即下线状态,当然这个状态不是最终的故障判定,只能代表这个节点自身的意见,也有可能存在误判;

下线流程:
  A,节点a发送ping消息给节点b ,如果通信正常将接收到pong消息,节点a更新最近一次与节点b的通信时间;
  B,如果节点a与节点b通信出现问题则断开连接,下次会进行重连,如果一直通信失败,则它们的最后通信时间将无法更新;
  C,节点a内的定时任务检测到与节点b最后通信时间超过cluster_note-timeout时,更新本地对节点b的状态为主观下线(pfail)
客观下线:指真正的下线,集群内多个节点都认为该节点不可用,达成共识,将它下线,如果下线的节点为主节点,还要对它进行故障转移
  假如节点a标记节点b为主观下线,一段时间后节点a通过消息把节点b的状态发到其它节点,当节点c接受到消息并解析出消息体时,会发现节点b的pfail状态时,会触发客观下线流程;
当下线为主节点时,此时redis集群为统计持有槽的主节点投票数是否达到一半,当下线报告统计数大于一半时,被标记为客观下线状态;

7、故障恢复:
故障主节点下线后,如果下线节点的是主节点,则需要在它的从节点中选一个替换它,保证集群的高可用;转移过程如下:

  1,资格检查:检查该从节点是否有资格替换故障主节点,如果此从节点与主节点断开过通信,那么当前从节点不具体故障转移;
  2,准备选举时间:当从节点符合故障转移资格后,更新触发故障选举时间,只有到达该时间后才能执行后续流程;
  3,发起选举:当到达故障选举时间时,进行选举;
  4,选举投票:只有持有槽的主节点才有票,会处理故障选举消息,投票过程其实是一个领导者选举(选举从节点为领导者)的过程,每个主节点只能投一张票给从节点,
当从节点收集到足够的选票(大于N/2+1)后,触发替换主节点操作,撤销原故障主节点的槽,委派给自己,并广播自己的委派消息,通知集群内所有节点。

---------------------------------------

over

posted @ 2018-03-25 22:16  facelessvoidwang  阅读(329)  评论(0编辑  收藏  举报