什么是主从复制
是为了解决单机状态下服务器宕机带来的风险.
主从复制可以理解为是slave节点通过不间断复制主节点的数据来实现灾难备份的手段之一,它和RDB等持久化的区别在于主从复制是运行时起作用,RDB或AOF则需要重启写入来恢复数据.
实现
比如我的6380节点希望以slave的角色作为6379节点的从属,那么可以执行
redis-cli -p 6380 slaveof 127.0.0.1 6379
也可以通过修改配置文件的方式
slaveof ip port
# 从节点只读,默认yes
slave-read-only yes
# 如果有密码,需要配置密码
masterauth XXXXXX
取消
如果想撤销自身的从节点属性,可以使用
redis-cli -p 6380 slaveof no one
此时,原master
节点新增数据不会被复制,已经复制过来的数据不会被删除.
状态
一般状态查看均涉及info
命令.这里列举主机(server
)和分片(replication
)两种信息.
-
主机
redis-cli -p 6380 info server
得到如下输出
# Server redis_version:5.0.7 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:7e387a3dd196c136 redis_mode:standalone os:Linux 4.15.0-30deepin-generic x86_64 arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:6.3.0 process_id:14424 run_id:b702eade18c5e3cf283f6116e572761af352ef17 tcp_port:6380 uptime_in_seconds:1420 uptime_in_days:0 hz:10 configured_hz:10 lru_clock:1916305 executable:/usr/local/download/redis-server config_file:/etc/redis/redis-6380.conf
-
分片
redis-cli info replication
得到如下输出
# Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:2002 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:57cc3f56c87301d65b85dac88c8564c249af7132 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:2002 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:2002
可以看到自身角色以及其他关联实例信息.
复制方式
主从复制,很关键的一点就是复制,那么,什么时候全量复制,什么时候增量复制呢?
全量
在刚设置master
节点后,会进行全量复制。原理是,首先将master
本身的RDB
文件同步给slave
,而在同步期间,master
写入的命令也会记录下来(master
内部有一个复制缓冲区,会记录同步时master
新增的写入),当slave
将RDB
加载完后,会通过偏移量(redis-cli info replication | grep offset
)的对比将这期间master
写入的值同步给slave
。
原理
slave
内部首先会发送一个psync
的命令给master
这个命令第一个参数是runId
,第二个参数是偏移量
,而由于是第一次复制,slave不知道master
的runId
,也不知道自己偏移量1,这时候会传一个问号和-1
,告诉master
节点是第一次同步。- 当
master
接受到psync ? -1
时,就知道slave是要全量复制,就会将自己的runID
和offset
告知slave
slave
会将master
信息保存master
这时会做一个RDB
的生成(bgsave
)- 将
RDB
发送给slave
- 将复制缓冲区记录的操作也发送给
slave
slave
清空自己的所有老数据slave
这时就会加载RDB文件以及复制缓冲区数据,完成同步
开销
bgsave
的开销,每次bgsave
需要fork
子进程,对内存和CPU的开销很大RDB
文件网络传输的时间(网络带宽)- 从节点清空数据的时间
- 从节点加载
RDB
的时间 - 可能的
AOF
重写时间(如果我们的从节点开启了AOF
,则加载完RDB
后会对AOF
进行一个重写,保证AOF
是最新的)
增量
为什么要部分复制? 在redis2.8
版本之前,如果master
和slave
之间的网络发生了抖动连接断开,就会导致slave
完全不知道master
的动作,同步就会出问题,而为了保证数据一致,等网络恢复后进行一次全量复制。而全量复制的开销是很大的,redis2.8
版本就提个了一个部分复制的功能。
部分复制的实现原理:
当master
和slave
断开连接时,,master
会将期间所做的操作记录到复制缓存区当中(可以看成是一个队列,其大小默认1M
)。待slave重连后,slave
会向master
发送psync
命令并传入offset
和runId
(注:run id
并不是pid
,slave
把它保存在内存中,重启就消失),这时候,如果master
发现slave
传输的偏移量的值,在缓存区队列范围中,就会将从offset开始到队列结束的数据传给slave
,从而达到同步,降低了使用全量复制的开销。
本节说明
本节几乎全量复制了详解redis的全量复制与部分复制,著作权归原作者吴正宇所有.
运维建议
规避全量复制
- 第一次全量复制不可避免,但其他情况可以避免:
- 小主节点: 将
maxmemory
设置低一些 - 低峰期: 比如夜间
- 小主节点: 将
- 节点运行ID不匹配
- 主节点重启(run_id变化)
- 故障转移,例如哨兵或集群
- 复制积压缓冲区不足
- 网络中断,部分复制无法满足
- 增大复制缓冲区配置
rel_backlog_size
,网络"增强".
规避复制风暴
-
单主节点复制风暴
如果主节点重启,多个从节点会复制,可以将复制结构转换成下图模式
虽然可以解决master
重启复制风暴,但slave-1
挂掉仍然存在复制风暴问题.
-
单机器复制风暴
如下图:
解决: 主节点分散到多个主机
问题
-
如果
6380
,也就是准slave
节点,以前有数据,动态执行slaveof
命令后,源数据还存在吗?答: 不存在.
-
如果
slave
节点可写(slave-read-only
设置为no
),是否会同步到master
节点?不能!
-
redis进程重启后会发生全量复制还是部分复制?
答:
master
重启时,run id
会发生变化, 会发生全量复制,因为部分复制的条件之一run id
已经不能满足,slave
重启时会不会,这里存疑???
参考
redis-cli -p 6380 info replication
中的master_repl_offset
对应的值 ↩︎