Redis主从复制集群的实现
主从复制的特点
-
一个master可以有多个slave
-
一个slave只能有一个master
-
数据流向是从master到slave单向的
1.主从复制的实现
Redis SLave也要开启持久化并设置和master同样的连接密码,因为后期slave会有提升为master可能,slave端切换master同步后丢失之前的所有数据,而通过持久化可以恢复数据
一旦某个slave成为一个master的slave,redis slave服务会清空当前redis服务器上的所有数据并将master的数据导入到自己的内存,但是如果只是断开同步关系后,则不会删除当前已经同步过的数据
当配置redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的主节点redis服务器应该避免自动启动
1.1启动主从同步
默认redis状态为master,需要转换为slave角色并指向master服务器的IP+PORT+Password在从节点执行REPLICAOF MASTER_IP PORT指令可以启动主从同步复制功能,早起版本使用SLAVEOF指令
127.0.0.1:6379> REPLICAOF MASTER_IP PORT
127.0.0.1:6379> CONFIG SET masterauth <masterpass>
环境准备
三台机器:
10.0.0.58 Redis-6.2.4 master
10.0.0.17 Redis-6.2.4 slave 1
10.0.0.27 Redis-6.2.4 slave 2
1.2master
[root@centos8 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:e04b37408faec364d9bb88963c63d76ea2735204
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 name hkping
OK
127.0.0.1:6379> get name
"hkping"
127.0.0.1:6379> dbsize
(integer) 10000105
1.3slave1
[root@centos7 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
#查看当前角色默认为master
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:e258e8539458974e642b25004c8797c37e9c26ff
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
#在slave1上设置master的IP和端口
127.0.0.1:6379> replicaof 10.0.0.58 6379
OK
#在slave1上设置master的密码
127.0.0.1:6379> config set masterauth 123456
OK
127.0.0.1:6379> info replication
# Replication
role:slave #角色变为了slave
master_host:10.0.0.58 #指向了master的ip
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:112
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:22fd1acb9c4bb39ab3e914d71742f7e8491b9c11
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:112
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:112
#在slave1上查看已经同步成功
127.0.0.1:6379> get name
"hkping"
127.0.0.1:6379> dbsize
(integer) 10000105
#永久修改需要改slave1配置文件
[root@centos7 ~]#vim /apps/redis/etc/redis.conf
# replicaof <masterip> <masterport>
replicaof 10.0.0.7 6379 #指定master的IP和端口号
# masterauth <master-password>
masterauth 123456 #指定master的密码
#重启redis服务
[root@centos7 ~]#systemctl restart redis
#再次登录redis查看状态
[root@centos7 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:2685c2aba949056d3ff4aae88426a4356621da2e
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
#查看slave1日志
[root@centos7 ~]# tail -f /apps/redis/log/redis-6379.log
5817:S 25 May 2022 11:20:40.301 * DB loaded from disk: 5.604 seconds
5817:S 25 May 2022 11:20:40.301 * 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.
5817:S 25 May 2022 11:20:40.301 * Ready to accept connections
5817:S 25 May 2022 11:20:40.703 * Connecting to MASTER 10.0.0.58:6379
5817:S 25 May 2022 11:20:40.704 * MASTER <-> REPLICA sync started
5817:S 25 May 2022 11:20:40.705 * Non blocking connect for SYNC fired the event.
5817:S 25 May 2022 11:20:40.707 * Master replied to PING, replication can continue...
5817:S 25 May 2022 11:20:40.708 * Trying a partial resynchronization (request 22fd1acb9c4bb39ab3e914d71742f7e8491b9c11:1).
5817:S 25 May 2022 11:20:40.710 * Successful partial resynchronization with master.
5817:S 25 May 2022 11:20:40.710 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
#slave1状态为只读
127.0.0.1:6379> set key1 abc
(error) READONLY You can't write against a read only replica.
#取消主从复制,在slave上执行replicaof no one指令,可以取消主从复制
#取消主从复制后,会断开和master的连接不再主从复制,但不会清除slave1上的已有数据
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:2685c2aba949056d3ff4aae88426a4356621da2e
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> get name
"hkping"
127.0.0.1:6379> dbsize
(integer) 10000105
1.4slave2
[root@centos7 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
#查看当前角色默认为master
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:e258e8539458974e642b25004c8797c37e9c26ff
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
#在slave2上设置master的IP和端口
127.0.0.1:6379> replicaof 10.0.0.58 6379
OK
#在slave2上设置master的密码
127.0.0.1:6379> config set masterauth 123456
OK
127.0.0.1:6379> info replication
# Replication
role:slave #角色变为了slave
master_host:10.0.0.58 #指向了master的ip
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:112
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:22fd1acb9c4bb39ab3e914d71742f7e8491b9c11
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:112
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:112
#在slave1上查看已经同步成功
127.0.0.1:6379> get name
"hkping"
127.0.0.1:6379> dbsize
(integer) 10000105
#永久修改需要改slave2配置文件
[root@centos7 ~]#vim /apps/redis/etc/redis.conf
# replicaof <masterip> <masterport>
replicaof 10.0.0.58 6379 #指定master的IP和端口号
# masterauth <master-password>
masterauth 123456 #指定master的密码
#重启redis服务
[root@centos7 ~]#systemctl restart redis
#再次登录redis查看状态
[root@centos7 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:2685c2aba949056d3ff4aae88426a4356621da2e
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
#查看slave2日志
[root@centos7 ~]# tail -f /apps/redis/log/redis-6379.log
5817:S 25 May 2022 11:20:40.301 * DB loaded from disk: 5.604 seconds
5817:S 25 May 2022 11:20:40.301 * 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.
5817:S 25 May 2022 11:20:40.301 * Ready to accept connections
5817:S 25 May 2022 11:20:40.703 * Connecting to MASTER 10.0.0.58:6379
5817:S 25 May 2022 11:20:40.704 * MASTER <-> REPLICA sync started
5817:S 25 May 2022 11:20:40.705 * Non blocking connect for SYNC fired the event.
5817:S 25 May 2022 11:20:40.707 * Master replied to PING, replication can continue...
5817:S 25 May 2022 11:20:40.708 * Trying a partial resynchronization (request 22fd1acb9c4bb39ab3e914d71742f7e8491b9c11:1).
5817:S 25 May 2022 11:20:40.710 * Successful partial resynchronization with master.
5817:S 25 May 2022 11:20:40.710 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
#slave2状态为只读
127.0.0.1:6379> set key2 abc
(error) READONLY You can't write against a read only replica.
1.5主从复故障恢复实现
master故障后,只能手动提升一个slave为新的master,不支持自动切换
之后将其它的slave节点重新指定为新的master为master节点
master的切换会导致master_replid发生变化,slave之前的master_replid就和当前master不一致,从而会引发所有slave的全量同步
假设现在当节点10.0.0.58故障了,手工提升10.0.0.17为新的master节点
1.51master
#手工关闭master节点制造故障
[root@centos8 ~]# systemctl stop redis
#此时slave1节点会
[root@centos7 ~]# tail -f /apps/redis/log/redis-6379.log
5855:S 25 May 2022 11:42:48.258 # Error condition on socket for SYNC: Connection refused
5855:S 25 May 2022 11:42:49.262 * Connecting to MASTER 10.0.0.58:6379
5855:S 25 May 2022 11:42:49.263 * MASTER <-> REPLICA sync started
5855:S 25 May 2022 11:42:49.264 # Error condition on socket for SYNC: Connection refused
5855:S 25 May 2022 11:42:50.267 * Connecting to MASTER 10.0.0.58:6379
1.52slave1
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.58
master_port:6379
master_link_status:down #此时down,无法连接到master
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:2534
master_link_down_since_seconds:222
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:22fd1acb9c4bb39ab3e914d71742f7e8491b9c11
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2534
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2534
#停止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:897295db2365224c35cb321b1454db47ef3eb785
master_replid2:22fd1acb9c4bb39ab3e914d71742f7e8491b9c11
master_repl_offset:2534
second_repl_offset:2535
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2534
#测试能否写入数据
127.0.0.1:6379> set age 35
OK
127.0.0.1:6379> get age
"35"
127.0.0.1:6379> dbsize
(integer) 10000106