Redis6.0.6_04_Redis 主从复制与哨兵模式

Redis 主从复制与哨兵模式

redis主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

redis主从复制的开启很简单,是在从节点发起的,完全不需要我们在主节点做任何事情。

开启主从复制的三种方式
  • 1、redis.conf修改replicaof
# 配置主节点ip、端口
replicaof <masterip> <masterport>
# 从节点只允许读
replica-read-only yes
  • 2、redis-server启动命令后加入 --replicaof
bin/redis-server ./redis.conf --replicaof <masterip> <masterport>
  • 3、redis服务启动后;在redis客户端使用命令replicaof ,则该Redis实例成为从节点
关闭主从复制
  • 1、配置文件模式修改配置文件重启即可
  • 2、剩下的两种命令方式可以再客户端通过命令replicaof no one断开主从复制,

从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。

主从复制的作用
  • 1、数据冗余: 主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 2、故障恢复: 当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 3、负载均衡: 在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  • 4、高可用基石: 除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
主从复制工作原理

主从复制过程大体可以分为3个阶段:连接建立阶段(即准备阶段)、数据同步阶段、命令传播阶段;

1、连接建立阶段
步骤1:保存主节点信息
从节点服务器内部维护了两个字段,即masterhost和masterport字段,用于存储主节点的ip和port信息。

replicaof是异步命令,从节点完成主节点ip和port的保存后,向发送replicaof命令的客户端直接返回OK,实际的复制操作在这之后才开始进行。
步骤2:建立socket连接
从节点每秒1次调用复制定时函数replicationCron(),如果发现了有主节点可以连接,便会根据主节点的ip和port,创建socket连接。如果连接成功,则:

从节点:为该socket建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收RDB文件、接收命令传播等。

主节点:接收到从节点的socket连接后(即accept之后),为该socket创建相应的客户端状态,并将从节点看做是连接到主节点的一个客户端,后面的步骤会以从节点向主节点发送命令请求的形式来进行。
步骤3:发送ping命令
从节点成为主节点的客户端之后,发送ping命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。

从节点发送ping命令后,可能出现3种情况:

  • (1)返回pong:说明socket连接正常,且主节点当前可以处理请求,复制过程继续。
  • (2)超时:一定时间后从节点仍未收到主节点的回复,说明socket连接不可用,则从节点断开socket连接,并重连。
  • (3)返回pong以外的结果:如果主节点返回其他结果,如正在处理超时运行的脚本,说明主节点当前无法处理命令,则从节点断开socket连接,并重连。
    步骤4:身份验证
    如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证;没有设置该选项,则不需要验证。从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。

如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续;如果不一致,则从节点断开socket连接,并重连。
步骤5:发送从节点端口信息
身份验证之后,从节点会向主节点发送其监听的端口号,主节点将该信息保存到该从节点对应的客户端的slave_listening_port字段中;该端口信息除了在主节点中执行info Replication时显示以外,没有其他作用。

2、数据同步阶段
主从节点之间的连接建立以后,便可以开始进行数据同步,该阶段可以理解为从节点数据的初始化。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步。
psync命令的执行过程
在这里插入图片描述
数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为全量复制部分复制
需要注意的是,在数据同步阶段之前,从节点是主节点的客户端,主节点不是从节点的客户端;而到了这一阶段及以后,主从节点互为客户端。原因在于:在此之前,主节点只需要响应从节点的请求即可,不需要主动发请求,而在数据同步阶段和后面的命令传播阶段,主节点需要主动向从节点发送请求(如推送缓冲区中的写命令),才能完成复制。

3、命令传播阶段
数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING和REPLCONF ACK。
延迟与不一致
需要注意的是,命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复;因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的程度,与主从节点之间的网络状况、主节点写命令的执行频率、以及主节点中的repl-disable-tcp-nodelay配置等有关。

repl-disable-tcp-nodelay no:该配置作用于命令传播阶段,控制主节点是否禁止与从节点的TCP_NODELAY;默认no,即不禁止TCP_NODELAY。当设置为yes时,TCP会对包进行合并从而减少带宽,但是发送的频率会降低,从节点数据延迟增加,一致性变差;具体发送频率与Linux内核的配置有关,默认配置为40ms。当设置为no时,TCP会立马将主节点的数据发送给从节点,带宽增加但延迟变小。

一般来说,只有当应用对Redis数据不一致的容忍度较高,且主从节点之间网络状况不好时,才会设置为yes;多数情况使用默认值no。

全量复制和部分复制

在Redis2.8以前,从节点向主节点发送sync命令请求同步数据,此时的同步方式是全量复制;在Redis2.8及以后,从节点可以发送psync命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。

  • 1、全量复制: 用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。
  • 2、部分复制: 用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。

全量复制
Redis通过psync命令进行全量复制的过程如下:

  • (1)从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行部分复制;具体判断过程需要在讲述了部分复制原理后再介绍。
  • (2)主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令
  • (3)主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态
  • (4)主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态
  • (5)如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态

全量复制是非常重型的操作:

  • (1)主节点通过bgsave命令fork子进程进行RDB持久化,该过程是非常消耗CPU、内存(页表复制)、硬盘IO的;
  • (2)主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都会带来很大的消耗
  • (3)从节点清空老数据、载入新RDB文件的过程是阻塞的,无法响应客户端的命令;如果从节点执行bgrewriteaof,也会带来额外的消耗

部分复制
部分复制的实现,依赖于三个重要的概念:

  • (1)复制偏移量
    主节点和从节点分别维护一个复制偏移量(offset),代表的是主节点向从节点传递的字节数;主节点每次向从节点传播N个字节数据时,主节点的offset增加N;从节点每次收到主节点传来的N个字节数据时,从节点的offset增加N。

offset用于判断主从节点的数据库状态是否一致:如果二者offset相同,则一致;如果offset不同,则不一致,此时可以根据两个offset找出从节点缺少的那部分数据。例如,如果主节点的offset是1000,而从节点的offset是500,那么部分复制就需要将offset为501-1000的数据传递给从节点。而offset为501-1000的数据存储的位置,就是下面要介绍的复制积压缓冲区。

  • (2)复制积压缓冲区
    复制积压缓冲区是由主节点维护的、固定长度的、先进先出(FIFO)队列,默认大小1MB;当主节点开始有从节点时创建,其作用是备份主节点最近发送给从节点的数据。注意,无论主节点有一个还是多个从节点,都只需要一个复制积压缓冲区。

在命令传播阶段,主节点除了将写命令发送给从节点,还会发送一份给复制积压缓冲区,作为写命令的备份;除了存储写命令,复制积压缓冲区中还存储了其中的每个字节对应的复制偏移量(offset)。由于复制积压缓冲区定长且是先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区。

由于该缓冲区长度固定且有限,因此可以备份的写命令也有限,当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。反过来说,为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size);例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。

从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:

  • 如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;

  • 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。

  • (3)服务器运行ID(runid)
    每个Redis节点(无论主从),在启动时都会自动生成一个随机ID(每次启动都不一样),由40个随机的十六进制字符组成;runid用来唯一识别一个Redis节点。通过redis客户端info server命令,可以查看节点的runid:

主从节点初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来;当断线重连时,从节点会将这个runid发送给主节点;主节点根据runid判断能否进行部分复制:

  • 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
  • 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。

redis哨兵模式

Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移。下面是Redis官方文档对于哨兵功能的描述:

监控(Monitoring): 哨兵会不断地检查主节点和从节点是否运作正常。
自动故障转移(Automatic failover): 当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
配置提供者(Configuration provider): 客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
通知(Notification): 哨兵可以将故障转移的结果发送给客户端。
其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

哨兵模式配置文件sentinel.conf
# sentinel.conf配置文件示例。

# 指定 redis 只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求
# 你可以绑定单一接口,如果没有绑定,所有接口都会监听到来的连接
#
# bind 127.0.0.1 192.168.1.1

# 设置外部网络连接redis服务;默认是yes,即开启;设置方式如下:
# 1、关闭protected-mode模式,此时外部网络可以直接访问
# 2、开启protected-mode保护模式,需配置bind ip或者设置访问密码
#
# protected-mode no

# sentinel监听端口,默认是26379,可以修改
#
port 26379

# 守护进程
# 是否在后台执行,yes:后台运行;no:不是后台运行
#
daemonize no

# 配置pid文件路径。当redis以守护模式启动时,如果没有配置pidfile,pidfile默认值是/var/run/redis-sentinel.pid
#
pidfile /var/run/redis-sentinel.pid

# 日志文件的位置,当指定为空字符串时,为标准输出,如果redis已守护进程模式运行,那么日志将会输出到  /dev/null 
#
logfile ""

# 哨兵将会在gossip hello消息中使用指定的ip地址,而不是自动发现的本地地址。
# sentinel announce-ip <ip>
# 哨兵会使用指定的端口
# sentinel announce-port <port>

# Sentinel服务运行时使用的临时文件夹
#
dir /tmp

# 告诉sentinel去监听地址为ip:port的一个master,
# 这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效。
# master-name只能包含英文字母,数字,和“.-_”这三个字符需要注意的是master-ip 要写真实的ip地址而不要用回环地址(127.0.0.1)。
sentinel monitor mymaster 127.0.0.1 6379 2

# 设置master和slaves验证密码,在监控redis实例时很有用。如果你想监控masters和slaves而设置不同的密码,这样是达不到目的的。
#
# sentinel auth-user <master-name> <username>

# 这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒
# 默认30秒
#
sentinel down-after-milliseconds mymaster 30000

# requirepass <password>
#
# 在failover期间我们可以重配slaves的个数(默认1个)
#
sentinel parallel-syncs mymaster 1

#  1)相邻前后两次failover的时间间隔
# 2)slave错误的配置为master多长时间后重新配置
# 3)正在进行的failover,发现配置没变,多长时间后取消failover
# 4)slaves被配置为新master的slave后,多长时间后有可能被重新配置sentinel failover-timeout <master-name> <milliseconds>
#
# 默认值3分钟
#
sentinel failover-timeout mymaster 180000

# 用来配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。对于脚本的运行结果有以下规则:
# 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
# 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
# 如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
# 一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
#
#
# 通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),
# 将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。
# 调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配置文件中配置了这个脚本路径,
# 那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
# sentinel notification-script <master-name> <script-path>
# 
#  当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。以下参数将会在调用脚本时传给脚本:

#       <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”, <role>是“leader”或者“observer”中的一个。 
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的。这个脚本应该是通用的,能被多次调用,不是针对性的。
#
# sentinel client-reconfig-script <master-name> <script-path>
#

# 安全
# 避免脚本重置,默认值yes
# 默认情况下,SENTINEL SET将无法在运行时更改notification-script和client-reconfig-script。
# 这避免了一个简单的安全问题,客户端可以将脚本设置为任何内容并触发故障转移以便执行程序。
#
sentinel deny-scripts-reconfig yes

# REDIS命令重命名
#
#
# 在这种情况下,可以告诉Sentinel使用不同的命令名称而不是正常的命令名称。
# 例如,如果主“mymaster”和相关副本的“CONFIG”全部重命名为“GUESSME”,我可以使用:
#
# SENTINEL rename-command mymaster CONFIG GUESSME
#
# 设置此类配置后,每次Sentinel使用CONFIG时,它将使用GUESSME。 请注意,实际上不需要尊重命令案例,因此在上面的示例中写“config guessme”是相同的。
#
# SENTINEL SET也可用于在运行时执行此配置。
#
# 为了将命令设置回其原始名称(撤消重命名),可以将命令重命名为它自身:
#
# SENTINEL rename-command mymaster CONFIG CONFIG
哨兵模式搭建

配置所有节点sentinel.conf如下参数

port 26379
daemonize yes
pidfile /local/redis-6.0.6/redis-sentinel.pid
logfile /local/redis-6.0.6/log/redis-sentinel.log
dir ./tmp
# 主节点ip
sentinel monitor mymaster 192.168.236.140 6379 2

哨兵模式可以单独服务器,个数也可自行控制

哨兵模式启动

# 方式一
./bin/redis-sentinel ./sentinel.conf
# 方式二
./bin/redis-server ./sentinel.conf --sentinel

连接哨兵节点

./bin/redis-cli -p 26379

查看

# 查看相关信息
>info

info Sentinel命令可以看到从节点的个数及哨兵节点的个数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f45rl9Ei-1603539276193)(en-resource://database/2163:1)]

哨兵节点支持的命令
  • (1)基础查询:通过这些命令,可以查询哨兵系统的拓扑结构、节点信息、配置信息等。
    info sentinel: 获取监控的所有主节点的基本信息
    sentinel masters: 获取监控的所有主节点的详细信息
    sentinel master mymaster: 获取监控的主节点mymaster的详细信息
    sentinel slaves mymaster: 获取监控的主节点mymaster的从节点的详细信息
    sentinel sentinels mymaster: 获取监控的主节点mymaster的哨兵节点的详细信息
    sentinel get-master-addr-by-name mymaster: 获取监控的主节点mymaster的地址信息,前文已有介绍
    sentinel is-master-down-by-addr: 哨兵节点之间可以通过该命令询问主节点是否下线,从而对是否客观下线做出判断

  • (2)增加/移除对主节点的监控
    sentinel monitor mymaster2 192.168.92.128 16379 2: 与部署哨兵节点时配置文件中的sentinel monitor功能完全一样,不再详述
    sentinel remove mymaster2: 取消当前哨兵节点对主节点mymaster2的监控

  • (3)强制故障转移
    sentinel failover mymaster: 该命令可以强制对mymaster执行故障转移,即便当前的主节点运行完好;例如,如果当前主节点所在机器即将报废,便可以提前通过failover命令进行故障转移。

哨兵基本原理

关于哨兵的原理,关键是了解以下几个概念。

  • (1)定时任务:每个哨兵节点维护了3个定时任务。定时任务的功能分别如下:通过向主从节点发送info命令获取最新的主从结构;通过发布订阅功能获取其他哨兵节点的信息;通过向其他节点发送ping命令进行心跳检测,判断是否下线。
  • (2)主观下线:在心跳检测的定时任务中,如果其他节点超过一定时间没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观地”判断下线;与主观下线相对应的是客观下线。
  • (3)客观下线:哨兵节点在对主节点进行主观下线后,会通过sentinel is-master-down-by-addr命令询问其他哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到一定数值,则对该主节点进行客观下线。
    需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。
  • (4)选举领导者哨兵节点:当主节点被判断客观下线以后,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。
    监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者。选举的具体过程这里不做详细描述,一般来说,哨兵选择的过程很快,谁先完成客观下线,一般就能成为领导者。
  • (5)故障转移:选举出的领导者哨兵,开始进行故障转移操作,该操作大体可以分为3个步骤:

在从节点中选择新的主节点:选择的原则是,首先过滤掉不健康的从节点;然后选择优先级最高的从节点(由slave-priority指定);如果优先级无法区分,则选择复制偏移量最大的从节点;如果仍无法区分,则选择runid最小的从节点。
更新主从状态:通过slaveof no one命令,让选出来的从节点成为主节点;并通过slaveof命令让其他节点成为其从节点。
将已经下线的主节点(即6379)设置为新的主节点的从节点,当6379重新上线后,它会成为新的主节点的从节点。

总结
  • (1)配置提供者:客户端可以通过哨兵节点+masterName获取主节点信息,在这里哨兵起到的作用就是配置提供者。
    需要注意的是,哨兵只是配置提供者,而不是代理。二者的区别在于:如果是配置提供者,客户端在通过哨兵获得主节点信息后,会直接建立到主节点的连接,后续的请求(如set/get)会直接发向主节点;如果是代理,客户端的每一次请求都会发向哨兵,哨兵再通过主节点处理请求。
    举一个例子可以很好的理解哨兵的作用是配置提供者,而不是代理。在前面部署的哨兵系统中,将哨兵节点的配置文件进行如下修改:
sentinel monitor mymaster 192.168.92.128 6379 2
改为
sentinel monitor mymaster 127.0.0.1 6379 2

然后,将前述客户端代码在局域网的另外一台机器上运行,会发现客户端无法连接主节点;这是因为哨兵作为配置提供者,客户端通过它查询到主节点的地址为127.0.0.1:6379,客户端会向127.0.0.1:6379建立redis连接,自然无法连接。如果哨兵是代理,这个问题就不会出现了。

  • (2)通知:哨兵节点在故障转移完成后,会将新的主节点信息发送给客户端,以便客户端及时切换主节点。

相关文章

Redis6.0.6_01_Redis安装教程
Redis6.0.6_02_Redis 入门基础
Redis6.0.6_03_Redis 实用
Redis6.0.6_04_Redis 主从复制与哨兵模式
Redis6.0.6_05_Redis管道和Lua脚本
Redis6.0.6_06_Redis 集群
Redis6.0.6_07_Redis 开发须知

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值