乐趣区

关于redis:Redis的复制基础篇系列四

Redis 的主从复制篇来啦,本篇咱们来具体理解一下 Redis 的复制性能。

前言

在分布式系统中为了解决单点问题,通常会把数据复制多个正本部署到其余机器,满足故障复原和负载平衡等需要。Redis 也是如此,它为咱们提供了 复制 性能,实现了雷同数据的多个 Redis 正本。

Redis 复制概述

Redis 复制是主机数据更新后依据配置和策略,主动会以 异步复制 的形式,同步数据到备机的机制;复制过程中并不会阻塞复制波及的 Redis 节点,他们都能持续解决其余命令的申请。其实复制实质上沿用了 RDB 长久化的流程,在主节点收到命令后执行 bgsave 生成 RDB 文件,而后将 RDB 文件送给另一个 Redis 节点应用。

参加复制的 Redis 实例划分为主节点(master)和从节点(slave)。默认状况下,Redis 都是主节点。每个从节点只能有一个主节点,而主节点能够同时具备多个从节点。复制的数据流是单向的,只能由主节点复制到从节点。

因为复制波及到了主从节点的概念,所以也能够称为 主从复制,然而,主从复制的概念和主从集群还是有些差异的,咱们下一篇集群中就会讲到主从集群。

Redis 复制的用处

(1)读写拆散:主节点提供写服务,从节点提供读服务;进步 Redis 服务器的并发量。
(2)容灾复原:当主节点产生故障无奈服务,能够由从节点持续提供服务,实现故障的疾速复原。
(3)数据冗余:主从复制实现了数据的热备份,是长久化之外的一种数据冗余形式。
(4)高可用的基石:主从复制还是哨兵和主从集群可能施行的根底,因而说主从复制是 Redis 高可用的根底。

Redis 主从复制操作

开启主从复制,个别有以下三种形式:

(1)配置文件中配置:slaveof masterip masterport在该配置文件中退出这个,指定成为谁的从机。
(2)Redis 服务启动时配置:redis-server redis.conf --slaveof masterip masterport;在服务启动的时候指定成为谁的从机。
(3)Redis 服务启动后通过客户端配置:slaveof masterip masterport:输出该命令后,本机成为从机,本机本来的数据也会不存在,跟主机的数据保持一致。

敞开主从复制:
slaveof no one:使本机成为主数据库,也就完结了与其余数据库的同步。

Redis 主从复制实现过程

Redis 主从复制过程大抵分为三个步骤:

(1)连贯建设阶段:主从节点之间建设连贯,为数据同步做好筹备。
(2)数据同步阶段:是主从复制最外围的阶段,依据主从节点以后状态的不同,能够分为全量复制和局部复制。
(3)命令流传阶段:在这个阶段主节点将本人执行的写命令发送给从节点,从节点接管命令并执行,从而保障主从节点数据的一致性。

在本次例子中我应用了第三种形式创立主从复制,也就是连贯客户端后输出 slaveof masterip masterport 命令去复制,输出完这个命令后,Redis 的日志如下,外面记录了在这之后具体产生了什么事件:

27962:S 23 Apr 12:09:11.774 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
#保留主节点的信息
27962:S 23 Apr 12:09:11.776 * SLAVE OF 127.0.0.1:26379 enabled (user request from 'id=4 addr=127.0.0.1:26461 fd=7 name= age=43 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=slaveof')
#建设 socket 连贯
27962:S 23 Apr 12:09:12.596 * Connecting to MASTER 127.0.0.1:26379
27962:S 23 Apr 12:09:12.598 * MASTER <-> SLAVE sync started
#通过 ping 命令检测 socket 连贯是否可用
27962:S 23 Apr 12:09:12.598 * Non blocking connect for SYNC fired the event.
27962:S 23 Apr 12:09:12.598 * Master replied to PING, replication can continue...
27962:S 23 Apr 12:09:12.599 * Trying a partial resynchronization (request 21fa80655747f5e0448ae8449ebf7c61664304cb:1).
27962:S 23 Apr 12:09:12.601 * Full resync from master: cc4cce78d7d21fe6d93ce00825db1274c8b256f1:4606
27962:S 23 Apr 12:09:12.601 * Discarding previously cached master state.
#从机接管到来自主机的 197 比特的数据
27962:S 23 Apr 12:09:12.731 * MASTER <-> SLAVE sync: receiving 197 bytes from master
#从节点革除旧数据
27962:S 23 Apr 12:09:12.731 * MASTER <-> SLAVE sync: Flushing old data
#从节点把 RDB 中的数据载入内存
27962:S 23 Apr 12:09:12.732 * MASTER <-> SLAVE sync: Loading DB in memory
27962:S 23 Apr 12:09:12.732 * MASTER <-> SLAVE sync: Finished with success

连贯建设阶段

依据下面的日志能够看到,连贯建设也分为几个步骤:
(1)保留主节点信息:

27962:S 23 Apr 12:09:11.776 * SLAVE OF 127.0.0.1:26379 enabled (user request from 'id=4 addr=127.0.0.1:26461 fd=7 name= age=43 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=slaveof')

(2)建设 socket 连贯:

27962:S 23 Apr 12:09:12.596 * Connecting to MASTER 127.0.0.1:26379
27962:S 23 Apr 12:09:12.598 * MASTER <-> SLAVE sync started

(3)通过 ping 检测连贯是否可用:

27962:S 23 Apr 12:09:12.598 * Non blocking connect for SYNC fired the event.
27962:S 23 Apr 12:09:12.598 * Master replied to PING, replication can continue...

如果还配置了身份验证的话,从节点还须要向主节点进行身份验证。

数据同步阶段

主从节点之间的连贯建设当前,便能够开始进行数据同步,该阶段能够了解为从节点数据的初始化。具体执行的形式是:从节点向主节点发送 psync 命令(Redis2.8 以前是 sync 命令),开始同步。

数据同步阶段是主从复制最外围的阶段,依据主从节点以后状态的不同,能够分为 全量复制 局部复制,上面会具体理解这两种复制形式以及 psync 命令的执行过程;在本例中,是首次复制的场景,属于全量复制。

须要留神的是,在数据同步阶段之前,从节点是主节点的客户端,主节点不是从节点的客户端;而到了这一阶段及当前,主从节点互为客户端。起因在于:在此之前,主节点只须要响应从节点的申请即可,不须要被动发申请,而在数据同步阶段和前面的命令流传阶段,主节点须要被动向从节点发送申请(如推送缓冲区中的写命令),能力实现复制。

实际上 psync 命令运行就须要上面这几个组件的反对:

(1)复制偏移量:

参加复制的主从节点都会保护本身复制偏移量。主节点(master)在解决完写入命令后,会把命令的字节长度做累加记录,统计信息在 info relication 中的 master_repl_offset 指标中:

127.0.0.1:26379> info Replication
# Replication
role:master
connected_slaves:1
# 从节点的偏移量
slave0:ip=127.0.0.1,port=16379,state=online,offset=7826,lag=1
master_replid:06229f3457d2630cbf179ae725c6148489245a95
master_replid2:0000000000000000000000000000000000000000
#主节点的偏移量
master_repl_offset:7826
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:7826

从节点(slave)每秒钟上报本身的复制偏移量给主节点,因而主节点也会保留从节点的复制偏移量,指标如下:

slave0:ip=127.0.0.1,port=16379,state=online,offset=7826,lag=1

从节点在接管到主节点发送的命令后,也会累加记录本身的偏移量。统计信息在从节点的 info relication 中的 slave_repl_offset 指标中:

127.0.0.1:16379> info Replication
# Replication
role:slave
slave_repl_offset:8120

(2)复制积压缓冲区

复制积压缓冲区是保留在主节点上的一个固定长度的队列,默认大小为 1MB,当主节点有连贯的从节点(slave)时被创立,这时主节点(master)响应写命令时,岂但会把命令发送给从节点,还会写入复制积压缓冲区。

因为缓冲区实质上是先进先出的定长队列,所以能实现保留最近已复制 数据的性能,用于局部复制和复制命令失落的数据补救。复制缓冲区相干统计信息保留在主节点的 info replication 中:

#1 代表开启复制缓冲区,当主节点有连贯的从节点(slave)时主动被创立
repl_backlog_active:1
#缓冲区最大长度
repl_backlog_size:1048576
#起始偏移量
repl_backlog_first_byte_offset:1
#已保留数据的无效长度
repl_backlog_histlen:8344

(3)主节点运行 ID

每个 Redis 节点启动后都会动态分配一个 40 位的十六进制字符串作为运行 ID。运行 ID 的次要作用是用来惟一辨认 Redis 节点,比方从节点保留主节点的运行 ID 辨认本人正在复制的是哪个主节点。如果只应用 ip+port 的形式辨认主节点,那么主节点重启变更了整体数据集(如替换 RDB/AOF 文件),从节点再基于偏移量复制数据将是不平安的,因而当运行 ID 变动后从节点将做全量复制。能够运行 info server 命令查看以后节点的运行 ID:

127.0.0.1:16379> info Server
# Server
#主节点运行 ID
run_id:b8eac4a5b10bdf8703ede30f7e2c8a9ef1e84a72

psync 命令的执行过程

从节点会应用 psync 命令实现全量复制和局部复制性能,命令格局:
psync {runId} {offset},参数含意如下:
runId:从节点所复制主节点的运行 id。
offset:以后从节点已复制的数据偏移量。

psync 命令执行流程:

(1)从节点(slave)发送 psync 命令给主节点,参数 runId 是以后从节点保留的主节点运行 ID,如果没有则默认值为,参数 offset 是以后从节点保留的复制偏移量,如果是第一次参加复制则默认值为 -1。
(2)主节点(master)依据 psync 参数和本身数据状况决定响应后果:

  • 如果回复 +FULLRESYNC {runId} {offset},那么从节点将触发全量复制流程。
  • 如果回复 +CONTINUE,从节点将触发局部复制流程。
  • 如果回复 +ERR,阐明主节点版本低于 Redis 2.8,无奈辨认 psync 命令,从节点将发送旧版的 sync 命令触发全量复制流程。

全量复制

全量复制个别用于 首次复制 场景,Redis 晚期反对的复制性能只有全量复制,它会把主节点全副数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。

在 Redis >= 2.8 版本后,触发全量复制的的命令是 psync,这里也次要介绍 psync全量复制的流程:

(1)从节点发送 psync 命令进行数据同步,因为是第一次进行复制,从节点没有复制偏移量和主节点的运行 ID,所以发送 psync-1。
(2)主节点依据 psync- 1 解析出以后为全量复制,回复 FULL RESYNC 响应。
(3)从节点接管主节点的响应数据保留运行 ID 和偏移量 offset,执行到以后步骤时从节点打印如下日志:

27962:S 23 Apr 12:09:12.599 * Trying a partial resynchronization (request 21fa80655747f5e0448ae8449ebf7c61664304cb:1).
27962:S 23 Apr 12:09:12.601 * Full resync from master: cc4cce78d7d21fe6d93ce00825db1274c8b256f1:4606

(4)主节点回复 FULL RESYNC 响应后开始执行 bgsave 保留 RDB 文件到本地,并应用一个缓冲区(称为复制缓冲区)记录从当初开始执行的所有写命令。
(5)主节点的 bgsave 实现后,发送 RDB 文件给从节点,从节点把接管的 RDB 文件保留在本地并间接作为从节点的数据文件,接管完 RDB 后从节点打印相干日志,能够在日志中查看主节点发送的数据量:

27962:S 23 Apr 12:09:12.731 * MASTER <-> SLAVE sync: receiving 197 bytes from master

(6)对于从节点开始接管 RDB 快照到接管实现期间,主节点依然响应读和写命令,因而主节点会把这期间写命令数据保留在复制客户端缓冲区内,当从节点加载完 RDB 文件后,主节点再把缓冲区内的数据发送给从节点,这样就保障主从之间数据一致性。
(7)从节点接管完主节点传送来的全副数据后会先清空本身旧数据,而后开始加载 RDB 文件,对于较大的 RDB 文件,这一步操作仍然比拟耗时。
(9)从节点胜利加载完 RDB 后,如果以后节点开启了 AOF 长久化性能,它会立即做 bgrewriteaof 操作,为了保障全量复制后 AOF 长久化文件立即可用。

理解齐全量复制的所有流程,大家会发现全量复制是一个十分耗时费劲的操作。它的工夫开销次要包含:

(1)主节点 bgsave 进行 RDB 长久化的工夫,该过程是十分耗费 CPU、内存(页表复制)、硬盘 IO 的。
(2)RDB 文件网络传输工夫,对主从节点的带宽都会带来很大的耗费。
(3)从节点清空数据、加载 RDB 的工夫。
(4)可能的 AOF 重写工夫。

例如咱们数据量在 6G 左右的主节点,从节点发动全量复制的总耗时在 2 分钟左右。因而当数据量达到肯定规模之后,因为全量复制过程中将 进行屡次长久化相干操作和网络数据传输,这期间会大量耗费主从节点所在 服务器的 CPU、内存和网络资源。

所以除了第一次复制时采纳全量复制在劫难逃之外,对于其余场景应该躲避全量复制的产生。正因为全量复制的老本 问题,Redis 实现了局部复制性能。

局部复制

局部复制次要是 Redis 针对全量复制的过高开销做出的一种优化措施,用于解决在主从复制中因网络闪断等起因造成的数据失落场景,应用 psync {runId} {offset}命令实现。

当从节点(slave)正在复制主节点(master)时,如果呈现网络闪断或者命令失落等异常情况时,从节点会向 主节点要求补发失落的命令数据,如果主节点的复制积压缓冲区内存在这部分数据则间接发送给从节点,这样就能够放弃主从节点复制的一致性。因为补发的数据远远小于全量数据,能够无效防止全量复制的过高开销。Redis 2.8 版本开始提供局部复制,因而当应用复制性能时,尽量采纳 2.8 以上版本的 Redis。

局部复制的流程:

(1)当主从节点之间网络呈现中断时,如果超过配置文件中配置的 repl-timeout 工夫,主节点会认为从节点故障并中断复制连贯。
(2)主从连贯中断期间主节点仍然响应命令,但因复制连贯中断命令无奈发送给从节点,不过主节点外部存在的复制积压缓冲区,仍然能够保留最近一段时间的写命令数据,默认最大缓存大小为 1MB。
(3)当主从节点网络复原后,从节点会再次连上主节点。

(4)当主从连贯复原后,因为从节点之前保留了本身已复制的偏移量和主节点的运行 ID。因而会把它们当作 psync 参数(下面曾经讲过 psync 命令参数)发送给主节点,要求进行局部复制操作。
(5)主节点接到 psync 命令后首先核查参数 runId 是否与本身统一,如果统一,阐明之前复制的是以后主节点;之后依据参数 offset 在本身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送 +CONTINUE 响应,示意能够进行局部复制。
(6)主节点依据偏移量把复制积压缓冲区里的数据发送给从节点,保障主从复制进入失常状态。

在理论流程中,局部复制传递的数据远远小于全量数据,所以开销很小。

命令流传阶段

在命令流传阶段,除了发送写命令,主从节点之间保护着长连贯并彼此发送心跳命令;
主节点向从节点发送 ping 命令,从节点回复主节点 replconf ack {offset}。心跳机制对于主从复制的超时判断、数据安全等有作用。

主从心跳判断机制:

(1)主从节点彼此都有心跳检测机制,各自模仿成对方的客户端进行通信,通过 client list 命令查看复制相干客户端信息,主节点的连贯状态为 flags=M,从节点连贯状态为 flags=S。
(2)主节点默认每隔 10 秒对从节点发送 ping 命令,判断从节点的存活性和连贯状态。可通过参数 repl-ping-slave-period 管制发送频率,单位是秒。
(3)从节点在主线程中每隔 1 秒发送 replconf ack {offset}命令,给主节点上报本身以后的复制偏移量。

replconf 命令还有其余作用,次要作用如下:

(1)实时监测主从节点网络状态。
(2)上报本身复制偏移量,查看复制数据是否失落,如果从节点数据失落,再从主节点的复制缓冲区中拉取失落数据。
(3)实现保障从节点的数量和提早性功能,通过 min-slaves-to-write、minslaves-max-lag 参数配置定义。

主节点能够依据 replconf 命令判断从节点超时工夫,体现在 info replication 统计中的从机信息的 lag 字段中,lag 示意与从节点最初一次通信提早的秒数,失常提早应该在 0 和 1 之间。如果超过 repl-timeout 配置的值(默认 60 秒),则断定从节点下线并断开复制客户端连贯。即便主节点断定从节点下线后,如果从节点从新复原,心跳检测会持续进行。

Redis 主从复制毛病

(1)Redis 不具备主动容错和复原性能,一旦主节点呈现故障,须要手动将一个从节点降职为主节点,同时须要批改利用方的主节点地址,还须要命令其余从节点去复制新的主节点,整个过程都须要 人工干预

(2)主节点的写能力受到单机的限度。

(3)主节点的存储能力受到单机的限度。

Redis 主从复制总结

接下来的是一些对于 Redis 复制的十分重要的事实(摘自官网):

  • Redis 应用异步复制,slave 和 master 之间异步地确认解决的数据量。
  • 一个 master 能够领有多个 slave。
  • slave 能够承受其余 slave 的连贯。除了多个 slave 能够连贯到同一个 master 之外,slave 之间也能够像层叠状的构造(cascading-like structure)连贯到其余 slave。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到齐全一样的复制流。
  • Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行首次同步或者是局部重同步时,能够持续解决查问申请。
  • 复制在 slave 侧大部分也是非阻塞的。当 slave 进行首次同步时,它能够应用旧数据集解决查问申请,假如你在 redis.conf 中配置了让 Redis 这样做的话。否则,你能够配置如果复制流断开,Redis slave 会返回一个 error 给客户端。然而,在首次同步之后,旧数据集必须被删除,同时加载新的数据集。slave 在这个短暂的工夫窗口内(如果数据集很大,会继续较长时间),会阻塞到来的连贯申请。自 Redis 4.0 开始,能够配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行,然而,加载新数据集的操作仍然须要在主线程中进行并且会阻塞 slave。
  • 复制既能够被用在可伸缩性,以便只读查问能够有多个 slave 进行(例如 O(N) 复杂度的慢操作能够被下放到 slave),或者仅用于数据安全。
  • 能够应用复制来防止 master 将全副数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以防止对磁盘进行长久化,而后连贯一个 slave,其配置为不定期保留或是启用 AOF。然而,这个设置必须小心解决,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。
退出移动版