高可用篇(redis底层分析)

文章详细介绍了Redis的主从复制过程,包括从服务器如何连接主服务器,全量和增量复制的步骤,以及如何处理网络断开后的数据同步。接着,文章阐述了哨兵机制的作用,它是如何监控主从节点的状态,判断主节点的主观和客观下线,以及在主节点故障时如何执行主从切换。最后,提到了哨兵集群通过发布者/订阅者机制实现通信。
摘要由CSDN通过智能技术生成

一、关于主从的基本思路:

首先由于数据都存储在一个服务器上,如果该服务器发生某些意外,此会引出无法服务新的请求数据丢失问题,这样就需要多个服务器。但是这多个服务器中的数据要保持一致且要有规则(比如几个服务器执行写操作),于是可以引出主从复制模式,这个模式保证多台服务器的数据一致且主从服务器直接读写分离方式,这样客户端发来写或读操作命令后,见图如下:在这里插入图片描述
此外呢,如果某一时刻主服务器宕机,那么需要选该主服务器之下的从服务器之一为新主服务器,这个过程是哨兵发挥作用,就如其名,含义为一直盯着主服务器,观其挂没。
以上就是主从的基本思路,中间有许多细节并没体现(比如主服务器怎么与从服务器进行写操作同步?主服务器挂了之后,哨兵该怎么做呢?等等问题)。接下来开始认真看吧:

二、主从复制(主从怎么连接?主从怎么复制?)

  1. 执行此命令之后,服务器B就会变成服务器 A 的从服务器
# 服务器 B 执行这条命令
replicaof <服务器 A 的 IP 地址> <服务器 A 的 Redis 端口号>
  1. 从服务器开始与主服务器进行第一次同步,步骤如下:
    第一部, 建立链接、协商同步。从服务器就会给主服务器发送 psync 命令, 主服务器收到 psync 命令(此命令含两个参数,分别是主服务器的 runID 和复制进度 offset)后,会用 FULLRESYNC 作为响应命令返回给对方,此响应代表主服务器会把所有的数据都同步给从服务器,即全量复制
    第二部,主服务器同步数据给从服务器。主服务器执行bgsave(不影响主进程的命令,会通过fork函数生成一个子进程,也就是不影响服务客户端新的请求)生成RDB文件,并发送给从服务器,从服务器先清空数据然后加载RDB文件。但是主服务器仍不能把所有的写操作命令都给从服务器。主服务器在下面这三个期间中将收到的写操作命令,写入到 replication buffer 缓冲区里:
    (1)主服务器生成 RDB 文件期间
    (2)主服务器发送 RDB 文件给从服务器期间
    (3)从服务器加载RDB文件期间
    第三部,主服务器发送新写操作命令给从服务器。主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器,从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令,这时主从服务器的数据就一致了。
  2. 从服务器与主服务器之间会建立tcp连接。以后通过此连接主服务器可以直接发送给从服务器,以此维护主从数据一致。此过程为基于长连接的命令传播
对于以上步骤中的再多些细节因素就可以得到如下注意事项以及如何解决?如下:
  1. 如果主服务器中数据量很大时候,那么主服务器的进程就会一直忙于通过fork函数创建子进程,也就是阻塞了主服务器的进程,会导致客户端的新请求会迟迟得不到响应
  2. 传输 RDB 文件会占用主服务器的网络带宽,会对主服务器响应命令请求产生影响。

以上这两个问题,可使从服务器来充当主服务器的一个小弟(经理)这个角色进行解决。通过这种方式,主服务器生成 RDB 和传输 RDB 的压力可以分摊到充当经理角色的从服务器

  1. 对于我们说过的主从之间已经建立好tcp连接。如果tcp断开了呢,这时从服务器的数据就没办法和主服务器保持一致了,客户端就可能从从服务器读到旧的数据。进而也可以想到,如果在网络断开期间,客户端发新的写操作给主服务器,在某一时刻网络连接恢复了,又怎把这些写操作发给从服务器呢?

对于以上这个问题,采用增量复制方法进行解决,解决思路如下:repl_backlog_buffe 是一个环形缓冲区里面有两个偏移量(也可以联想到算法的双指针),主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己写到的位置,从服务器使用 slave_repl_offset 来记录自己读到的位置。见图如下:
在这里插入图片描述
此图详解:在主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入到 repl_backlog_buffer 缓冲区里,因此这个缓冲区里一直会保存着最近传播的写命令。当从服务器断开有连接上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器,主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差值来执行增量同步或者全量复制操作。
呵,还有细节:因为repl_backlog_buffer 缓冲区是环形的,那么就可能在某一时刻出现主服务器写的数据会把从服务器想读的数据覆盖。那么此时,主服务器就会采用全量同步,这个方式比增量同步的性能损耗要大很多。所以,我们应该调整下 repl_backlog_buffer 缓冲区大小,尽可能的大一些。大小可以通过这个式子进行计算:
在这里插入图片描述
以上这两个变量含义为:

  • second 为从服务器断线后重新连接上主服务器所需的平均 时间(以秒计算)。
  • write_size_per_second 则是主服务器平均每秒产生的写命令数据量大小。

三、 哨兵机制

  1. 哨兵引出:主服务器挂了,需要继续服务客户端的请求和主从机制,来使redis能够正常合理工作。
  2. 哨兵简介:哨兵其实是一个运行在特殊模式下的 Redis 进程,所以它也是一个节点。从“哨兵”这个名字也可以看得出来,它相当于是“观察者节点”,观察的对象是主从节点。

以下为哨兵机制的工作原理:

哨兵会每隔 1 秒给所有主从节点发送 PING 命令,当主从节点收到 PING 命令后,会发送一个响应命令给哨兵,这样就可以判断它们是否在正常运行。见图如下:在这里插入图片描述

如果主节点或者从节点没有在规定的时间内响应哨兵的 PING 命令,哨兵就会将它们标记为主观下线。此外主节点还有客观下线,当主节点也被判断为客观下线之后,那么它就是真的挂了。(因为主观下线会因为主节点的系统压力比较大等原因误判)。那么客观下线是怎么判断的呢?是这样的,哨兵在部署的时候不会只部署一个节点,而是用多个节点部署成哨兵集群(最少需要三台机器来部署哨兵集群),通过多个哨兵节点一起判断,就可以就可以避免单个哨兵因为自身网络状况不好,而误判主节点下线的情况。流程如下:
(1) 当一个哨兵判断主节点为主观下线后,就会向其他哨兵发起命令,其他哨兵收到这个命令后,就会根据自身和主节点的网络状况,做出赞成投票或者拒绝投票的响应。
(2)当这个哨兵的赞同票数达到哨兵配置文件中的 quorum 配置项设定的值后,这时主节点就会被该哨兵标记为客观下线。(quorum 的值一般设置为哨兵个数的二分之一加1
(3)此时就可判断该主节点是否真正下线

此后,哨兵判断完主节点客观下线后,哨兵就要开始在多个从节点中,选出一个从节点来做新主节点。现在就要选出谁来主持这个主从切换呢?
(1)候选者(判断主节点为客观下线的哨兵节点)会向其他哨兵发送命令,表明希望成为主持人来执行主从切换,并让所有其他哨兵对它进行投票。每个哨兵只有一次投票机会,如果用完后就不能参与投票了,可以投给自己或投给别人,但是只有候选者才能把票投给自己。
(2)若此候选者满足 拿到半数以上的赞成票 且 拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
(3)若条件满足,那么候选者就成为了主持人

  1. 到此,已经知道了 主节点已下线完成主从切换的主持人,那么接下来要做的就是开始进行主从切换
    (1)选出新主节点(层层过滤):首先过滤掉网络不好的从节点,然后由主持人进行三轮考察。第一轮,优先级最高的从节点胜出。Redis 有个叫 slave-priority 配置项,可以给从节点设置优先级。每一台从节点的服务器配置不一定是相同的,我们可以根据服务器性能配置来设置从节点的优先级(性能好的从节点优先级较高)。第二轮,复制进度最靠前的从节点胜出,这个是比较从节点在repl_backlog_buffer缓冲区的复制偏移量大小,看哪个的复制偏移量最接近主节点的写入偏移量,那么哪个从节点的数据就是最新的。第三轮,ID号最小的胜出,每个从节点都有一个编号,这个编号就是 ID 号,是用来唯一标识从节点的。这样就选出了新主节点
    以上流程见图如下:

在这里插入图片描述

(2) 将从节点指向新主节点。让已下线主节点属下的所有从节点指向新主节点,这一动作可以通过向从节点发送 SLAVEOF 命令来实现。
(3)通知客户端主节点已更换。这主要通过 Redis 的发布者/订阅者机制来实现的。每个哨兵节点提供发布者/订阅者机制,客户端可以从哨兵订阅消息。客户端和哨兵建立连接后,客户端会订阅哨兵提供的频道。主从切换完成后,哨兵就会向 +switch-master 频道发布新主节点的 IP 地址和端口的消息,这个时候客户端就可以收到这条信息,然后用这里面的新主节点的 IP 地址和端口进行通信了。此外,客户端还可以Redis 的发布者/订阅者机制知道主从切换的进度。
(4)将旧主节点变为从节点。故障转移操作最后要做的是,继续监视旧主节点,当旧主节点重新上线时,哨兵集群就会向它发送 SLAVEOF 命令,让它成为新主节点的从节点。

  1. 至此,哨兵机制的实现到此结束。

四、通过Redis的发布者/订阅者机制实现哨兵集群

思路如下:在主从集群中,主节点上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。
在下图中,哨兵 A 把自己的 IP 地址和端口的信息发布到__sentinel__:hello 频道上,哨兵 B 和 C 订阅了该频道。那么此时,哨兵 B 和 C 就可以从这个频道直接获取哨兵 A 的 IP 地址和端口号。然后,哨兵 B、C 可以和哨兵 A 建立网络连接。在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis 是一个基于内存的高性能键值数据库,常被用于缓存、消息队列等场景。Redis底层实现原理主要包括以下几个方面: 1. 内存存储:Redis 将所有数据都存储在内存中,通过使用数据结构来提高内存使用效率,如使用压缩列表来存储链表等。 2. 异步 I/O:Redis 采用单线程模型,通过异步 I/O 来提高并发处理能力。当客户端发送请求时,Redis 将请求放入请求队列中,然后通过 epoll 或 kqueue 等机制来监听文件描述符,当有请求完成时,再将结果返回给客户端。 3. 数据持久化:Redis 支持两种数据持久化方式,分别是快照和日志。快照是将内存中的数据定期保存到磁盘上,而日志则是将每个写操作转化为日志,当需要恢复数据时,通过重新执行日志中的写操作来实现。 4. 多种数据结构支持:Redis 支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等,每种数据结构都有不同的实现方式,如字符串采用简单动态字符串,哈希表采用哈希表等。 5. 网络协议:Redis 使用自定义的网络协议,协议格式简单,易于解析。客户端与 Redis 服务器之间的通信都是通过网络协议来实现的。 总之,Redis底层实现原理主要是通过内存存储、异步 I/O、数据持久化、多种数据结构支持和网络协议等多种技术手段来实现高性能和高可用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值