redis设计与实现读书笔记(四)

2021-01-21  本文已影响0人  peareaden

本文内容为《redis设计与实现》一书学习笔记。本文主要概述十五到十六章内容。

第十五章 复制

可以通过执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制(replicate)另一个服务器。如:

127.0.0.1:12345> SLAVEOF 127.0.0.1:6379
OK

服务器127.0.0.1:12345将成为127.0.0.1:6379的从服务器。
进行复制中的主从服务器双方的数据库将保存相同的数据,这种现象即“数据库状态一致”。

15.1 旧版复制功能的实现

Redis的复制功能分为同步(sync)和命令传播(commandpropagate)两个操作。

同步:用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。 当客户端向从服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器首先需要执行同步操作,将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器通过向主服务器发送SYNC命令来完成同步操作,以下是SYNC命令的执行步骤:

命令传播:在执行同步后,当主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。 主服务器会将自己执行的写命令,也即是造成主从服务器不一致的那条写命令,发送给从服务器执行,当从服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。

15.2 旧版复制功能的缺陷

在Redis中,从服务器对主服务器的复制可以分为以下两种情况:

对于初次复制来说,旧版复制没有问题;但是对于断线重连后的复制,旧版复制效率非常低。断线重连后,主从服务器状态不再一致,从服务器向主服务器发送SYNC命令;但主从服务器断开的时间越短,主服务器在断线期间执行的写命令就越少,而执行少量写命令所产生的数据量通常比整个数据库的量要少得多。为了让从服务器补足一小部分缺失的数据,却要让主从服务器重新执行一次SYNC命令(重新发送所有数据),这种做法是很低效的。

15.3 新版复制功能的实现

为了解决旧版复制功能在处理断线重复制情况时的低效问题,Redis从2.8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作。PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:

15.4 部分重同步的实现

部分重同步功能由以下三个部分构成:

  1. 如果offset偏移量之后的数据(即offset+1开始的数据)仍然存在于复制积压缓冲区里面,那么主服务器会对从服务器执行部分重同步操作;
  2. 否则,就会执行完整重同步操作,这和SYNC命令是一样的;

复制积压缓冲区的最小大小可以根据公式second*write_size_per_second来估算,其中second为从服务器断线后重新连接上主服务器所需的平均时间(以秒计算);write_size_per_second是主服务器平均每秒产生的写命令数据量(协议格式的写命令的长度总和)。

15.5 PSYNC命令的实现

PSYNC命令的调用方法有两种:

  1. 主服务器返回+FULLRESYNC <runid> <offset>回复,表示主服务器将与从服务器执行完整重同步操作:runid是这个主服务器的运行ID,从服务器会将这个ID保存起来,下一次发送PSYNC命令时使用;offset是主服务器当前的复制偏移量,从服务器会将这个值作为自己的初始化偏移量。
  2. 主服务器返回+CONTINUE回复,表示主服务器将与从服务器执行部分重同步操作,从服务器等待主服务器将自己缺少的那部分数据发送过来就可以了。
  3. 主服务器返回-ERR回复,表示主服务器的版本低于Redis 2.8,识别不了PSYNC命令,从服务器将向主服务器发送SYNC命令,并与主服务器执行完整同步操作。
    PSYNC命令执行完整重同步和部分重同步流程图如下:


关于PSYNC命令,书中给出了一个便于理解的完整例子,但原文较长所以此处省略。

15.7 心跳检测

第十六章 Sentinel

Sentinel(哨岗、哨兵)是Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

16.1 启动并初始化Sentinel

启动一个Sentinel可以使用命令

$ redis-sentinel /path/to/your/sentinel.conf

或者:

$ redis-server /path/to/your/sentinel.conf --sentinel

Sentinel启动时,需要执行以下步骤:

  1. 初始化服务器。Sentinel本质上只是一个运行在特殊模式下的Redis服务器(默认26379端口)。所以启动Sentinel的第一步,就是初始化一个普通的Redis服务器,但是不需要像普通Redis服务器那样载入RDB文件之类的操作,因为它不需要使用Redis数据库功能;

  2. 将普通Redis服务器使用的代码替换成Sentinel专用的代码。在Sentinel模式下,Redis服务器不能执行诸如SET、DBSIZE、EVAL等等这些命令,因为服务器根本没有在命令表中载入这些命令。PING、SENTINEL、INFO、SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE和PUNSUBSCRIBE这七个命令就是客户端可以对Sentinel执行的全部命令。

  3. 初始化Sentinel状态。

  4. 根据给定的配置文件,初始化Sentinel的监视主服务器列表
    Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,字典的键是被监视主服务器的名字,字典的值是被监视主服务对应的实例结构

  5. 创建连向主服务器的网络连接
    Sentinel将成为主服务器的客户端,可以向主服务器发送命令,并从命令回复中获取相关的信息。对于每个被Sentinel监视的主服务器来说,Sentinel会创建两个面向主服务器的异步网络连接:

16.2 获取主服务器信息

Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息。

16.3 获取从服务器信息

当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。
创建命令连接之后,Sentinel默认也会以十秒一次的频率通过命令连接向从服务器发送INFO命令,以获取从服务器信息。

16.4 向主服务器和从服务器发送信息

在默认情况下,Sentinel会以每两秒一次的频率,通过命令连接,向所有被监视的Redis服务器发送一个命令,向服务器的sentinel:hello频道发送一条信息来向其他Sentinel宣告自己的存在

PUBLISH _sentinel _:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

16.5 接收来自主服务器和从服务器的频道信息

对于每个与Sentinel连接的服务器,Sentinel既通过命令连接向服务器的__sentinel __:hello频道发送信息,又通过订阅连接从服务器的__sentinel __:hello频道接收信息,如下图。


如果一个Redis服务器被多个Sentinel实例监视,那么一个Sentinel向某个被监视的Redis服务器发送的频道信息,会被其他所有监视这个Redis服务器的Sentinel实例接收到,这些Sentinel接收到不是自己发送的频道信息之后,会对其他Sentinel发送的频道信息进行解析,如下图。


Sentinel只会和主服务器和从服务器创建命令连接和订阅连接,Sentinel之间则只创建命令连接

16.6 检测主观下线状态

在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他Sentinel在内)发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
在Sentinel配置文件中有一个配置:down-after-milliseconeds,如果一个实例(包括主服务器、从服务器、其他Sentinel在内)在down-after-milliseconeds毫秒后依然没有返回有效的PING回应,那么Sentinel就会判断该实例为下线;

16.7 检测客观下线状态

当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其他Sentinel进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel那里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器执行故障转移操作。

16.8 选举领头Sentinel

当一个主服务器被判定为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,负责执行故障转移操作:

16.9 故障转移

在选举产生领头Sentinel之后,领头Sentinel就会对已下线的主服务器执行故障转移操作:

  1. 选出新的主服务器
    故障转移的第一步就是需要在故障的主服务器的所有从服务器中挑选一个状态良好、数据完整的从服务器,然后向这个从服务器发送SLAVEOF no one命令,将这个从服务器转换成主服务器;
    领头Sentinel会将已下线的Sentinel服务器的所有从服务器保存在一个列表里面,然后按照下面的规则过滤:
  1. 修改从服务器的复制目标
  2. 将旧的主服务器变为从服务器
上一篇下一篇

猜你喜欢

热点阅读