说明
文章内容通过学习小林Coding内的优质文章后整理而来,整理成思维导图的方式是为了帮助自己理解、记忆和复习。如若侵权请联系删除,再次对小林Coding内的优质文章表示感谢。参考文章如下:
思维导图会不断修改完善,下方的文字内容不一定会跟着修改,请大家以思维导图的内容为准。
Redis高可用
Redis部署方式
单服务器部署
- 宕机,需要时间恢复,期间无法提供服务
- 硬盘损坏,数据丢失
多服务器部署
-
一台服务器出问题,其他服务器还能提供服务
-
有什么问题
- 服务器之间的数据如何保持一致
- 数据的读写操作在服务器间如何分配
-
问题如何解决
- 交给主从复制
主从复制
是什么
- 主从服务器使用读写分离方式,主可读写,从只读
- 主发生写操作时自动将写操作同步给从
有什么用
- 保证主从服务器的数据一致性
怎么确定主从关系
- B服务器执行下面命令,就变成A服务器的从节点
- replicaof <A 的 IP 地址> < A 的 Redis 端口号>
第一次同步
-
为什么
- 刚建立主从关系时,主从服务器的数据不一致,需要进行第一次同步
-
什么步骤
-
- 建立链接、协商同步
-
从执行 replicaof 命令后,就会给主发送 psync 命令
-
psync表示要进行数据同步
-
psync包含两参数
-
runID
- 每个Redis服务器在启动时会生成一个随机runID来标识自己
- 第一次同步,从不知道主的runID,因此设置为 ?
-
offset
- 表示复制的进度
- 第一次同步设置为-1
-
-
-
主收到psync命令后,将 FULLRESYNC 作为响应命令返回给对方
-
FULLRESYNC返回两参数
- 主的runID
- 主的复制进度offset
-
-
从收到响应之后,记录相应的参数
-
- 主同步全量数据给从
-
步骤
- 主执行 bgsave 命令fork子进程来生成 RDB 文件并发送给从
- 从收到 RDB 文件后,先清空当前数据,后载入 RDB 文件
-
问题
-
在生产RDB文件期间,主收到的写操作不会写到RDB文件中,主从数据会不一致
-
解决
-
主在这三个时间间隙中将收到的写操作命令,写入到replication buffer里
- 主生成RDB文件期间
- 主发送RDB给从期间
- 从加载RDB文件期间
-
-
-
- 主发送新写操作命令给从
- 从载入RDB文件后,回复一个确认消息给主
- 主将replication buffer里的写操作命令发送给从来执行,这时主从的数据就一致了
-
命令传播
-
是什么
- 主从完成第一次同步后,双方会维护一个 TCP 长连接,后续主通过该连接继续将写操作命令传播给从来执行,使主从数据一致
增量复制
-
为什么需要增量复制
-
主从服务器在命令传播时,网络连接不一定永远稳定,若网络不稳定,部分写操作命令同步失败,主从的数据就会不一致
-
断开的网络恢复正常后,怎么重新保证主从的数据一致
- Redis2.8前:主从重新进行数据全量复制,性能不好
- Redis2.8后:使用增量复制,把网络断开期间的写操作命令同步给从
-
-
过程
-
- 从恢复网络后,发送 psync 命令给主,此时 psync 命令里的offset不是 -1
-
- 主收到 psync 命令后,用 CONTINUE 响应命令告诉从将采用增量复制的方式同步数据
-
- 主将主从服务器断线期间,所执行的写命令发送给从执行
-
-
问题
-
主怎么知道那些是增量数据
-
存储相关信息
-
repl_backlog_buffer
- 一个环形缓冲区,用于主从断连后,从中找到差异的数据
-
replication offset
-
标记环形缓冲区的同步进度
- 主使用 master_repl_offset 记录自己写到的位置
- 从使用 slave_repl_offset 记录自己读到的位置
-
-
-
主进行命令传播时,不仅会将写命令发送给从,还会将写命令写入到 repl_backlog_buffer ,因此缓冲区里会保存着最近传播的写命令
-
当从重新连上主服务器时,从通过 psync 命令将slave_repl_offset 发送给主,主根据 master_repl_offset 和 slave_repl_offset 之间的差距来决定对从服务器执行哪种同步操作
- 从要读取的数据还在 repl_backlog_buffer 里,使用增量同步
- 从要读取的数据不在 repl_backlog_buffer 里,使用全量同步
-
repl_backlog_buffer 默认大小是 1M,因其是环形缓冲区,当缓冲区写满后,主继续写入的话,就会覆盖之前的数据。若从想读的数据被覆盖,就只能进行全量同步,性能损耗较大
-
优化:调整repl_backlog_buffer大小,降低覆盖概率
-
设置多大?
- sw(保险起见,可以设置为2sw)
- s:从断线后重新连接主所需的平均秒数
- w:主平均每秒产生的写命令数据量大小
-
怎么设置
- 修改redis.conf
- repl-backlog-size 1mb
-
-
-
经理角色分摊主服务器的压力
-
为什么要分摊
-
主从在第一次数据同步的过程中,主会生成 RDB 文件和传输 RDB 文件,这两个操作比较耗时
- 主生成 RDB 文件时,会忙于使用 fork() 创建子进程,如果主的内存数据非常大,执行 fork() 函数时会阻塞主线程,使得 Redis 无法正常处理请求
- 传输 RDB 文件会占用主的网络带宽,影响主响应命令请求
-
-
怎么分摊
- 从有自己的从节点,将拥有从节点的从当作经理角色,它不仅接收主的同步数据,同时作为主将数据同步给自己的从节点
-
怎么操作
- 服务器执行下面命令,将其作为经理服务器的从节点。执行完成之后,经理就会将数据同步给自己的从节点
- replicaof <想作为经理的IP> <Redis端口>
哨兵机制
为什么需要哨兵机制
- 主从模式是读写分离的,如果主节点挂了,则没法服务客户端的写请求,也没有主节点给从节点同步数据。
- 如果需要恢复服务,需要人工介入,恢复主节点或将一个从节点改为主节点。需要一套更加智能的方式
- Redis2.8后提供哨兵模式,可检测主节点是否存活,若主节点挂了,则重新推举一个从节点成为主节点,并且把新主节点的相关信息通知给从节点和客户端(主从故障迁移)
哨兵介绍
-
是什么
- 哨兵其实是一个运行在特殊模式下的 Redis 进程
-
做什么
- 监控主从节点的状态
- 选主
- 通知
如何判断主节点是否故障
-
主节点主观下线
- 哨兵节点每隔 1 秒给所有主从节点发送 PING 命令,当主从节点收到 PING 命令后,会发送一个响应命令给哨兵,如果主节点或者从节点没有在规定的时间内响应,哨兵就会将它们标记为【主观下线】
- 规定时间设置: 修改哨兵配置文件的down-after-milliseconds,单位是毫秒
-
主节点客观下线
-
可能主节点没有故障,只是因为主节点的系统压力比较大或者网络发送了拥塞,导致没有在规定时间内响应哨兵的 PING 命令(会造成误判)
-
为了减少误判,针对主节点还设置了【客观下线】状态,即经过集群投票(让多个哨兵一起判断,避免单个哨兵自身网络不好误判主节点下线)认定的下线为【客观下线】(单个节点判断的为【主观下线】)
-
投票步骤
- 当一个哨兵判断主节点为【主观下线】后,向其他哨兵发起is-master-down-by-addr 命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应
- 当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被【该哨兵】标记为【客观下线】(如集群中有三个哨兵,quorum为2,则三个哨兵中至少需要两个赞成,发起投票者也算赞成)
- quorum 一般设置为(哨兵个数/2)+ 1
-
哪个哨兵进行主从故障转移
-
在判断主节点客观下线后,由哪个节点(Leader)来进行主从故障转移?
-
候选者
- 那个将主节点标记为【客观下线】的节点,其实就是第一个判断主节点为【主观下线】的节点
- 如果某个时间点有两个哨兵节点判断到主节点为客观下线,则有两个候选者
-
Leader选举
-
候选者会让其他哨兵对它进行投票,每个哨兵只有一次投票机会,候选者可以投给自己
-
多个候选者,哨兵投给谁?
- 先收到谁的命令,就投给谁(先到先得)
-
需要满足
-
- 拿到半数以上(大于半数)的赞成票
-
- 拿到的票数需要大于等于哨兵配置文件中的 quorum 值
- 注意:候选者会默认给自己投一票,没有则需要重新选举
-
-
为什么哨兵节点至少要有 3 个
- 哨兵集群中只有 2 个哨兵节点,此时如果一个哨兵想要成功成为 Leader,必须获得 2 票,只要挂一个,就没办法进行主从节点切换
- 哨兵集群中有 3 个哨兵节点,要挂一个,还是有机会投票成功。挂两个就需要人工介入
-
为什么 quorum 设置为(哨兵个数/2)+ 1
- 如集群有三个节点,其中两个节点宕机,quorum设置为1
- 这时可以完成客观下线,却不能完成主从切换,因此quorum设置为1没有意义
-
主从故障转移的过程
-
挑选从节点
-
做什么
- 在已下线主节点属下的所有从节点里面,挑选出一个状态良好、数据完整的从节点,给其发送SLAVEOF no one命令将其转换为主节点
-
怎么做
-
- 过滤掉下线和网络状态不好的节点
- Redis 有个叫 down-after-milliseconds * 10 配置项,其 down-after-milliseconds 是主从节点断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从节点的网络状况不好,不适合作为新主节点
-
- 优先级最高的从节点胜出
- Redis 有个叫 slave-priority 配置项,可以根据服务器配置给从节点设置优先级
-
- 复制进度最靠前的从节点胜出
- 如果某个从节点的 slave_repl_offset 最接近 master_repl_offset,说明它的复制进度是最靠前的
-
- ID 号小的从节点胜出
- 每个从节点都有一个编号,这个编号就是 ID 号,是用来唯一标识从节点的
-
-
-
被挑选从节点转化为主节点
- 哨兵 leader 向被选中的从节点发送 SLAVEOF no one 命令,让这个从节点解除从节点的身份,将其变为新主节点
- 在发送 SLAVEOF no one 命令之后,leader 会以每秒一次的频率向被升级的从节点发送 INFO 命令(没进行故障转移之前,INFO 命令的频率是每十秒一次),并观察命令回复中的角色信息,当被升级节点的角色信息从原来的 slave 变为 master 时, leader 就知道从节点顺利升级为主节点了
-
将从节点指向新主节点
- 哨兵 leader 向所有从节点发送 SLAVEOF 命令让它们成为新主节点的从节点
-
通知客户端主节点更换信息
- 通过 Redis 的发布者/订阅者机制来实现。每个哨兵节点提供发布者/订阅者机制,客户端可以从哨兵订阅消息
- 主从切换完成后,哨兵就会向 +switch-master 频道发布新主节点的 IP 地址和端口的消息,客户端收到信息,然后用新主节点的 IP 地址和端口进行通信
- 通过发布者/订阅者机制机制,客户端不仅可以在主从切换后得到新主节点的连接信息,还可以监控到主从节点切换过程中发生的各个重要事件。有助于客户端了解主从切换进度
- 事件通知有哪些?
-
旧主节点上线,将其变为从节点
- 主从切换后,哨兵集群继续监视旧主节点,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF 命令,让它成为新主节点的从节点
哨兵集群是如何组成
-
配置哨兵
- sentinel monitor
-
哨兵之间相互感知
- 配置哨兵时,不需要填其他哨兵信息,哨兵节点之间可以通过 Redis 的发布者/订阅者机制来相互发现
- 在主从集群中,主节点上有一个名为sentinel:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的
-
哨兵集群如何知道从节点信息
- 主节点知道所有从节点信息,所以哨兵会每 10 秒一次的频率向主节点发送 INFO 命令来获取所有从节点的信息