🌿 Redis 的高可用
2022年10月10日
- db
🌿 Redis 的高可用
1. 主从
1) 常见拓扑结构
- 一主一从
- 一主多从
- 树状结构
2) 主从同步原理
slave
保存master
的ip & port
- 主从建立 连接
slave
发送ping
请求与master
进行首次通信,检测网络是否可用- 同时根据
psync
的值判断是 全量复制 | 部分复制,master 回复runID & offset
给slave
- 同时根据
- 权限认证
- 若 master 要求密码验证,则 slave 需要提供正确的密码
- 同步数据集
master
开启持久化,生成RDB
文件,将数据发送给slave
master
将RDB
期间的新指令
保存在复制缓冲区
,slave
加载完RDB
后,会将这部分数据也发送给slave
slave
收到全部数据后,清空 自身全部数据,然后 加载master
传来的数据
- 命令持续复制
master
将后续 写 指令通过AOF
发送给slave
进行同步
3) 两种方式
- 全量复制
- 将 master 全部数据一次性发送给 slave,当数据量较大时,会对 主从节点 & 网络 带来很大的开销
- slave 发送
psync -1
表示全量复制
- 部分复制
- slave 发送
psync runId offset
表示部分复制 - master 验证 runId & offset 有效后,会将 offset 之后的数据发送给 slave
- slave 发送
4) 可能存在的问题
- master 发生故障后,需要手动将一个 slave 节点晋升为 master,同时修改调用方的 master 的 ip & port,还需要其他 slave 复制新的 master
- 主节点的 写能力 受到 单机限制
- 主节点的 存储能力 受到 单机限制
5) 相关命令
Command | function |
---|---|
slaveOf host port | 当前客户端的 redis 为 指定 redis 服务器的 slave |
slaveOf no one | 当前客户端的 redis 不为任何主服务器的 slave |
psync runid offset | slave 向 master 请求发送哪些内容,master 回复 +continue 表示部分复制,否则全量复制 |
psync ? -1 | 全量复制 |
6) 源码
2. 哨兵
1) 作用
- 节点状态监测
- 自动故障转移
- 配置提供者
- 客户端初始化时,通过连接哨兵来获得当前 Redis 服务的 master 地址
- 通知
- 哨兵可将故障转移的 结果 发送给 客户端
2) 两种节点
- 数据节点
- 存储数据,对外提供读写服务
- 哨兵节点
- 不存储数据,只是对 数据节点 进行状态监控
3) 哨兵实现原理
- 定时监控
- 节点心跳检测
- 每隔 1 秒,每个 哨兵 向 master、slave、其余哨兵 节点发送 ping 命令做一次 心跳检测,确认这些节点是否可达
- 哨兵信息发布
- 每隔 2 秒,每个 哨兵 向 Redis 数据节点的
__sentinel__:hello
频道发送该哨兵节点对于 master 的判断 & 当前哨兵节点的信息
- 每隔 2 秒,每个 哨兵 向 Redis 数据节点的
- 主从信息获取
- 每隔 10 秒,每个 哨兵 向 master、slave 发送 info 命令获取最新的 拓扑结构
- 节点心跳检测
- 主观下线 & 客观下线
- 主观下线
- 哨兵节点 认为 某个节点 存在问题
- 每隔 1 秒,每个 哨兵 向 master、slave、其余哨兵 节点发送 ping 命令做一次 心跳检测,确认这些节点是否可达
- 若在规定时间
down-after-milliseconds
没有进行有效回复,则认为其 主观下线
- 客观下线
- 超过一定数量的 哨兵节点 均认为 master 有问题
- 当 master 有问题时,该 哨兵节点 会通过
sentinel is-master-down-by-addr
命令向其他哨兵节点询问 master 的判断 - 若 > quorum,则认为该 master 有问题,做出 客观下线 的决定
- 主观下线
- 选举一个 哨兵 进行 故障转移
Raft
算法选举出 领导者哨兵节点- 每个在线 哨兵 节点均有资格成为领导者,当它确认 master 主观下线时,该 哨兵节点 会通过
sentinel is-master-down-by-addr
命令,要求将自己设置为 领导者 - 收到命令的 哨兵节点,若没有同意过 其他哨兵 节点的
sentinel is-master-down-by-addr
命令,则会同意该请求,否则拒绝 - 某个 哨兵节点 发现自己收到的
同意票数 >= max{quorum, num(sentinel) / 2 + 1}
时,会晋升为 领导者 - 若本轮没有选举出领导者,则会进入 下一次选举
- 每个在线 哨兵 节点均有资格成为领导者,当它确认 master 主观下线时,该 哨兵节点 会通过
- 选取新的 master,进行 故障转移
- 选出 新 master 节点
- 过滤不合法节点
- 剔除 已经主观下线 | 断线 | 5 秒内无回复过 哨兵节点 ping 响应 | 与 master 失联超过
10 * down-after-milliseconds
的节点
- 剔除 已经主观下线 | 断线 | 5 秒内无回复过 哨兵节点 ping 响应 | 与 master 失联超过
- 选择
slave-priority
值最小 的 slave,如果只存在一个,返回 - 选择 复制偏移量最大 的 slave,若只存在一个,返回
- 选择 runid 最小 的 slave
- 过滤不合法节点
- 设置 master
- 哨兵节点对选择的 新 master 节点 执行
slaveof no one
命令,让其成为 master
- 哨兵节点对选择的 新 master 节点 执行
- slave 节点同步
- 哨兵节点向剩余 slave 节点发送命令,让其成为 新 master 节点的 slave
- 原 master 节点变为 slave
- 选出 新 master 节点
4) 源码
3. 集群
1) 作用
- 数据分区
- 将 数据分片 存储到不同 slave 节点
- 存储容量增加
- 每个 master 均对外提供读写服务,响应能力增加
- 将 数据分片 存储到不同 slave 节点
- 高可用
- 支持 主从复制 & master 的 自动故障转移
2) 数据分区
- 节点取余
- 选取 key | 其他数据求 hash 值,然后对 分区数 取余,映射到 对应节点
- 当节点数量发生改变时,映射关系也会发生改变,需要进行数据的 重新迁移
- 选取 key | 其他数据求 hash 值,然后对 分区数 取余,映射到 对应节点
- 一致性哈希分区
- 将 节点 映射到这个 Hash 值空间,可以看出一个虚拟的圆环结构,节点不一定完全平分该 Hash 值空间
- 当 key 存入时,求取其 hash 值,顺时针往后查找距离其最近的 节点
- 当节点数量变化时,只影响到 哈希环 中相邻节点,影响范围变小
- 节点存放数据分布不均匀,某个节点故障时,压力会转移到顺序方向的下一个节点
- 虚拟槽分区
- 槽完全平分 Hash 值空间,每个节点负责部分槽对应的 Hash 值范围
- 槽 个数 = 16384
- 当节点数量变化时,可将该节点所属的槽分给 前面几个 & 后面几个 节点,影响范围只在相邻几个节点,且将一个节点的压力分给多个相邻节点,每个节点平摊的压力降低
3) 原理
- 集群创建
- 设置节点
- 一般设置节点数 >= 6 才可保证高可用的集群,至少需要配置在 3 台物理机
- 每个节点需要开启配置
cluster-enabled yes
,让其工作在 集群模式 下
- 节点握手
- 集群模式下的节点通过
gossip
协议彼此通信- 每个节点随机选择一些节点进行通信
- 收敛性较弱,但是消耗宽带较少,
- 类似于 范围感染 的形式,首先有一个感染源,然后范围内的随机人数感染,被感染者再随机感染范围内的其他人,最终密闭空间达到全体感染情况
- 收敛性较弱,但是消耗宽带较少,
- 每个节点随机选择一些节点进行通信
- 命令
cluster meet {ip} {port}
- 集群模式下的节点通过
- 分配槽
- 将节点映射到 16384 个槽中,每个节点负责部分槽
- 命令
cluster addslots {startIndex, endIndex}
- 设置节点
- 故障转移
- 故障发现
- 集群中每个节点 均承担 故障发现 的任务
- 节点通过 ping/pong 实现节点通信
- 每个节点定期向其他节点发送 ping 消息,接收 pong 消息
- 若在规定时间
cluster-node-timeout
内通信一直失败,则认为 目标节点 发生故障,将其标记为 主观下线,并将该消息 传播给 其他节点
- 故障发现
- 故障恢复
- 剔除不合法的 slave
- 需要保证 slave 与 master 最后断线时间在有效范围之内
- 准备选举时间
- 存在满足条件的 slave 后,触发选举时间,达到时间后才进行选举
- 发起选举
- 达到故障选举时间
failover_auth_time
后,发起选举
- 达到故障选举时间
- 投票选举
- 集群中的节点每个节点只能投给 一个自己想要其成为 master 的 slave 节点
- 若某个 slave 票数 > n/2 + 1,则为 新 master,这个 n 包含了发生故障的 master 节点
- 替换 master
- 剔除不合法的 slave
4) 源码
4. 无底洞问题
1) 描述
- 在某种情况下,增加 节点数 不仅不能提高性能,反而会降低系统性能
2) 原因
- 不同 key 根据 Hash 存放在不同节点,对于批量操作时,需要从不同节点中获取数据,然后进行整合
- 每个客户端要获取批量数据,需要访问 多个节点
3) 如何优化
- 优化
- 命令本身的优化
- 降低接入成本,客户端使用长连接