1.
主从详解
1.1. 主从配置
参与复制的redis实例划分为主节点(master)和从节点(slave)。默认情况下,redis都是主节点。
每个从节点只能有一个主节点,二主节点可以同时具有多个从节点。复 制的数据流是单向的,只能有主节点复制到从节点
每个从节点只能有一个主节点,二主节点可以同时具有多个从节点。复 制的数据流是单向的,只能有主节点复制到从节点
redis对于主从复制有三种方式
1. 在配置文件中加入 slaveof {masterHost} {masterPort} 随redis启动生效
2. 在redis-server启动命令后加入 --slaveof {masterHost} {masterPort} 生效
3. 直接使用命令: slaveof {masterHost} {masterPort}
info replication
查看复制相关状态
根据上图分析大致可以分为
6
个过程:
1.
保存主节点
(master)
执行
slaveof
后从节点只保存主节点的地址信息便直接返回,这时建立复制流程还没有开始,在从节点
6350
执行
info replication
可以看到如下信息
:
master_host:192.160.1.50
master_port:6379
master_link_status:up
2.
从节点
(slave)
内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接
3.
发送
ping
命令
4.
权限验证
5.
同步数据集
6.
命令持续复制
1.4.
数据同步
1.
全量复制:
用于初次复制或其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作,当数据量较大时,会对主从节点和网络造
成很 大的开销
2.
部分复制:
用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果(条件允许
)
,主节点会补发丢失数据给从节点。 因为补
发的数据远远小于全量数据,可以有效避免全量复制的过高开销,需要注意的是,如果网络中断时间过长,造成主节点没有能够完整地保存中断期间执行
的写命令,则无法进行部分复制,仍使用全量复制
1.4.2.
复制偏移量
参与复制的主从节点都会维护自身复制偏移量。主节点(
master
)在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在
info relication
中的
master_repl_offset
指标中:
127.0.0.1:6379> info replication
#
Replication
role:master
...
master_repl_offset:6104
从节点(
slave
)每秒钟上报自身的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量,统计指标如下
127.0.0.1:6379> info replication
#
Replication
role:master
connected_slaves:1
slave0:ip=192.160.1.140,port=6379,state=online,offset=6104,lag=1
从节点在接收到主节点发送的命令后,也会累加记录自身的偏移量。统计信息在
info relication
中的
slave_repl_offset
中
1.4.3.
复
制积压缓冲区
复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为
1MB
,当主节点有连接的从节点(
slave
)时被创建,这时主节点(
master
)响应写命令
时,不但会把命令发送给从节点,还会写入复制积压缓冲区
在命令传播阶段,主节点除了将写命令发送给从节点,还会发送一份给复制积压缓冲区,作为写命令的备份;除了存储写命令,复制积压缓冲区中还存储了其中
的每个字节对应的复制偏移量
(offset)
。由于复制积压缓冲区定长且先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区
()
。
1.4.4.
主
节点运行
ID
每个
Redis
节点启动后都会动态分配一个
40
位的十六进制字符串作为运行
ID
。运行
ID
的主要作用是用来唯一识别
Redis
节点,比如从节点保存主节点的运行
ID
识别自
己正在复制的是哪个主节点。如果只使用
ip+port
的方式识别主节点,那么主节点重启变更了整体数据集
(
如替换
RDB/AOF
文件
)
,从节点再基于偏移量复制数据将是
不安全的,因此当运行
ID
变化后从节点将做全量复制。可以运行
info server
命令查看当前节点的运行
ID:
127.0.0.1:6379> info server
#
Server
redis_version:5.0.7
...
run_id:868a5d49a276620b9f79788a1c894f07bd872f56
需要注意的是
Redis
关闭再启动,运行的
id
会随之变化
>
redis-cli shutdown
>
redis-server redis.conf
1.4.5. Psync
命令
从节点使用
psync
命令完成部分复制和全量复制功能
psync runid offset
流程说明:
1.
从节点
(slave)
发送
psync
命令给主节点,参数
runid
是当前从节点保存的主节点运行
id
,如果没有则默认值为 ?
,
参数
offset
是当前从节点保存的复制偏移量,如
果是第一次参与复制则默认值为
-1
2.
主节点
(master)
根据
psync
参数和自身数据情况决定响应结果:
如果回复
+FULLRESYNC {runid} {offset},
那么从节点将厨房全量复制流程。
如果回复
+CONTINUE
,从节点将触发部分复制流程。
如果回复
+ERR
,说明主节点版本低于
Redis2.8
1.5.
全量复制流程
注意: 从节点在载入主节点的数据之前要先将从节点老数据清除
全量复制是
Redis
最早支持的复制方式,也是主从第一次建立复制时必须经历的阶段。触发全流量复制的命令是
sync
和
psync
流程说明
1.
发送
psync
命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行
id
,所以发送
psync ? -1
2.
主节点根据
psync ? -1
解析出当前为全量复制,回复
+FULLRESYNC
响应
(
主机会向从机发送
runid
和
offset
,因为
slave
并没有对应的
offset
,所以是全量复制
)
3.
从节点接收主节点的响应数据保存运行
ID
和偏移量
offset(
从机
slave
会保存 主机
master
的基本信息
save masterInfo)
4.
主节点收到全量复制的命令后,执行
bgsave
(异步执行),在后台生成
RDB
文件(快照),并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行 的所
有写命令
5.
主节点发送
RDB
文件给从节点,从节点把接收到的
RDB
文件保存在本地并直接作为从节点的数据文件,接收完
RDB
后从节点打印相关日志,可以在日志中查看
主节点发送的数据量
(
主机
send RDB
发送
RDB
文件给从机
)
MASTER <-> REPLICA sync: Flushing old data
注意!对于数据量较大的主节点,比如生成的
RDB
文件超过
6GB
以上时要格外小心。传输文件这一步操作非常耗时,速度取决于主从节点之间网络带宽,通过
细致分析
Full resync
和
MASTER <-> SLAVE
这两行日志的时间差,可以算出
RDB
文件从创建到传输完毕消耗的总时间。如果总时间超过
repl-timeout
所配置的值
(
默认
60
秒
)
,从节点将放弃接受
RDB
文件并清理已经下载的临时文件,导致全量复制失败
;
针对数据量较大的节点,建议调大
repl-timeout
参数防止出现全量同步
数据超时
;
例如对于千兆网卡的机器,网卡带宽理论峰值大约每秒传输
100MB,
在不考虑其他进程消耗带宽的情况下,
6GB
的
RDB
文件至少需要
60
秒传输时间,默认配置
下,极易出现主从数同步超时。
6.
对于从节点开始接收
RDB
快照到接收完成期间,主节点仍然响应读写命令,因此主节点会把这期间写命令数据保存在复制客户端缓冲区内,当从节点加载完
RDB
文件后,主节点再把缓冲区内的数据发送给从节点,保证主从之间数据致性。
(
发送缓冲区数据
)
7.
从节点接收顽主节点传送来的全部数据后会清空自身旧数据
(
刷新旧的数据,从节点在载入主节点的数据之前要先将老数据清除
)
8.
从节点清空数据后开始加载
RDB
文件,对于较大的
RDB
文件,这一步操作依然比较消耗时间,可以通过计算日志之间的实际差来判断加载
RDB
的总消耗时间
(
加
载
RDB
文件将数据库状态更新至主节点执行
bgsave
时的数据库状态和缓冲区数据的加载。
)
114:S 28 Apr 2020 18:57:33.537 * MASTER <-> REPLICA sync: Loading DB in memory
114:S 28 Apr 2020 18:57:33.537 * MASTER <-> REPLICA sync: Finished with success
9.
从节点成功加载完
RDB
后,如果当前节点开启了
AOF
持久化的功能,它会立刻做
bgrewriteeaof
的操作,为了保证全量复制后
AOF
持久化文件立刻可用。
通过分析全量复制的所有流程,全量制是一个非常耗时费力的操作。他的实际开销主要包括:
主节点
bgsave
时间
RDB
文件网络传输时间。
从节点清空数据时间
从节点加载
RDB
的时间
可能的
AOF
重写时间
1.6.
部分复制流程
部分复制是
Redis 2.8
以后出现的,之所以要加入部分复制,是因为全量复制会产生很多问题,比如像上面的时间开销大、无法隔离等问题,
Redis
希望能够在
master
出现抖动(相当于断开连接)的时候,可以有一些机制将复制的损失降低到最低
1.
当主从节点之间网络出现中断时,如果超过
repl-timeout
时间,主节点会认为从节点出问题了并断开复制链接
(
如果网络抖动(连接断开
connection lost
)
)
2.
主从连接中断期间主节点依然响应命令,但因复制链接中断命令无法发送给从节点不过主节点内部存在的复制积压缓存去,依然可以保存一段时间的写命令数
据,默认最大缓存
1MB(
主机
master
还是会写
replbackbuffer
(复制缓冲区)
)
3.
当主从节点网络恢复后,从节点会再次连上主节点。
(
从机
slave
会继续尝试连接主机
)
4.
当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行
id
。因此会把他们当作
psync
参数发送给主节点,要求进行部分复制操作。
(
从
机
slave
会把自己当前
runid
和偏移量传输给主机
master
,并且执行
pysnc
命令同步
)
5.
主节点接到
psync
命令后首先核对参数的
runid
,如果
master
发现你的偏移量是在缓冲区的范围内,根据参数
offset
在缓冲区查找复制内内,如果在偏移量之后
的数据存在缓存区中,则对从节点发送
continue
表示可以进行部分复制
6.
主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。
(
同步了
offset
的部分数据,所以部分复制的基础就是偏移量
offset)
1.7.
心跳
主节点在建立成功后会维护这长连接彼此发送心跳检测
1.
主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通信,通过
client list
命令查看复制相关客户端信息,主节点的连接状态为
flags=M,
从节点连接
状
flags=S
2.
主节点默认每隔
10
秒对从节点发送
ping
命令,判断从节点的存活性和连接状态。可通过参数
repl-ping-slave-period
控制发送频率。
3.
从节点在主线程中每隔
1
秒发送
replconf ack {offset}
命令,给主节点上报自身当前的复制偏移量。
1.8.
缓冲大小调节
由于缓冲区长度固定且有限,因此可以备份的写命令也有限,当主从节点
offset
的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。反过 来
说,为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小
(
通过配置
repl-backlog-size)
来设置; 例如 如果网络中断的平均时间是
60s
,而主节点平均每秒产生的写命令
(
特定协议格式
)所占的字数断线情况都可以使用部分复制。