上一章介绍了Redis的基本用法和常见概念,本章主要介绍Redis高可用。
1. Redis的主从模式
Redis多实例部署时,这些实例节点会被分成两类,主节点(master节点)和从节点(slave节点)。一般主节点进行读、写操作,而从节点只能进行读操作。主节点写数据发生变化时,会将变化的数据同步给从节点,这样从节点的数据就可以和主节点的数据保持一致了。一个主节点可以有多个从节点,但是一个从节点会只会有一个主节点,也就是所谓的一主多从结构。
1.1 Redis的主从复制
redis的主从复制过程分为两个阶段:同步和命令传播。
同步操作,具体的步骤有:
- 当从库和主库建立MS关系后,会向主数据库发送SYNC命令
- 主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程),并将期间接收到的写命令缓存起来;
- 当快照完成后,主Redis会将快照文件和所有缓存的写命令发送给从Redis,从Redis接收到后,会载入快照文件并且执行收到的缓存的命令;
- 主服务器再将缓冲区记录的写命令发送给从服务器,从服务器执行完这些写命令后,此时的数据库状态便和主服务器一致了。
同步操作完成后,Redis后期的主从一致主要通过命令传播方式。后期master有写的操作,会把写命令传播到slave,slave执行后保持与主一致。
主从复制有一个很大的缺点:所有的slave节点数据的复制和同步都由master节点来处理,会照成master节点压力太大,可以使用主从从结构来解决。为了解决这个问题,2.8以后开始就使用 psync 命令来代替 sync 命令去执行同步操作。psync与sync的不同点在于:初次复制,过程与sync相同;断线后复制,如果满足一定条件,主服务器只需要将断线期间执行的写命令发送给从服务器即可。
满足的条件有:
- 主从复制偏移量:主服务器每次向从服务器传播 n 个字节数据时,都会将自己的复制偏移量加 n。从服务器接受主服务器传来的数据时,也会将自己的复制偏移量加 n。
- 复制积压缓冲区:master发送给slave命令后,还会将命令push到一个缓冲区队列中,初始大小为1M。如果从复制偏移量在缓冲区中,则进行部分复制,否则全部复制。
- run id:在进行初次复制的时候,主服务器会将自己运行的ID发送给从服务器,从服务器断线重连后,会尝试用run id连接master,如果能连上,表示可以部分复制,否则完整同步。
1.2 Redis的主从复制常见的性能问题
- Master写内存快照RDB,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
- Master AOF持久化,调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
- Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
2. 哨兵模式
在主从模式下,redis同时提供了哨兵命令redis-sentinel。
哨兵是一个独立的进程,其原理是哨兵进程向所有的redis机器发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵可以有多个,一般为了便于决策选举,使用奇数个哨兵。哨兵可以和redis机器部署在一起,也可以部署在其他的机器上。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现master宕机哨兵之间会进行决策选举新的master。哨兵模式工作通过3个监控任务。
info命令
每隔10秒,每个哨兵节点都会向主、从redis数据节点发送info命令,获取新的拓扑结构信息。redis拓扑结构信息包括了:本节点角色(主或从);主从节点的地址、端口信息。
图片来自:Redis高可用方案实现 - 知乎
向__sentinel__:hello频道同步信息
每隔2秒,每个哨兵节点会广播自身得到的主节点信息和当前哨兵节点信息,广播频道是__sentinel__:hello。由于其他哨兵节点也订阅了这个频道,因此实际上这个操作可以交换哨兵节点之间关于主节点以及哨兵节点的信息。交换信息可以得到:发现新的哨兵节点;交换主节点的状态信息,作为后续客观判断主节点下线的依据。
向数据节点做心跳探测
每隔1秒,每个哨兵节点向主、从数据节点以及其他sentinel节点发送ping命令做心跳探测,这个心跳探测是后续主观判断数据节点下线的依据。
2.1 主观下线和客观下线
主观下线
如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。
客观下线
如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态;当一个哨兵节点认为主节点主观下线时,该哨兵节点需要通过”sentinel is-master-down-by addr”命令向其他哨兵节点咨询该主节点是否下线了,如果有超过半数的哨兵节点都回答了下线,此时认为主节点“客观下线”。
若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
2.2 选举新的master节点
选举哨兵领导者
当主节点客观下线时,需要选举出一个哨兵节点做为哨兵领导者,以完成后续选出新的主节点的工作。大体的思路是:
- 每个哨兵节点通过向其他哨兵节点发送”sentinel is-master-down-by addr”命令来申请成为哨兵领导者。
- 而每个哨兵节点在收到一个”sentinel is-master-down-by addr”命令时,只允许给第一个节点投票,其他节点的该命令都会被拒绝。
- 如果一个哨兵节点收到了半数以上的同意票,则成为哨兵领导者。
- 如果前面三步在一定时间内都没有选出一个哨兵领导者,将重新开始下一次选举。
通过哨兵领导者选举出新的备选master节点:
- 过滤掉“不健康”的数据节点:比如主观下线、断线的从节点、五秒内没有回复过哨兵节点ping命令的节点、与主节点失联的从节点。
- 选择slave-priority(从节点优先级)最高的从节点,如果存在则返回不存在则继续后面的流程。
- 选择复制偏移量最大的从节点,这意味着这个从节点上面的数据最完整,如果存在则返回不存在则继续后面的流程。
- 剩余从节点的状态都是一样的,选择runid最小的从节点;
提升新的master节点
选择了新的主节点之后,还需要最后的流程让该节点成为新的主节点:
- 哨兵领导者向上一步选出的从节点发出“slaveof no one”命令,让该节点成为主节点。
- 哨兵领导者向剩余的从节点发送命令,让它们成为新主节点的从节点。
- 哨兵节点集合会将原来的主节点更新为从节点,当其恢复之后命令它去复制新的主节点的数据。
3. redis cluster集群模式
I. Redis Cluster特点如下:
- 所有的节点相互连接;
- 集群消息通信通过集群总线通信,集群总线端口大小为客户端服务端口+10000,这个10000是固定值;
- 节点与节点之间通过二进制协议进行通信;
- 客户端和集群节点之间通信通过文本协议进行;
- 集群节点不会代理查询;
II. redis cluster分区的实现:Redis Cluster中有一个16384长度的槽的概念,每个Master节点都会负责一部分的槽,当有某个key被映射到某个Master负责的槽,那么这个Master负责为这个key提供服务。master维护了16384/8字节的位列结构,通过位列结构判断slot是否被管理。Redis Cluster并不会代理查询。
III. redis重新分片:重新分片意为槽到集群节点的映射关系要改变,键到槽的映射关系不变,因此当重新分片的时候,如果槽中有键,那么键也是要被移动到新的节点。槽迁移的过程中有一个不稳定状态,这个不稳定状态会有一些规则。
预备迁移槽的时候槽的状态首先会变为MIGRATING状态,当客户端请求到达时,会有:
1)key存在就处理返回;
2)key不存在,返回ASK,并不会刷新客户端中node的映射关系;
3)key包含多个命令,如果都存在返回处理结果,如果部分存在,返回客户端TRYAGAIN,直到所有key迁徙完成。
3.1 常见问题的搜集
- 为什么使用虚拟槽?什么是一致性hash
一致性哈希的原理: 把所有的哈希值空间组织成一个虚拟的圆环(哈希环),整个空间按顺时针方向组织。根据机器的名称或者IP计算哈希值,然后分布到哈希环中。一致性哈希解决了动态增减节点时,所有数据都需要重新分布的问题,它只会影响到下一个相邻的节点,对其他节点没有影响。 但有一个缺点,节点数据不能得到均匀分布。
- 客户端重定向
客户端请求的命令不在当前的master节点上,会返回一个moved指令,包含真正的slot对应的master服务节点。Jedis 等客户端会在本地维护一份 slot——node 的映射关系,大部分时候不需要重定向。
- 数据迁移
因为redis cluster维护的slot是不变的,新的节点加入,会将原来节点slot拆出一部分给新的节点。重分片操作具体见上。
参考链接:https://juejin.im/post/5b1480646fb9a01e6b2c0b82
https://zhuanlan.zhihu.com/p/177000194