🌿 Redis 的高可用

吞佛童子2022年10月10日
  • db
  • 高可用
大约 32 分钟

🌿 Redis 的高可用

1. 主从

1) 常见拓扑结构

  1. 一主一从
  2. 一主多从
  3. 树状结构

2) 主从同步原理

  1. slave 保存 masterip & port
  2. 主从建立 连接
  3. slave 发送 ping 请求与 master 进行首次通信,检测网络是否可用
    • 同时根据 psync 的值判断是 全量复制 | 部分复制,master 回复 runID & offsetslave
  4. 权限认证
    • 若 master 要求密码验证,则 slave 需要提供正确的密码
  5. 同步数据集
    • master 开启持久化,生成 RDB 文件,将数据发送给 slave
    • masterRDB 期间的 新指令 保存在 复制缓冲区slave 加载完 RDB 后,会将这部分数据也发送给 slave
    • slave 收到全部数据后,清空 自身全部数据,然后 加载 master 传来的数据
  6. 命令持续复制
    • master 将后续 指令通过 AOF 发送给 slave 进行同步

3) 两种方式

  1. 全量复制
    • 将 master 全部数据一次性发送给 slave,当数据量较大时,会对 主从节点 & 网络 带来很大的开销
    • slave 发送 psync -1 表示全量复制
  2. 部分复制
    • slave 发送 psync runId offset 表示部分复制
    • master 验证 runId & offset 有效后,会将 offset 之后的数据发送给 slave

4) 可能存在的问题

  1. master 发生故障后,需要手动将一个 slave 节点晋升为 master,同时修改调用方的 master 的 ip & port,还需要其他 slave 复制新的 master
  2. 主节点的 写能力 受到 单机限制
  3. 主节点的 存储能力 受到 单机限制

5) 相关命令

Commandfunction
slaveOf host port当前客户端的 redis 为 指定 redis 服务器的 slave
slaveOf no one当前客户端的 redis 不为任何主服务器的 slave
psync runid offsetslave 向 master 请求发送哪些内容,master 回复 +continue 表示部分复制,否则全量复制
psync ? -1全量复制

6) 源码


2. 哨兵

1) 作用

  1. 节点状态监测
  2. 自动故障转移
  3. 配置提供者
    • 客户端初始化时,通过连接哨兵来获得当前 Redis 服务的 master 地址
  4. 通知
    • 哨兵可将故障转移的 结果 发送给 客户端

2) 两种节点

  1. 数据节点
    • 存储数据,对外提供读写服务
  2. 哨兵节点
    • 不存储数据,只是对 数据节点 进行状态监控

3) 哨兵实现原理

  1. 定时监控
    • 节点心跳检测
      • 每隔 1 秒,每个 哨兵 向 master、slave、其余哨兵 节点发送 ping 命令做一次 心跳检测,确认这些节点是否可达
    • 哨兵信息发布
      • 每隔 2 秒,每个 哨兵 向 Redis 数据节点的 __sentinel__:hello 频道发送该哨兵节点对于 master 的判断 & 当前哨兵节点的信息
    • 主从信息获取
      • 每隔 10 秒,每个 哨兵 向 master、slave 发送 info 命令获取最新的 拓扑结构
  2. 主观下线 & 客观下线
    • 主观下线
      • 哨兵节点 认为 某个节点 存在问题
      • 每隔 1 秒,每个 哨兵 向 master、slave、其余哨兵 节点发送 ping 命令做一次 心跳检测,确认这些节点是否可达
      • 若在规定时间 down-after-milliseconds 没有进行有效回复,则认为其 主观下线
    • 客观下线
      • 超过一定数量的 哨兵节点 均认为 master 有问题
      • 当 master 有问题时,该 哨兵节点 会通过 sentinel is-master-down-by-addr 命令向其他哨兵节点询问 master 的判断
      • 若 > quorum,则认为该 master 有问题,做出 客观下线 的决定
  3. 选举一个 哨兵 进行 故障转移
    • Raft 算法选举出 领导者哨兵节点
      • 每个在线 哨兵 节点均有资格成为领导者,当它确认 master 主观下线时,该 哨兵节点 会通过 sentinel is-master-down-by-addr 命令,要求将自己设置为 领导者
      • 收到命令的 哨兵节点,若没有同意过 其他哨兵 节点的 sentinel is-master-down-by-addr 命令,则会同意该请求,否则拒绝
      • 某个 哨兵节点 发现自己收到的 同意票数 >= max{quorum, num(sentinel) / 2 + 1} 时,会晋升为 领导者
      • 若本轮没有选举出领导者,则会进入 下一次选举
  4. 选取新的 master,进行 故障转移
    • 选出 新 master 节点
      • 过滤不合法节点
        • 剔除 已经主观下线 | 断线 | 5 秒内无回复过 哨兵节点 ping 响应 | 与 master 失联超过 10 * down-after-milliseconds 的节点
      • 选择 slave-priority 值最小 的 slave,如果只存在一个,返回
      • 选择 复制偏移量最大 的 slave,若只存在一个,返回
      • 选择 runid 最小 的 slave
    • 设置 master
      • 哨兵节点对选择的 新 master 节点 执行 slaveof no one 命令,让其成为 master
    • slave 节点同步
      • 哨兵节点向剩余 slave 节点发送命令,让其成为 新 master 节点的 slave
    • 原 master 节点变为 slave

4) 源码


3. 集群

1) 作用

  1. 数据分区
    • 将 数据分片 存储到不同 slave 节点
      • 存储容量增加
      • 每个 master 均对外提供读写服务,响应能力增加
  2. 高可用
    • 支持 主从复制 & master 的 自动故障转移

2) 数据分区

  1. 节点取余
    • 选取 key | 其他数据求 hash 值,然后对 分区数 取余,映射到 对应节点
      • 当节点数量发生改变时,映射关系也会发生改变,需要进行数据的 重新迁移
  2. 一致性哈希分区
    • 将 节点 映射到这个 Hash 值空间,可以看出一个虚拟的圆环结构,节点不一定完全平分该 Hash 值空间
    • 当 key 存入时,求取其 hash 值,顺时针往后查找距离其最近的 节点
      • 当节点数量变化时,只影响到 哈希环 中相邻节点,影响范围变小
      • 节点存放数据分布不均匀,某个节点故障时,压力会转移到顺序方向的下一个节点
  3. 虚拟槽分区
    • 槽完全平分 Hash 值空间,每个节点负责部分槽对应的 Hash 值范围
    • 槽 个数 = 16384
      • 当节点数量变化时,可将该节点所属的槽分给 前面几个 & 后面几个 节点,影响范围只在相邻几个节点,且将一个节点的压力分给多个相邻节点,每个节点平摊的压力降低

3) 原理

  1. 集群创建
    • 设置节点
      • 一般设置节点数 >= 6 才可保证高可用的集群,至少需要配置在 3 台物理机
      • 每个节点需要开启配置 cluster-enabled yes,让其工作在 集群模式 下
    • 节点握手
      • 集群模式下的节点通过 gossip 协议彼此通信
        • 每个节点随机选择一些节点进行通信
          • 收敛性较弱,但是消耗宽带较少,
            • 类似于 范围感染 的形式,首先有一个感染源,然后范围内的随机人数感染,被感染者再随机感染范围内的其他人,最终密闭空间达到全体感染情况
      • 命令 cluster meet {ip} {port}
    • 分配槽
      • 将节点映射到 16384 个槽中,每个节点负责部分槽
      • 命令 cluster addslots {startIndex, endIndex}
  2. 故障转移
    • 故障发现
      • 集群中每个节点 均承担 故障发现 的任务
      • 节点通过 ping/pong 实现节点通信
      • 每个节点定期向其他节点发送 ping 消息,接收 pong 消息
      • 若在规定时间 cluster-node-timeout 内通信一直失败,则认为 目标节点 发生故障,将其标记为 主观下线,并将该消息 传播给 其他节点
  3. 故障恢复
    • 剔除不合法的 slave
      • 需要保证 slave 与 master 最后断线时间在有效范围之内
    • 准备选举时间
      • 存在满足条件的 slave 后,触发选举时间,达到时间后才进行选举
    • 发起选举
      • 达到故障选举时间 failover_auth_time 后,发起选举
    • 投票选举
      • 集群中的节点每个节点只能投给 一个自己想要其成为 master 的 slave 节点
      • 若某个 slave 票数 > n/2 + 1,则为 新 master,这个 n 包含了发生故障的 master 节点
    • 替换 master

4) 源码


4. 无底洞问题

1) 描述

  • 在某种情况下,增加 节点数 不仅不能提高性能,反而会降低系统性能

2) 原因

  • 不同 key 根据 Hash 存放在不同节点,对于批量操作时,需要从不同节点中获取数据,然后进行整合
  • 每个客户端要获取批量数据,需要访问 多个节点

3) 如何优化

  • 优化
    • 命令本身的优化
    • 降低接入成本,客户端使用长连接
上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou