Redis 主从复制

图片[1]-Redis 主从复制-李佳程的个人主页

1、Redis 主从复制架构

主从模式(master/slave),和MySQL的主从模式类似,可以实现Redis数据的跨主机的远程备份。

程序APP先连接到高可用性 LB 集群提供的虚拟IP,再由LB调度将用户的请求至后端Redis 服务器来真正提供服务。

图片[2]-Redis 主从复制-李佳程的个人主页
  • 一个master可以有多个slave
  • 一个slave只能有一个master
  • 数据流向是从master到slave单向的
  • master 可读可写
  • slave 只读

2、主从复制实现

当master出现故障后,可以会提升一个slave节点变成新的Mster,因此Redis Slave 需要设置和master相同的连接密码,此外当一个Slave提升为新的master 通过持久化实现数据的恢复。

图片[3]-Redis 主从复制-李佳程的个人主页

当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的主节点Redis服务应该要避免自动启动。

# 导致主从服务器数据全部丢失
1.假设节点A为主服务器,并且关闭了持久化。并且节点B和节点C从节点A复制数据
2.节点A崩溃,然后由自动拉起服务重启了节点A.由于节点A的持久化被关闭了,所以重启之后没有任何数据
3.节点B和节点C将从节点A复制数据,但是A的数据是空的,于是就把自身保存的数据副本删除。

在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动启动。

2.1、启用主从同步

Redis Server 默认为 master节点,如果要配置为从节点,需要指定master服务器的IP,端口及连接密码在从节点执行 REPLICAOF MASTER_IP PORT 指令可以启用主从同步复制功能,早期版本使用 SLAVEOF指令。

127.0.0.1:6379> REPLICAOF MASTER_IP PORT        #新版推荐使用
127.0.0.1:6379> SLAVEOF MasterIP Port           #旧版使用,将被淘汰
127.0.0.1:6379> CONFIG SET masterauth <masterpass>
# 在mater上设置key1
[root@redis01 ~]# redis-cli
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:2a06311156932c13d70f12d2c50c1e6c5a1adc16
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> SET key1 v1-master
OK
127.0.0.1:6379> KEYS *
1) "key1"
127.0.0.1:6379> GET key1
"v1-master"
# 都在slave01上设置key1
[root@redis02 ~]# redis-cli
127.0.0.1:6379> info
NOAUTH Authentication required.
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> INFO replication
# Replication
role:master                                         # 查看当前角色默认为master
connected_slaves:0
master_failover_state:no-failover
master_replid:8648681f72e489c47d61431c8b3221117fadcaab
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> SET key1 v1-slave01
OK
127.0.0.1:6379> KEYS *
1) "key1"
127.0.0.1:6379> GET key1
"v1-slave01"
# 都在slave02上设置key1
[root@redis03 ~]# redis-cli
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> SET key1 v1-slave02
OK
127.0.0.1:6379> KEYS *
1) "key1"
127.0.0.1:6379> GET key1
"v1-slave02"
127.0.0.1:6379> INFO replication
# Replication
role:master                                         # 查看当前角色默认为master
connected_slaves:0
master_failover_state:no-failover
master_replid:0069ca9763396f9a0c8d2c8e2e9ff65c8f1e9fde
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# 在slave01上设置master参数
# 在slave01上设置master的IP和端口,4.0版之前的指令为slaveof
127.0.0.1:6379> REPLICAOF 192.168.1.41 6379
OK

# 在slave01上设置master的密码,才可以同步
127.0.0.1:6379> CONFIG SET masterauth 123456
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave                                          # 角色变为slave

master_host:192.168.1.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

# 在slave02上设置master参数
127.0.0.1:6379> REPLICAOF 192.168.1.41 6379
OK
127.0.0.1:6379> CONFIG SET masterauth 123456
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.1.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:56
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57
repl_backlog_histlen:0
# 在slave上查看已经同步成功
127.0.0.1:6379> GET key1
"v1-master"

# 在master上可以看到所有slave信息
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.42,port=6379,state=online,offset=294,lag=1
slave1:ip=192.168.1.43,port=6379,state=online,offset=294,lag=0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:294
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:294
# 删除主从同步
# 在从节点执行 REPLICAOF NO ONE 指令可以取消主从复制
# 取消复制,在slave上执行REPLICAOF NO ONE,会断开和master的连接不再主从复制,但不会清  除slave
上已有的数据
127.0.0.1:6379> REPLICAOF no one

2.2、验证同步

# 在 master 上观察日志
[root@redis01 ~]# tail /apps/redis/log/redis-6379.log
968:M 27 Nov 2022 10:48:59.520 * Background saving terminated with success
968:M 27 Nov 2022 10:48:59.520 * Synchronization with replica 192.168.1.42:6379 succeeded
968:M 27 Nov 2022 10:49:35.063 * Replica 192.168.1.43:6379 asks for synchronization
968:M 27 Nov 2022 10:49:35.063 * Full resync requested by replica 192.168.1.43:6379
968:M 27 Nov 2022 10:49:35.063 * Starting BGSAVE for SYNC with target: disk
968:M 27 Nov 2022 10:49:35.063 * Background saving started by pid 1551
1551:C 27 Nov 2022 10:49:35.064 * DB saved on disk
1551:C 27 Nov 2022 10:49:35.064 * RDB: 0 MB of memory used by copy-on-write
968:M 27 Nov 2022 10:49:35.067 * Background saving terminated with success
968:M 27 Nov 2022 10:49:35.067 * Synchronization with replica 192.168.1.43:6379 succeeded
# 在 slave 节点观察日志
[root@redis02 ~]# tail /apps/redis/log/redis-6379.log
967:S 27 Nov 2022 10:48:59.493 * Master replied to PING, replication can continue...
967:S 27 Nov 2022 10:48:59.495 * Partial resynchronization not possible (no cached master)
967:S 27 Nov 2022 10:48:59.497 * Full resync from master: c9a209456539e08104670ef17bbe37520b35148c:0
967:S 27 Nov 2022 10:48:59.520 * MASTER <-> REPLICA sync: receiving 196 bytes from master to disk
967:S 27 Nov 2022 10:48:59.520 * MASTER <-> REPLICA sync: Flushing old data
967:S 27 Nov 2022 10:48:59.520 * MASTER <-> REPLICA sync: Loading DB in memory
967:S 27 Nov 2022 10:48:59.520 * Loading RDB produced by version 6.2.5
967:S 27 Nov 2022 10:48:59.520 * RDB age 0 seconds
967:S 27 Nov 2022 10:48:59.520 * RDB memory usage when created 1.91 Mb
967:S 27 Nov 2022 10:48:59.520 * MASTER <-> REPLICA sync: Finished with success

2.3、通过修改两个slave节点配置文件启用主从

[root@redis02 ~]# vim /apps/redis/etc/redis.conf
 477 # replicaof <masterip> <masterport>
 478 replicaof 192.168.1.41 6379

 485 # masterauth <master-password>
 486 masterauth 123456

[root@redis02 ~]# systemctl restart redis.service

2.4、master和slave查看状态

# 在master上查看状态
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.42,port=6379,state=online,offset=1064,lag=0
slave1:ip=192.168.1.43,port=6379,state=online,offset=1064,lag=0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1064
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1064

# 在slave上查看状态
127.0.0.1:6379> get key1
"v1-master"
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.1.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:1218
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1218
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1218

# 停止master的redis服务,在slave上可以观察到以下现象
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.1.41
master_port:6379
master_link_status:down                      # 显示down,表示无法连接master

master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1330
master_link_down_since_seconds:4
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:c9a209456539e08104670ef17bbe37520b35148c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1330
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1330

2.5、Slave 日志

[root@redis02 ~]# tail /apps/redis/log/redis-6379.log
1600:S 27 Nov 2022 11:06:42.828 # Error condition on socket for SYNC: Connection refused
1600:S 27 Nov 2022 11:06:43.836 * Connecting to MASTER 192.168.1.41:6379
1600:S 27 Nov 2022 11:06:43.836 * MASTER <-> REPLICA sync started
1600:S 27 Nov 2022 11:06:43.836 # Error condition on socket for SYNC: Connection refused
1600:S 27 Nov 2022 11:06:44.843 * Connecting to MASTER 192.168.1.41:6379
1600:S 27 Nov 2022 11:06:44.843 * MASTER <-> REPLICA sync started
1600:S 27 Nov 2022 11:06:44.843 # Error condition on socket for SYNC: Connection refused
1600:S 27 Nov 2022 11:06:45.850 * Connecting to MASTER 192.168.1.41:6379
1600:S 27 Nov 2022 11:06:45.850 * MASTER <-> REPLICA sync started
1600:S 27 Nov 2022 11:06:45.850 # Error condition on socket for SYNC: Connection refused

2.6、Master日志

[root@redis01 ~]# tail /apps/redis/log/redis-6379.log
968:M 27 Nov 2022 10:49:35.067 * Synchronization with replica 192.168.1.43:6379 succeeded
968:M 27 Nov 2022 11:01:23.647 # Connection with replica 192.168.1.42:6379 lost.
968:M 27 Nov 2022 11:01:31.944 # Connection with replica 192.168.1.43:6379 lost.
968:M 27 Nov 2022 11:02:05.174 * Replica 192.168.1.42:6379 asks for synchronization
968:M 27 Nov 2022 11:02:05.174 * Partial resynchronization request from 192.168.1.42:6379 accepted. Sending 1050 bytes of backlog starting from offset 1.
968:M 27 Nov 2022 11:02:14.594 * Replica 192.168.1.43:6379 asks for synchronization
968:M 27 Nov 2022 11:02:14.594 * Partial resynchronization request from 192.168.1.43:6379 accepted. Sending 1008 bytes of backlog starting from offset 57.
968:M 27 Nov 2022 11:04:53.873 # Connection with replica 192.168.1.42:6379 lost.
968:M 27 Nov 2022 11:05:06.084 * Replica 192.168.1.42:6379 asks for synchronization
968:M 27 Nov 2022 11:05:06.084 * Partial resynchronization request from 192.168.1.42:6379 accepted. Sending 1302 bytes of backlog starting from offset 1.

2.7、slave 只读状态

# 验证Slave节点为只读状态,不支持写入
127.0.0.1:6379> SET key2 123
(error) READONLY You can't write against a read only replica.

3、主从复制故障恢复

3.1、slave 节点故障和恢复

当 slave 节点故障时,将Redis Client指向另一个 slave 节点即可,并及时修复故障从节点

图片[4]-Redis 主从复制-李佳程的个人主页

3.2、master 节点故障和恢复

当 master 节点故障时,需要提升slave为新的master

图片[5]-Redis 主从复制-李佳程的个人主页
  • master故障后,只能手动提升一个slave为新master,不支持自动切换。
  • 之后将其它的slave节点重新指定新的master为master节点
  • Master的切换会导致master_replid发生变化,slave之前的master_replid就和当前master不一致从而会引发所有 slave的全量同步。

3.3、主从复制故障恢复实现

假设当前主节点192.168.1.41故障,提升192.168.1.42为新的master

# 查看当前192.168.1.42节点的状态为slave,master指向192.168.1.41
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.1.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_repl_offset:532
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:42f1202f8605123ac94247f6187265d787ef820f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:532
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:532
# 将当前 slave 节点提升为 master 角色
127.0.0.1:6379> REPLICAOF no one
OK
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:359112ec399ba53a80ed6803dcf0c7bb7ffef041
master_replid2:42f1202f8605123ac94247f6187265d787ef820f
master_repl_offset:588
second_repl_offset:589
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:588
# 测试新master能否写入数据
127.0.0.1:6379> set key2 123456
OK
# 修改所有slave 指向新的master节点
127.0.0.1:6379> SLAVEOF 192.168.1.42 6379
OK

127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.1.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:674
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:359112ec399ba53a80ed6803dcf0c7bb7ffef041
master_replid2:42f1202f8605123ac94247f6187265d787ef820f
master_repl_offset:674
second_repl_offset:1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:674
127.0.0.1:6379> KEYS *
1) "key2"
2) "key1"
127.0.0.1:6379> get key2
"123456"

# 查看日志
[root@redis03 ~]# tail /apps/redis/log/redis-6379.log
1600:S 27 Nov 2022 11:17:12.514 * Before turning into a replica, using my own master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
1600:S 27 Nov 2022 11:17:12.514 * Ready to accept connections
1600:S 27 Nov 2022 11:17:12.516 * Connecting to MASTER 192.168.1.42:6379
1600:S 27 Nov 2022 11:17:12.516 * MASTER <-> REPLICA sync started
1600:S 27 Nov 2022 11:17:12.517 * Non blocking connect for SYNC fired the event.
1600:S 27 Nov 2022 11:17:12.517 * Master replied to PING, replication can continue...
1600:S 27 Nov 2022 11:17:12.518 * Trying a partial resynchronization (request 42f1202f8605123ac94247f6187265d787ef820f:1).
1600:S 27 Nov 2022 11:17:12.518 * Successful partial resynchronization with master.
1600:S 27 Nov 2022 11:17:12.518 # Master replication ID changed to 359112ec399ba53a80ed6803dcf0c7bb7ffef041
1600:S 27 Nov 2022 11:17:12.518 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
# 在新master节点上查看状态
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.43,port=6379,state=online,offset=828,lag=0
master_failover_state:no-failover
master_replid:359112ec399ba53a80ed6803dcf0c7bb7ffef041
master_replid2:42f1202f8605123ac94247f6187265d787ef820f
master_repl_offset:828
second_repl_offset:589
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:828

4、实现 Redis 的级联复制

实现基于Slave节点的Slave

图片[6]-Redis 主从复制-李佳程的个人主页

master和slave1节点无需修改,只需要修改slave2及slave3指向slave1做为mater即可

# master上查看状态
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.42,port=6379,state=online,offset=756,lag=0
master_failover_state:no-failover
master_replid:42f1202f8605123ac94247f6187265d787ef820f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:756
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:756

# slave1上查看状态
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.1.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3        # 最近一次与master通信已经过去多少秒。

master_sync_in_progress:0           # 是否正在与master通信。
slave_repl_offset:742               # 当前同步的偏移量
slave_priority:100                  # slave优先级,master故障后值越小越优先同步。
slave_read_only:1
replica_announced:1
connected_slaves:1
slave0:ip=192.168.1.43,port=6379,state=online,offset=742,lag=0 # slave的slave节点
master_failover_state:no-failover
master_replid:42f1202f8605123ac94247f6187265d787ef820f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:742
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:742

# slave2上查看状态
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.1.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_repl_offset:756
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:42f1202f8605123ac94247f6187265d787ef820f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:756
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:701
repl_backlog_histlen:56

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享