Redis主从哨兵与集群
Redis主从关系
主从存在的意义
通过持久化功能,Redis保证了即使服务器重启的情况下也不会损失数据。因为持久化会将数据保存到硬盘中。重启时会从硬盘中加载数据。但假设服务器一直宕机下去,那是不是整个业务线程都无法继续进行了呢?
为了避免单点故障,通常的做法是将数据库复制多个副本,部署在不同的服务器上。这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此,Redis提供了复制(replication)功能。可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。
在复制的概念中,数据库分为两类。一类是主数据库(master),另一类是从数据库(slave)。主数据库可以进行读写操作,当写操作导致数据变化时,会自动将数据同步给从数据库。而从数据库一般是只读的。并接受主数据库同步过来的数据。一个主数据库可以拥有多个数据库。而一个从数据库只能拥有一个主数据库。
主从复制
a,方式一、新增 redis6380.conf, 加入 slaveof 192.168.42.111 6379, 在 6379 启动完后再启 6380,完成配置;
b,方式二、在从服务器输入redis-server --slaveof 192.168.42.111 6379
c,查看状态:info replication
d,断开主从复制:在 slave 节点,执行 6380:>slaveof no one
e,断开后再变成主从复制:6380:> slaveof 192.168.42.111 6379
f,数据较重要的节点,主从复制时使用密码验证: requirepass
e,从节点建议用只读模式 slave-read-only=yes, 若从节点修改数据,主从数据不一致
h,传输延迟:主从一般部署在不同机器上,复制时存在网络延时问题,redis 提供
repl-disable-tcp-nodelay 参数决定是否关闭 TCP_NODELAY,默认为关闭
参数关闭时:无论大小都会及时发布到从节点,占带宽,适用于主从网络好的场景,
参数启用时:主节点合并所有数据成 TCP 包节省带宽,默认为 40 毫秒发一次,(类似于心跳)。取决于内核,主从的同步延迟 40 毫秒,适用于网络环境复杂或带宽紧张,如跨机房
主从拓扑()
一主一从
用于主节点故障转移从节点,当主节点的“写”命令并发高且需要持久化,可以只在从节点开启 AOF(持久化),这样即保证了数据的安全性,也避免持久化对主节点的影响
一主多从
针对“读”较多的场景,“读”由多个从节点来分担,但节点越多,主节点同步到多节点的次数也越多,影响带宽,也加重主节点的稳定
树状主从
一主多从的缺点(主节点推送次数多压力大)可用些方案解决,主节点只推送一次数据到从节点 B,C,再由从节点 B 推送到 D,E。减轻主节点推送的压力
复制原理
执行 slave master port 后,与主节点连接,同步主节点的数据,6380:>info replication:查看主从及同步信息
数据同步
redis 2.8 版本以上使用 psync 命令完成同步,过程分“全量”与“部分”复制
全量复制
一般用于初次复制场景(第一次建立 SLAVE 后全量)
部分复制
网络出现问题,从节占再次连主时,主节点补发缺少的数据。Master继续将新的所有收集到的修改命令依次传给slave,完成同步。
心跳
主从有长连接心跳,主节点默认每 10S 向从节点发 ping 命令,repl-ping-slave-period 控制发送频率
主从模式的缺点?
A,我们学习了 redis 的主从复制,但如果说主节点出现问题不能提供服务,需要人工重新把从节点设为主节点,还要通知我们的应用程序更新了主节点的地址,这种处理方式不是科学的,耗时费事(人为干预)
B,同时主节点的写能力是单机的,能力能限 (一个干活的,其他都是混子)
C,而且主节点是单机的,存储能力也有限 (干活的不止能力有限,容量也有限)
Redis哨兵模式
主节点挂了,从节点上位要做哪些事
A,主节点(master)故障,从节点 slave-1 端执行 slaveof no one 后变成新主节点
B,其它的节点成为新主节点的从节点,并从新节点复制数据
哨兵机制(sentinel)的高可用
原理:当主节点出现故障时,由 redis sentinel 自动完成故障发现和转移,并通知应用方,实现高可用性。
其实整个过程只需要一个哨兵节点来完成,首先使用 Raft 算法(选举算法)实现选举机制,选出一个哨兵节点来完成转移和通知 (这个机制有点像法院的审判。所有人都可以对凡人进行监督,发表意见。但最终拍案宣布结果通知我们老百姓的总是唯一的法官大人。可悲的是程序界的领导活干得多好没钱。这感觉完全就是保姆工具人。)。
哨兵的通讯任务
假如你是朱元璋,在没有电话的年代,你需要让你的锦衣卫去监视你手下的大臣们。你会怎么让他们各司其职,但又可以保证他们得到的消息统一呢?
哨兵有三个定时监控任务完成对各节点的发现和监控:
任务 1(10s轮询刷新关系图,多用于检测新节点)
每个哨兵节点每 10 秒会向主节点和从节点发送 info 命令获取最拓扑结构图,哨兵配置时只要配置对主节点的监控即可,通过向主节点发送 info,获取从节点的信息。
当有新的从节点加入时,可以通过此任务发现。
任务2(哨兵微信群,2s分享一次自己判断的主从状态)
每个哨兵节点每隔 2 秒会向 redis 数据节点的指定频道上发送该哨兵节点对于主节点的判断,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点对主节点的判断,其实就是通过消息 publish 和 subscribe 来完成的;(哨兵微信群,讨论自己对每个节点检测的结果)
任务3(1s判断一次其他节点状态)
每隔 1 秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次 ping 命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据。
主观下线和客观下线
主观下线
刚我们知道哨兵节点每隔1s会对主节点和其他从节点发动ping消息做心跳检测。当这些心跳检测时间超过down-after-milliseconds时,哨兵则认为该节点错误或者下线。这叫主观下线(针对某个特定的哨兵对节点的判断)。
客观下线
客观下线:然后每隔 2 秒会向 redis 数据节点的指定频道上分享自己对所有节点是否下线的一个判断。
当主观下线的节点是主节点时,此时该哨兵 3 节点会通过指令 sentinelis-masterdown-by-addr 寻求其它哨兵节点对主节点的判断,当超过 quorum(法定人数)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了,大部分哨兵节点都同意下线操作,也就说是客观下线。
领导者哨兵选举流程
1:自荐
每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵 3)主节点下线时,会向其它哨兵发 is-master-down-by-addr 命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;(所以每个哨兵就会拼命的找主节点的问题,发现问题了自己就有机会成为本次故障转移的哨兵领导)
2:投票
当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者;
3:票数汇总
如果哨兵 3 发现自己在选举的票数大于等于 num(sentinels)/2+1 (超过一半)时,将成为领导者,
如果没有超过,继续选举…………
可见,那个哨兵贡献出了主观下线的提案并被其他哨兵采纳,他就会变为新的领导。
故障转移机制
1:故障转移的发生条件
由 Sentinel 哨兵定期(1s/次)监控发现主节点是否出现了故障。sentinel 会向 master 发送心跳 PING 来确认 master 是否存活,如果 master 在“一定时间范围”内不回应 PONG 或者是回复了一个错误消息,那么这个 sentinel 会主观地(单方面地)认为这个 master 已经不可用了,主观下线。
2:主观下线变为客观下线,该节点选举为领导
当主节点出现故障,此时 3 个 Sentinel 节点共同选举了 Sentinel3 节点为领导,负责处理主节点的故障转移,
3:由领导哨兵开始执行故障转移
由 Sentinel3 领导者节点执行故障转移,过程和主从复制一样,但是自动执行
流程
1:将 slave-1 脱离原从节点,升级主节点
2:将从节点 slave-2 指向新的主节点
3:通知客户端主节点更换
4:将原主节点(oldMaster)变成从节点,指向新的主节点
4:故障转移后的redis sentinel 的拓扑结构图
哨兵机制—故障转移详细流程
A,过滤掉不健康的(下线或断线),没有回复过哨兵 ping 响应的从节点
B,选择 slave-priority 从节点优先级最高(redis.conf)
C,选择复制偏移量最大,指复制最完整的从节点
哨兵的安装与部署
部署案例一
我们以 3 个 Sentinel 节点、2 个从节点、1 个主节点为例进行安装部署
1. 搭建Redis一主两从
先搭好一主两从 redis 的主从复制,和之前复制搭建一样,搭建方式如下:
A 主节点 6379 节点(/usr/local/bin/conf/redis6379.conf):
修改 requirepass 12345678,注释掉#bind 127.0.0.1
B 从节点 redis6380.conf 和 redis6381.conf:
修改 requirepass 12345678 ,注释掉#bind 127.0.0.1,
加上 masterauth 12345678 ,加上 slaveof 127.0.0.1 6379
注意:当主从起来后,主节点可读写,从节点只可读不可写
2. redis sentinel哨兵机制核心配置
/usr/local/bin/conf/sentinel_26379.conf
/usr/local/bin/conf/sentinel_26380.conf
/usr/local/bin/conf/sentinel_26381.conf
将三个文件的端口改成: 26379 26380 26381
然后:sentinel monitor mymaster 190.168.1.111 6379 2 //监听主节点 6379。2代表有两个哨兵觉得节点有问题,就触发客观下线。
sentinel auth-pass mymaster 12345678
//连接主节点时的密码
三个配置除端口外,其它一样
3. 哨兵的其它配置
只要修改每个 sentinel.conf 的这段配置即可:
sentinel monitor mymaster 192.168.1.10 6379 2
//监控主节点的 IP 地址端口,sentinel 监控的 master 的名字叫做 mymaster 。 2 代表,当集群中有 2 个 sentinel 认为 master 死了时,才能真正认为该 master已经不可用了
sentinel auth-pass mymaster 12345678 //sentinel 连主节点的密码
sentinel config-epoch mymaster 2 //故障转移时最多可以有 2 从节点同时对新主节点进行数据同步
sentinel leader-epoch mymaster 2
sentinel failover-timeout mymasterA 180000 //故障转移超时时间 180s,
a,如果转移超时失败,下次转移时时间为之前的 2 倍;
b,从节点变主节点时,从节点执行 slaveof no one 命令一直失败的话,当时间超过 180S 时,则故障转移失败
c,从节点复制新主节点时间超过 180S 转移失败
sentinel down-after-milliseconds mymasterA 300000//sentinel 哨兵定期向主节点ping 命令,当超过了 300S 时间后没有回复,可能就认定为此主节点出现故障了……
sentinel parallel-syncs mymasterA 1 //故障转移后,1 代表每个从节点按顺序排队一个一个复制主节点数据,如果为 3,指 3 个从节点同时并发复制主节点数据,不会影响阻塞,但存在 网络和 IO 开销
4. 启动/关闭哨兵服务
启动:
./redis-sentinel conf/sentinel_26379.conf &
./redis-sentinel conf/sentinel_26380.conf &
./redis-sentinel conf/sentinel_26381.conf &
关闭:
./redis-cli -h 192.168.42.111 -p 26379 shutdown
5. 测试
kill -9 6379 杀掉 6379 的 redis 服务
看日志是分配 6380 还是 6381 做为主节点,当 6379 服务再启动时,已变成从节点
假设 6380 升级为主节点:进入 6380>info replication 可以看到 role:master
打开 sentinel_26379.conf 等三个配置,sentinel monitor mymaster 127.0.0.1 6380 2
打开 redis6379.conf 等三个配置, slaveof 192.168.42.111 6380,也变成了 6380
注意:生产环境建议让 redis Sentinel 部署到不同的物理机上。
重 要: sentinel monitor mymaster 192.168.42.111 6379 2 //切 记 将 IP 不 要 写 成
127.0.0.1
不然使用 JedisSentinelPool 取 jedis 连接的时候会变成取 127.0.0.1 6379 的错误地址
注:我们稍后要启动四个 redis 实例,其中端口为 6379 的 redis 设为 master,其他两个设为 slave 。所以 mymaster 后跟的是 master 的 ip 和端口,最后一个’2’代表只要有 2 个 sentinel 认为 master 下线,就认为该 master 客观下线,选举产生新的 master。通常最后一个参数不能多于启动的 sentinel 实例数。
哨兵 sentinel 个数为奇数,选举嘛,奇数哨兵个才能选举成功,一般建议 3 个
部署案例二(罕见)
一组哨兵监听两个Redis主节点
直接原有基础上加一行sentinel monitor mymasterB 192.168.1.20 6379 2
部署建议
a,sentinel 节点应部署在多台物理机(线上环境)
b,至少三个且奇数个 sentinel 节点
c,通过以上我们知道,3 个 sentinel 可同时监控一个主节点或多个主节点监听 N 个主节点较多时,如果 sentinel 出现异常,会对多个主节点有影响,同时还会造成 sentinel 节点产生过多的网络连接,一般线上建议还是, 3 个 sentinel 监听一个主节点。
sentinel 哨兵的 API
命令:redis-cli -p 26379 //进入哨兵的命令模式,使用 redis-cli 进入
26379>sentinel masters 或 sentinel master mymaster //查看 redis 主节点相关信息
26379>sentinel slaves mymaster //查看从节点状态与相关信息
26379>sentinel sentinels mymaster //查 sentinel 节点集合信息(不包括当前 26379)
26379>sentinel failover mymaster //对主节点强制故障转移,没和其它节点协商
客户端连接(redis-sentinel 例子工程)
我们在使用哨兵之后,Java操作Redis就可以直接通过对哨兵进行访问了。
客户端是和Sentinel来进行交互的,通过Sentinel来获取真正的Redis节点信息,然后来操作.实际工作时,Sentinel 内部维护了一个主题队列,用来保存Redis的节点信息,并实时更新,客户端订阅了这个主题,然后实时的去获取这个队列的Redis节点信息.
代码如下
结构图如下
远程客户端连接时,要打开 protected-mode no
./redis-cli -p 26380 shutdown //关闭
在使用工程 redis-sentinel,调用 jedis 查询的流程如下:
1,将三个 sentinel 的 IP 和地址加入 JedisSentinelPool
2,根据 IP 和地址创建 JedisSentinelPool 池对象
3,在这个对象创建完后,此时该对象已把 redis 的主节点 ( 此 时 sentinel monitor mymaster 必 须 写 成 192.168.42.111 6379 2 , 不 能 为127.0.0.1,不然查询出来的主节点的 IP 在客户端就变成了 127.0.0.1,拿不到连接了)查询出来了,当客户准备发起查询请求时,调用 pool.getResource()借用一个 jedis 对象,内容包括主节点的 IP 和端口;
4,将得到 jedis 对象后,可执行 jedis.get(“age”)指令了……。
Rerdis集群
集群和哨兵有什么区别?哨兵属于我们防止Redis服务器挂掉,硬盘坏死导致的数据无法恢复的毁灭性问题。而在大数据量的时代,一个服务器的Redis是无法抗住如此庞大的数据量的。于是引入了分布式的思想。
RedisCluster 是 redis 的分布式解决方案,在 3.0 版本后推出的方案,有效地解决了Redis 分布式的需求,当遇到单机内存、并发等瓶颈时,可使用此方案来解决这些问题
分布式数据库的概念
分布式数据库把整个数据按分区规则映射到多个节点,即把数据划分到多个节点上,每个节点负责整体数据的一个子集。
比如我们库有 900 条用户数据,有 3 个 redis 节点,将 900 条分成 3 份,分别存入到 3 个 redis 节点
区分规则
常见的分区规则哈希分区和顺序分区,redis 集群使用了哈希分区,顺序分区暂
用不到,不做具体说明;
rediscluster 采用了哈希分区的“虚拟槽分区”方式(哈希分区分节点取余、一致性哈希分区和虚拟槽分区)。以Hash规则将数据散列到各个Redis服务中。
虚拟槽位的区分
RedisCluster 采用此分区,所有的键根据哈希函数(CRC16[key]&16383)映射到 0-16383 槽内,共 16384 个槽位,每个节点维护部分槽及槽所映射的键值数据
哈希函数: Hash()=CRC16[key]&16383 按位与槽与节点的关系如下:
Redis用虚拟槽的原因
解耦数据与节点关系,节点自身维护槽映射关系,分布式存储
redisCluster 的缺陷
批量操作支持有限
键的批量操作支持有限,比如 mset, mget,如果多个键映射在不同的槽,就不支持了。
键事务支持有限
键事务支持有限,当多个 key 分布在不同节点时无法使用事务,同一节点是支持事务。
键是数据最小粒度
键是数据分区的最小粒度,不能将一个很大的键值对映射到不同的节点 。
不支持多数据库
不支持多数据库
复制结构只支持单层结构
复制结构只支持单层结构,不支持树型结构。
集群环境搭建
手动搭建(3主3从,6节点)
1:配置主从关系(参考之前的主从配置)
例:新增 redis6389.conf, 加入 slaveof 192.168.42.111 6379, 在 6379 启动完后再启 6389,完成配置
之后的按照:6389 为 6379 的从节点,6390 为 6380 的从节点,6391 为 6381 的从节点。主从配置完毕。
2:对所有节点开启集群模式
在/usr/local/bin/clusterconf 目录,对所有参与集群的节点进行配置
以6379为例:
port 6379 //节点端口
cluster-enabled yes //开启集群模式
cluster-node-timeout 15000 //节点超时时间
cluster-config-file /usr/local/bin/clustercon/data/nodes-6379.conf
//集群内部配置文件
其它节点的配置和这个一致,改端口即可
3:集群启动
分别启动redis6379、6380、6381、 6389、 6390、 6391节点
./redis-server clusterconf/redis6379.conf &
./redis-server clusterconf/redis6380.conf &
./redis-server clusterconf/redis6381.conf &
./redis-server clusterconf/redis6389.conf &
./redis-server clusterconf/redis6390.conf &
./redis-server clusterconf/redis6391.conf &
使用Ruby自动分配
使用ruby来自动分配槽与主从分配,见redis安装文档,建议用此方式完成。(本文不再详细讲解)
集群健康监测
执行: ./redis-trib.rb check 192.168.42.111:6379
如此出现了这个问题,6379的5798槽位号,6380的1180,2998,11212,11756槽位号,6381的1180被打开了。
以6380为例:
6380:>cluster setslot 1180 stable;
cluster setslot 2998 stable;
cluster setslot 11212 stable;
修复6379截图
其它也一样,分别执行修复完后:
配置集群从节点代替直接点
masterauth “12345678”
requiredpass “12345678”
当主节点下线时,从节点会变成主节点,用户和密码是很有必要的,设置成一致
集群测试
在集群是健康的条件下,当停掉6379主节点后,过会从节点6389变成主节点。
一主多从配置
指令解读第1排全是主节点,2,3排对应的第1排的从节点。replicas 2 代表每个主节点共2个从节点。
./redis-trib.rb create --replicas 2
192.168.42.111:6379 192.168.42.111:6380 192.168.42.111:6381
192.168.42.111:6479 192.168.42.111:6480 192.168.42.111:6481
192.168.42.111:6579 192.168.42.111:6580 192.168.42.111:6581
集群之间的通信
节点之间采用 Gossip 协议进行通信,Gossip 协议就是指节点彼此之间不断通信交换信息。
当主从角色变化或新增节点,彼此通过 ping/pong 进行通信知道全部节点的最新状态并达到集群同步
Gossip 协议
Gossip 协议的主要职责就是信息交换,信息交换的载体就是节点之间彼此发送的 Gossip 消息,常用的 Gossip 消息有 ping 消息、pong 消息、meet 消息、fail 消息
meet 消息:用于通知新节点加入,消息发送者通知接收者加入到当前集群,meet消息通信完后,接收节点会加入到集群中,并进行周期性 ping pong 交换(登录)
ping 消息:集群内交换最频繁的消息,集群内每个节点每秒向其它节点发 ping 消息,用于检测节点是在在线和状态信息,ping 消息发送封装自身节点和其他节点的状态数据;(心跳)
pong 消息,当接收到 ping meet 消息时,作为响应消息返回给发送方,用来确认正常通信,pong 消息也封闭了自身状态数据; (响应)
fail 消息:当节点判定集群内的另一节点下线时,会向集群内广播一个 fail 消息,后面会讲到。…… (登出)
消息解析流程
所有消息格式为:消息头、消息体,消息头包含发送节点自身状态数据(比如节点ID、槽映射、节点角色、是否下线等),接收节点根据消息头可以获取到发送节点的相关数据
选择节点并发送 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:消息数据:节点自身信息和其他节点信息。
集群扩容
1. 准备新的节点
2. 主节点加入集群,迁移槽和数据
3.新增节点操作
1,同目录下新增redis6382.conf、redis6392.conf,并启动两个新redis节点
./redis-server clusterconf/redis6382.conf &
./redis-server clusterconf/redis6392.conf &
2,新增主节点
./redis-trib.rb add-node 192.168.42.111:6382 192.168.42.111:6379
6379是原存在的主节点,6382是新的主节点
3,添加从节点
redis-trib.rb add-node --slave --master-id 062464bc7590400441fafb63f2 192.168.42.111:6392 192.168.42.111:6379
--slave,表示添加的是从节点
--master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2,主节点的node id,在这里是前面新添加的6378的node id
192.168.42.111:6392,新从节点
192.168.42.111:6379集群原存在的旧节点
4,redis-trib.rb reshard 192.168.42.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 //表示全部节点重新洗牌
集群缩减
流程说明
A,确定下线节点是否存在槽 slot,如果有,需要先把槽迁移到其他节点,保证整个集群槽节点映射的完整性;
B,当下线的节点没有槽或本身是从节点时,就可以通知集群内其它节点(或者叫忘记节点),当下线节点被忘记后正常关闭。
从节点6392删除步骤
在从节点中,没有分配哈希槽,执行
./redis-trib.rb del-node 192.168.42.111:6392 65ee465423c925326a5 (节点ID)。
从节点6392从集群中删除了。
主节点6382删除步骤
1,槽回收,数据转移
./redis-trib.rb reshard 192.168.42.111:6382
1,输入被删除节点之前分配的槽数
2,将被删除节点的数据转存到其它主节点
3,输入被删节点的ID号
4,确定删除,完成。
2,执行删除:
./redis-trib.rb del-node192.168.42.111:6382 61f70abd7dc773e6dd15a19
请求路由重定向
我们知道,在 redis 集群模式下,redis 接收的任何键相关命令首先是计算这个键 CRC值,通过 CRC 找到对应的槽位,再根据槽找到所对应的 redis 节点,如果该节点是本身,则直接处理键命令;如果不是,则回复键重定向到其它节点,这个过程叫做MOVED 重定向
故障转移
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 状态时,并且c节点自己也无法联系b节点时,会触发客观下线流程;
当下线为主节点时,此时 redis 集群为统计持有槽的主节点投票数是否达到一半,
当下线报告统计数大于一半时,被标记为客观下线状态。
故障恢复
故障主节点下线后,如果下线节点的是主节点,则需要在它的从节点中选一个替换它,保证集群的高可用;转移过程如下:
1,资格检查:检查该从节点是否有资格替换故障主节点,如果此从节点与主节点断开过通信,那么当前从节点不具体故障转移;
2,准备选举时间:当从节点符合故障转移资格后,更新触发故障选举时间,只有到达该时间后才能执行后续流程;
3,发起选举:当到达故障选举时间时,进行选举;
4,选举投票:只有持有槽的主节点才有票,会处理故障选举消息,投票过程其实是一个领导者选举(选举从节点为领导者)的过程,每个主节点只能投一张票给从节点,当从节点收集到足够的选票(大于 N/2+1)后,触发替换主节点操作,撤销原故障主节点的槽,委派给自己,并广播自己的委派消息,通知集群内所有节点。