likes
comments
collection
share

【Redis】高可用:主从、哨兵、切片集群

作者站长头像
站长
· 阅读数 15

高可用

主从复制

Why?

单点故障无法提供服务,硬盘故障数据丢失。

How?

数据备份,并且保证一致性:主从复制

  • 读写分离:写入主,读取从

【Redis】高可用:主从、哨兵、切片集群

建立过程:

  1. 建立链接、协商同步;

    1. 发送:psync:主服务器runID、offset
    2. 回复:FULLRESYNC:主服务器的 runID、主服务器目前的复制进度 offset
  2. 主服务器同步数据给从服务器;

    1. 主 bgsave 生成 RDB 文件,发送给从服务器。
    2. 从收到 RDB 文件后,会先清空当前的数据,然后载入 RDB 文件
  3. 主服务器发送新写操作命令给从服务器。

    1. 主将 replication buffer 缓冲区写操作命令发送给从
    2. 从执行主的命令,的数据就一致了

【Redis】高可用:主从、哨兵、切片集群

命令传播

Why?

后期主数据的变更需要及时同步到从

How?

双方之间就会维护一个长 TCP 连接。

后续主通过这个连接发送命令给从。

【Redis】高可用:主从、哨兵、切片集群

分摊主服务器的压力

Why?

每次从加入都要bgsave,fork创建子进程、传递RDB文件消耗资源

How?

主服务器生成 RDB 和传输 RDB 的压力可以分摊到充当经理角色的从服务器:

  • 在「从服务器」上执行下面这条命令,使其作为目标服务器的从服务器:

    • replicaof <目标服务器的IP> 6379
    • 目标服务器是「从服务器」,该目标服务器就会成为「经理」的角色

【Redis】高可用:主从、哨兵、切片集群

增量复制

Why?

主从TCP连接网络问题断开后,数据不一致。回复连接如何恢复一致性?

How?

  • Redis 2.8 之前:重新进行一次全量复制,性能消耗大
  • Redis 2.8 后:增量复制,只把网络断开期间主接收到的写操作命令,同步给从。

步骤:

  • 从发送 psync 命令给主,offset 参数不是 -1;

  • 主返回 CONTINUE 告诉从增量复制同步数据;

  • 主服务将主从断线期间,所执行的写命令发送给从,从执行这些命令。

  • repl_backlog_buffe:环形缓冲区,1M

  • replication offset:标记缓冲区的同步进度

    • master_repl_offset:主写到的位置
    • slave_repl_offset:从读到的位置。

【Redis】高可用:主从、哨兵、切片集群

【Redis】高可用:主从、哨兵、切片集群

主的写入速度远超于从读取速度,缓冲区的数据会被覆盖,只能再采用全量同步。

  • 为了避免主频繁全量同步,调大 repl_backlog_buffer 缓冲区大小

    • repl-backlog-size 10mb

高频问题

怎么判断 Redis 某个节点是否正常工作?

通过互相的 ping-pong 心态检测机制,如果有一半以上的节点去 ping 一个节点的时候没有 pong 回应,集群就会认为这个节点挂掉了,会断开与这个节点的连接。

  • 主默认每 10 秒对从发送 ping,repl-ping-slave-period 控制发送频率。

  • 从每 1 秒发送 replconf ack{offset} 命令,给主上报自身当前的复制偏移量,目的是为了:

    • 实时监测主从节点网络状态;
    • 上报自身复制偏移量检查复制数据是否丢失, 如丢失, 再从主复制缓冲区中拉取丢失数据。

过期key如何处理?

主模拟一条del命令发送给从

Redis 是同步复制还是异步复制?

主每次收到写命令之后,先写到内部的缓冲区,然后异步发送给从节点。

主从复制中两个 Buffer(replication buffer 、repl backlog buffer)有什么区别?

  • repl backlog buffer:增量复制阶段,一主只分配一个;

    • 满了覆盖起始位置数据
  • replication buffer:全量复制阶段和增量复制阶段都会出现

    • 主会给每个新连接的从,分配一个;
    • 满了,连接断开删除缓存,从重新连接,重新全量复制。

如何应对主从数据不一致?

Why?

  • 主从间的命令复制是异步的,无法实现强一致性

How?

  • 尽量保证主从节点间的网络连接状况良好,避免主从节点在不同的机房。

  • 可以开发一个外部程序来监控主从节点间的复制进度。

    • INFO replication 命令查看主接收写命令的进度信息(master_repl_offset)和从复制写命令的进度信息(slave_repl_offset)
    • 可以开发一个监控程序,先 INFO replication ,master_repl_offset - slave_repl_offset 得到从和主间的复制进度差值。
    • 如果某个从的进度差值大于预设的阈值,让从失效防止客户端读取。为了避免出现客户端和所有从都不能连接的情况,需要把复制进度差值的阈值设置得大一些。

主从切换如何减少数据丢失?

主从切换数据丢失的情况:

  • 异步复制同步丢失

    • min-slaves-max-lag:一旦所有从节点数据复制和同步的延迟都超过这个值,主拒绝服务。防止主宕机导致丢失过多数据。
    • 客户端发现 master 不可写后,降级措施,将数据暂时写入本地缓存和磁盘中,等 master 恢复后重新写入,也可以将数据写入 kafka 消息队列。
  • 集群产生脑裂数据丢失

    • 脑裂:主网络异常,哨兵找不到,新选了主,形成双主。

    • 主网络恢复只能变成从,重新全量同步新主,原来的新数据丢失

减少脑裂的数据丢的方案

  • 当主发现从下线的数量太多,或网络延迟太大,禁止写操作

    • min-slaves-to-write x:主必须要有至少 x 个从节点连接
    • min-slaves-max-lag x:主从数据复制和同步的延迟不能超过 x 秒

主从如何做到故障自动切换?

  • 需要人工处理
  • 哨兵

哨兵

Why?

主节点出问题,人工切换太沙雕了。

How?

Redis 2.8 版本提供的哨兵(Sentinel)机制:实现主从节点故障转移。监测、选主、通知。

监控

哨兵每1s对主发PING,没有在down-after-milliseconds内收到主的响应,主被判断下线。

  • 主观下线:哨兵网络问题观察不到主,但主其实没问题
  • 客观下线:主确实有问题

Why?

为避免单哨兵导致主观下线的错误判断,需要多个(>=3)哨兵对主进行监控

How?

一个哨兵发现主下线,所有哨兵进行投票,超过quorum个赞同就确定主下客观线。

  • 三个哨兵quorum设置为2(1/2+1)

【Redis】高可用:主从、哨兵、切片集群

哨兵leader选举

Why?

由哪个哨兵进行主从故障转移?

How?

  • 候选者:发现主下线的哨兵
  • 投票:每个哨兵只投一票,候选者可投自己
  • 归票:半数以上的赞成票 and 大于等于哨兵配置文件中的 quorum 值

如果未满足条件

故障转移

过程:

  1. 从里挑选出一个转换为主。

    1. 去除网络不好的从:down-after-milliseconds断链超过10次

    2. 选主:优先级排序,优先级相同按复制进度排序、再相同以ID小优先

      • slave-priority:从的优先级,高配置节点可以优先级高
      • slave_repl_offset:复制进度
    3. 向这个选出来的从发送 SLAVEOF no one 命令,转换为主。哨兵 leader 每秒向被升级的从发送 INFO 命令判断当前是否升级完成。

  2. 所有从修改复制目标为复制「新主节点」;

    1. 新主升级完成,哨兵leader向所有从发送 SLAVEOF 命令转移新主
  3. 将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;

    1. 哨兵向 +switch-master 频道发布新主节点的 IP 地址和端口的消息,客户端用新主的 IP 地址和端口通信
    2. 哨兵提供的消息订阅频道:
    3. 【Redis】高可用:主从、哨兵、切片集群
  4. 继续监视旧主,当重新上线时,设置新主的从;

哨兵集群

哨兵节点之间通过 Redis 的发布者/订阅者机制来相互通信

  • 主节点:sentinel:hello 频道

    • 哨兵把自己IP端口发送到__sentinel__:hello,其他订阅的哨兵就可以感知,并与之建立连接
  • 哨兵通过向主发送INFO得知从节点,并建立连接

【Redis】高可用:主从、哨兵、切片集群【Redis】高可用:主从、哨兵、切片集群

切片集群

Why?

数据量太大,单机内存不够用。

How?

Redis Cluster:

  1. 数据到哈希槽映射(16384 个哈希槽)

    1. 键值对的 key,按照 CRC16 算法计算一个 16 bit 值。
    2. 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。
  2. 哈希槽到实例映射

    1. 平均分配: cluster create 命令创建 Redis 集群时,自动把所有哈希槽平均分布到集群节点上。

    2. 手动分配: cluster meet 命令手动建立节点间的连接,组成集群,再使用 cluster addslots 命令,指定每个节点上的哈希槽个数。

【Redis】高可用:主从、哨兵、切片集群

转载自:https://juejin.cn/post/7244530183049904188
评论
请登录