面试官:请讲一下 Redis 主从复制的功能及实现原理
摘要:Redis 在主从模式下会有许多问题需要考虑,这里写了一些关于 redis 在多服务器下的一些问题分析和总结。
Redis 单节点存在单点故障问题,为了解决单点问题,一般都需要对 redis 配置从节点,然后使用哨兵来监听主节点的存活状态,如果主节点挂掉,从节点能继续提供缓存功能。主从配置结合哨兵模式能解决单点故障问题,提高 redis 可用性。从节点仅提供读操作,主节点提供写操作。对于读多写少的状况,可给主节点配置多个从节点,从而提高响应效率。
主从复制过程:
从节点执行 slaveofmasterIP,保存主节点信息
从节点中的定时任务发现主节点信息,建立和主节点的 socket 连接
从节点发送 Ping 信号,主节点返回 Pong,两边能互相通信
连接建立后,主节点将所有数据发送给从节点(数据同步)
主节点把当前的数据同步给从节点后,便完成了复制的建立过程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。
Redis 的数据同步过程:
redis2.8 之前使用 syncrunId 同步命令,redis2.8 之后使用 psyncrunId 命令。
两者不同在于,sync 命令仅支持全量复制过程,psync 支持全量和部分复制。
介绍同步之前,先介绍几个概念:
runId:每个 redis 节点启动都会生成唯一的 uuid,每次 redis 重启后,runId 都会发生变化。
offset:主节点和从节点都各自维护自己的主从复制偏移量 offset,当主节点有写入命令时,offset=offset+命令的字节长度。从节点在收到主节点发送的命令后,也会增加自己的 offset,并把自己的 offset 发送给主节点。这样,主节点同时保存自己的 offset 和从节点的 offset,通过对比 offset 来判断主从节点数据是否一致。
repl_backlog_size:保存在主节点上的一个固定长度的先进先出队列,默认大小是 1MB。
主节点发送数据给从节点过程中,主节点还会进行一些写操作,这时候的数据存储在复制缓冲区中。从节点同步主节点数据完成后,主节点将缓冲区的数据继续发送给从节点,用于部分复制。
主节点响应写命令时,不但会把命名发送给从节点,还会写入复制积压缓冲区,用于复制命令丢失的数据补救。
上面是 psync 的执行流程:
从节点发送 psyncrunId 命令,主节点有三种响应:
FULLRESYNC:第一次连接,进行全量复制
CONTINUE:进行部分复制
ERR:不支持 psync 命令,进行全量复制
全量复制和部分复制的过程
上面是全量复制的流程。主要有以下几步:
从节点发送 psync ? -1 命令(因为第一次发送,不知道主节点的 runId,所以为?,因为是第一次复制,所以 offset=-1)。
主节点发现从节点是第一次复制,返回 FULLRESYNC {runId} {offset},runId 是主节点的 runId,offset 是主节点目前的 offset。
从节点接收主节点信息后,保存到 info 中。
主节点在发送 FULLRESYNC 后,启动 bgsave 命令,生成 RDB 文件(数据持久化)。
主节点发送 RDB 文件给从节点。到从节点加载数据完成这段期间主节点的写命令放入缓冲区。
从节点清理自己的数据库数据。
从节点加载 RDB 文件,将数据保存到自己的数据库中。
-如果从节点开启了 AOF,从节点会异步重写 AOF 文件。
关于部分复制有以下几点说明:
1、部分复制主要是 Redis 针对全量复制的过高开销做出的一种优化措施,使用 psyncrunId 命令实现。当从节点正在复制主节点时,如果出现网络闪断或者命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,主节点的复制积压缓冲区将这部分数据直接发送给从节点,这样就可以保持主从节点复制的一致性。补发的这部分数据一般远远小于全量数据。
2、主从连接中断期间主节点依然响应命令,但因复制连接中断命令无法发送给从节点,不过主节点内的复制积压缓冲区依然可以保存最近一段时间的写命令数据。
3、当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行 ID。因此会把它们当做 psync 参数发送给主节点,要求进行部分复制。
4、主节点接收到 psync 命令后首先核对参数 runId 是否与自身一致,如果一致,说明之前复制的是当前主节点;之后根据参数 offset 在复制积压缓冲区中查找,如果 offset 之后的数据存在,则对从节点发送+COUTINUE 命令,表示可以进行部分复制。因为缓冲区大小固定,若发生缓冲溢出,则进行全量复制。
5、主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。
Redis 主从复制会存在以下问题:
一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
主节点的写能力受到单机的限制。
主节点的存储能力受到单机的限制。
原生复制的弊端在早期的版本中也会比较突出,比如:redis 复制中断后,从节点会发起 psync。此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。
所以用哨兵解决以上问题。
哨兵的功能
Redis Sentinel(哨兵)主要功能包括主节点存活检测、主从运行情况检测、自动故障转移、主从切换。Redis Sentinel 最小配置是一主一从。
Redis 的 Sentinel 系统可以用来管理多个 Redis 服务器,该系统可以执行以下四个任务:
监控:不断检查主服务器和从服务器是否正常运行。
通知:当被监控的某个 redis 服务器出现问题,Sentinel 通过 API 脚本向管理员或者其他应用程序发出通知。
自动故障转移:当主节点不能正常工作时,Sentinel 会开始一次自动的故障转移操作,它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,并且将其他的从节点指向新的主节点,这样人工干预就可以免了。
配置提供者:在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取主节点的信息。
哨兵的原理
1、每个 Sentinel 节点都需要定期执行以下任务:每个 Sentinel 以每秒一次的频率,向它所知的主服务器、从服务器以及其他的 Sentinel 实例发送一个 PING 命令。(如上图)
2、如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel 标记为主观下线。(如上图)
3、如果一个主服务器被标记为主观下线,那么正在监视这个服务器的所有 Sentinel 节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态。
4、如果一个主服务器被标记为主观下线,并且有足够数量的 Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。
5、一般情况下,每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令,当一个主服务器被标记为客观下线时,Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率,会从 10 秒一次改为每秒一次。
6、Sentinel 和其他 Sentinel 协商客观下线的主节点的状态,如果处于 SDOWN 状态,则投票自动选出新的主节点,将剩余从节点指向新的主节点进行数据复制。
7、当没有足够数量的 Sentinel 同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向 Sentinel 的 PING 命令返回有效回复时,主服务器的主观下线状态就会被移除。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/cbb1809c9b26524e1055d396b】。文章转载请联系作者。
评论