天天用着Redis集群,主从同步该知道吧?集群工作原理是否需要了解下?

    技术2024-11-27  9

      

    作者:z小赵

    ★ 

    一枚用心坚持写原创的“无趣”程序猿,在自身受益的同时也让朋友们在技术上有所提升。

    前言

    插播一个小插曲,本来文章已经写好准备发布了,手贱清理了缓存导致文本内容全部丢失,以至于重新写稿。借此提醒广大粉丝朋友,平时一定要养成备份的好习惯,谨防出现博主这种愚蠢的行为。

    上篇文章讲解了缓存剔除的流程,以及 RDB 文件和 AOF 文件的原理介绍,本文我们来讲讲数据复制和集群工作的原理。

    目录

    主从数据同步原理分析。

    Redis 集群工作原理剖析。

    集群槽指派机制。

    集群服务自动检测 & 故障转移恢复操作。

    主从数据同步原理分析

    主从数据同步分为两种同步情况,分为完整重同步和部分重同步两种。

    完整重同步流程

    完整重同步是指:在从服务器第一次启动时,其内部没有任何数据的时候,通过向从服务器发送 slaveof master_ip port 命令,通知从服务器向指定的主服务器发起完整的数据备份请求。具体流程如下:

    客户端向从服务器发送数据同步请求,从服务器接收到命令后,便通过指定的主服务器 ip 和 port 向主服务器发送 PSYNC 请求数据同步。

    主服务器接收到 PSYNC 后,判断是要求进行全量数据同步,此时主服务器生成当前服务器对应的 RDB 文件,然后将其返回给从服务器。

    在从服务器进行数据完整重同步的过程中,主服务器接收到的写请求在自己的服务器中完成命令操作之后,同时将写命令也发送到从服务器中。

    从服务器接收到 RDB 文件后,开始解析 RDB 文件,对 RDB 文件解析完成和主服务器写命令的操作之后,也就意味着数据完成完整重同步流程。

    以上整个流程便是数据完整重同步的具体执行流程,额外需要注意的一点是,完整重同步其实就是将主服务器的整个完整数据进行一次完整的备份。

    部分重同步

    部分重同步是指:从服务器在复制了一部分数据后发生了断线重连后继续复制的情形。在从服务器由于网络等原因导致数据同步终止,当网络恢复后,从服务器继续向主服务器进行数据同步操作。Redis 通过偏移量的机制来实现数据部分重同步操作,即主服务器和从服务器都维护着一个执行命令的偏移量,同时在主服务器内部维护着一个复制积压缓冲区(复制积压缓冲区是可以调节大小的,默认大小 1M,通过修改 repl-backlog-size 配置进行修改),该缓冲区中缓存着部分写命令和写命令对应的偏移量。当从服务器断线重连后,从服务器在发送数据同步请求的时候会带着从服务器当前同步的偏移量,如果从服务器发送的偏移量在复制积压缓冲区中存在,则从复制积压缓冲区中对应的偏移量位置继续复制往后位置的命令,如果从服务器发送的偏移量和主服务器维护的偏移量相等,则表示主从数据是一致的。部分重同步流程如下图所示:

    部分重同步机制的优势:

    相比于全量重同步,减少了数据同步量

    由于部分重同步数据量小,可以更快速的达到主从数据一致的目的

    由于数据同步量少,从而节省了带宽资源,同时也节省了主服务器生成 RDB 文件而产生的 CPU 浪费情况

    Redis 集群工作原理剖析

    Redis 集群在生产环境中通常是由多个节点服务器所组成,那么多个节点是如何建立起连接的呢?起初 Redis 集群是由各个节点各自为一个集群的,通过执行 CLUSTER MEET 目标机IP 目标机端口 命令,使得两台机器建立连接,从而构成集群。举个例子,假设现在有 3 个节点要组成一个 Redis 集群。

    起初,Redis 有 3 个节点且各自为一个伪集群,其如下图:

    通过客户端向节点 2 发送 CLUSTER MEET 节点1IP 节点1端口 命令,此时节点 2 加入了节点 1 所在的集群,其如下图:

    同理,通过客户端向节点 3 发送 CLUSTER MEET 节点1IP 节点1端口 命令,此时节点 3 加入了节点 1 所在的集群,在节点 1 和节点 3 建连完成后,节点 2 也会和节点 3 完成相同的操作,最终形成了 3 个节点互联的集群,其如下图所示:

    上述流程展示了一个集群建连的过程,那么两个节点在建连的时候到底是怎么实现的呢?举个例子,以节点 1 和节点 2 建连为例:

    首先节点 1 会创建一个 Node 结构体,用于存储节点 2 的信息,比如节点 2 的名字、IP、Port 等等信息。

    然后节点 1 发送 CLUSTER MEET IP PORT 命令到节点 2。

    节点 2 接收到节点 1 的命令后,在其节点上创建一个 Node 用于存储节点 1 的信息。

    节点 2 存储完成节点 1 的信息后,向节点 1 发送 PONG 命令,表示自己已经成功接收到了节点 1 的信息。

    节点 1 收到节点 2 返回的 PONG 命令后,然后节点 1 再向节点 2 发送 PING 命令,表示节点 1 知道节点 2 成功接收到节点 1 发送的消息了,至此两个节点完成建连。

    Redis 集群槽指派流程

    通过上面的流程明白了 Redis 集群是如何构建起来的,现在有个问题是假设有一条写命令发送到集群中,那么最终应该由那个节点实际执行呢?举个例子,集群由三个主节点组成,执行 set key1 value1 命令。Redis 集群通过槽指派机制来决定写命令应该被分配到那个节点。整个集群对应的槽是由 16384 大小的二进制数组组成,集群中每个主节点分配一部分槽,每条写命令落到二级制数组中的某个位置,该位置被分配给了那个节点则对应的命令就由该节点去执行。槽指派对应的二进制数组如下图所示:

    举个例子:假设节点 1 执行 0 - 4999,节点 2 执行 5000 - 9999,节点 3 执行 10000 - 16383, set key1 value1 命令通过 CRC16(key1) & 16383 = 8876,即认为该命令最后落到二级制数组的 8876 位置,则该命令最终由节点 2 执行。在比如在节点 2 执行一条命令时,假设通过 CRC 计算后得到的值为 889,则其应该有节点 1 执行,此时命令会发生一个转向操作,将要执行的命令转向到节点 1 上去执行,其具体工作原理如下:

    集群服务自动检测 & 故障转移恢复操作

    通过上述文章介绍,我们基本明白了 Redis 集群的基本工作原理,现在我们来看看集群节点自动检测,以及当节点发生故障时该如何进行故障转移恢复。假设现在集群由如下图所示,其总共由 3 个主节点和 6 个从节点构成。

    集群中每个主节点都会定时发送信息到其他主节点,如果其他主节点在规定时间内响应了发送消息的主节点,则发送消息的主节点认为响应了消息的这些主节点在正常工作,反之则认为响应消息的主节点疑似下线,则发送消息的主节点在其节点上将其标记疑似下线;当集群中超过半数的节点认为某个主节点被标记为疑似下线,则其中某个主节点将疑似下线节点标记为下线状态,并向集群广播一条下线消息,当下线节点对应的从节点接收到该消息时,则从从节点中选举出一个节点作为主节点继续对外提供服务。

    举个例子:如下图所示,假设节点 1 发送消息给节点 2 节点 3,然后节点 2 在规定时间内响应了节点 1 的信息,而节点 3 没有响应,此时节点 1 将节点 3 标记为疑似下线,然后节点 2 给节点 1 和节点 3 发送消息,节点 1 在规定时间内响应了节点 2,但是节点 3 没有响应节点 3,此时节点 2 先将其标记没疑似下线,同时发现节点 3 被标记的疑似下线个数超过集群总数的一半,所以节点 2 便将节点 3 标记为已下线状态,并将该消息广播给集群中所有的节点,节点 3 对应的从节点 5 和从节点 6 接收到该消息后,停止从节点 3 复制数据且节点 5 被选举为新的主节点,从节点 6 转而复制节点 5 的数据。

    故障转移图

    总结

    本文首先讲解了 Redis 主从复制的相关细节实现,然后接着讲解了 Redis 集群组成及相应的工作原理,最后讲解了集群自动检查及故障原理的实现。

    本来准备接着来讲讲集群的搭建,碍于文章篇幅,准备在下篇文章来专门讲述,本文干货满满,不懂的地方欢迎随时交流沟通。下篇文章再见,拜拜。

    特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下: 长按订阅更多精彩▼ 如有收获,点个在看,诚挚感谢
    Processed: 0.084, SQL: 9