redis主从复制
一、什么是redis主从复制
1、主从复制架构
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave)。
数据的复制是单向的,只能由主节点到从节点。
Redis Replication是一种 master-slave 模式的复制机制,这种机制使得 slave 节点可以成为与 master 节点完全相同的副本,可以采用一
主多从或者级联结构。架构如下:
- 一个master可以有多个slave
- 一个slave只能有一个master
- 数据流向是单向的,master到slave
2、redis为什么需要主从复制
使用redis主从复制的原因在于redis单台节点存在以下问题:
(1)、Redis虽然读写的速度都很快,单节点的Redis能够支撑QPS大概在5w左右,如果上千万的用户访问,Redis就承载不了,成为了高并发的瓶颈。
(2)、单节点的Redis不能保证高可用,当Redis因为某些原因意外宕机时,会导致缓存不可用
(3)、CPU的利用率上,单台Redis实例只能利用单个核心,这单个核心在面临海量数据的存取和管理工作时压力会非常大。
二、搭建主从复制
1、涉及主机
角色 | 主机名 | IP地址 |
---|---|---|
master | master | 192.168.112.40 |
slave | slave1 | 192.168.112.50 |
slave | slave2 | 192.168.112.60 |
2、编译安装redis
所有主机
2.1、获取软件安装包,安装编译环境
yum install -y make gcc tcl
wget https://download.redis.io/releases/redis-5.0.9.tar.gz
tar xf redis-5.0.9.tar.gz
2.2、编译安装
cd redis-5.0.9/src/
make
make PREFIX=/apps/redis install
2.3、配置变量
echo "PATH=/apps/redis/bin:$PATH" > /etc/profile.d/redis.sh
. /etc/profile.d/redis.sh
2.4、验证目录结构
tree /apps/redis/
2.5、准备目录及文件
mkdir /apps/redis/{etc,log,data,run}
cp ~/redis-5.0.9/redis.conf /apps/redis/etc/
3、前台启动redis
redis-server /apps/redis/etc/redis.conf
3.1、消除三个警告提示
不难发现,前台启动时会出现三个WARNING,默认情况, redis配置文件的参数和内核参数不匹配, 因此还需要修改配置参数, 否则启动时会有警告, 但是并不影响使用
echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
[root@master src]# sysctl -p
net.core.somaxconn = 1024
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
[root@master src]# sysctl -p
net.core.somaxconn = 1024
vm.overcommit_memory = 1
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
再次启动redis可以看到警告消除
redis-server /apps/redis/etc/redis.conf
4、使用systemctl管理redis
4.1、创建redis用户
useradd -r -s /sbin/nologin redis
chown -R redis.redis /apps/redis/
4.2、编辑redis服务启动文件
vim /lib/systemd/system/redis.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
4.3、验证redis启动
reids的默认启动端口是6379
systemctl daemon-reload
systemctl enable --now redis
ss -ntl
5、使用客户端连接redis
-
格式:
redis-cli -h IP/HOSTNAME -p PORT -a PASSWORD
-
连接实例:
redis-cli 127.0.0.1:6379> info 127.0.0.1:6379> exit
6、设置登陆密码、修改监听地址、数据目录、日志,PID文件路径
6.1、修改配置文件
sed -i -e "s/bind 127.0.0.1/bind 0.0.0.0/" -e "/# requirepass/a requirepass centos" -e "/^dir .*/c dir /apps/redis/data/" -e "/logfile .*/c logfile /apps/reids/log/redis_6379.log" -e "/^pidfile .*/c pidfile /apps/redis/run/redis_6379.pid" /apps/redis/etc/redis.conf
6.2、重启redis
systemctl restart redis
redis-cli
127.0.0.1:6379> info
NOAUTH Authentication required.
127.0.0.1:6379> auth centos
OK
7、创建命令软链接
ln -s /apps/redis/bin/ /usr/bin/
8、启用主从同步
- 默认redis 状态为master,需要转换为slave角色并指向master服务器的IP+PORT+Password
- REPLICAOF MASTER_IP PORT 指令可以启用主从同步复制功能,早期版本使用 SLAVEOF 指令
8.1、在master上设置key1
[root@master ~]# redis-cli -a centos
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_replid:f4efa528f4a3d63441a78ae714b3165a2c962fa4
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"
127.0.0.1:6379>
8.2、slave登录设置key1
slave1
[root@slave1 ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:53bb55466d846a521874f723a093 512a4ebcd55b
master_replid2:000000000000000000000000000 0000000000000
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-slave1
OK
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> get key1
"v1-slave1"
127.0.0.1:6379>
slave2
[root@slave2 ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:ba138fa5f600850d0339b347f388 af2655504162
master_replid2:000000000000000000000000000 0000000000000
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-slave2
OK
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> get key1
"v1-slave2"
127.0.0.1:6379>
8.3、所有slave设置master的IP和端口
slave1:
127.0.0.1:6379> replicaof 192.168.112.40 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.40
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0
127.0.0.1:6379> get key1
"v1-master"·
slave2:
127.0.0.1:6379> replicaof 192.168.112.40 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.40
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:70
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57
repl_backlog_histlen:14
127.0.0.1:6379> get key1
"v1-master"
这里特地在两台slave上设置不同的数据是为了验证Slave 端切换master同步后会丢失之前的所有数据
8.4、master端验证slave信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.112.50,port=6379,state=online,offset=378,lag=1
slave1:ip=192.168.112.60,port=6379,state=online,offset=378,lag=1
master_replid:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:378
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:378
9、删除主从同步
9.1、slave节点取消主从复制
REPLICAOF NO ONE 指令可以取消主从复制
在任意一台slave上操作:
127.0.0.1:6379> replicaof no one
OK
127.0.0.1:6379> info replication
# Replication
role:master #角色变为master
connected_slaves:0
master_replid:e8839adba5e81db5da86007a3b2bbdcc7d84de7d
master_replid2:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_repl_offset:2464
second_repl_offset:2465
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57
repl_backlog_histlen:2408
9.2、在master上验证
可以看到slave数量减少为1
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.112.50,port=6379,state=online,offset=2492,lag=0
master_replid:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2492
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2492
10、同步日志
10.1、各个节点上观察日志
master上:
[root@master ~]# tail /apps/redis/log/redis_6379.log
22618:M 15 Apr 2024 15:35:25.707 * Synchronization with replica 192.168.112.50:6379 succeeded
22618:M 15 Apr 2024 15:36:09.639 * Replica 192.168.112.60:6379 asks for synchronization
22618:M 15 Apr 2024 15:36:09.639 * Full resync requested by replica 192.168.112.60:6379
22618:M 15 Apr 2024 15:36:09.639 * Starting BGSAVE for SYNC with target: disk
22618:M 15 Apr 2024 15:36:09.639 * Background saving started by pid 22639
22639:C 15 Apr 2024 15:36:09.640 * DB saved on disk
22639:C 15 Apr 2024 15:36:09.640 * RDB: 0 MB of memory used by copy-on-write
22618:M 15 Apr 2024 15:36:09.647 * Background saving terminated with success
22618:M 15 Apr 2024 15:36:09.647 * Synchronization with replica 192.168.112.60:6379 succeeded
22618:M 15 Apr 2024 16:05:22.257 # Connection with replica 192.168.112.60:6379 lost.
slave节点:
[root@slave1 ~]# tail /apps/redis/log/redis_6379.log
12569:S 15 Apr 2024 15:35:25.702 * Connecting to MASTER 192.168.112.40:6379
12569:S 15 Apr 2024 15:35:25.702 * MASTER <-> REPLICA sync started
12569:S 15 Apr 2024 15:35:25.703 * Non blocking connect for SYNC fired the event.
12569:S 15 Apr 2024 15:35:25.703 * Master replied to PING, replication can continue...
12569:S 15 Apr 2024 15:35:25.703 * Partial resynchronization not possible (no cached master)
12569:S 15 Apr 2024 15:35:25.704 * Full resync from master: 2132feee25664555e9ef7b6c1d20d105ee308e3d:0
12569:S 15 Apr 2024 15:35:25.709 * MASTER <-> REPLICA sync: receiving 196 bytes from master
12569:S 15 Apr 2024 15:35:25.709 * MASTER <-> REPLICA sync: Flushing old data
12569:S 15 Apr 2024 15:35:25.709 * MASTER <-> REPLICA sync: Loading DB in memory
12569:S 15 Apr 2024 15:35:25.709 * MASTER <-> REPLICA sync: Finished with success
10.2、修改slave节点
slave1:
[root@slave1 ~]# echo "replicaof 192.168.112.40 6379" >> /apps/redis/etc/redis.conf
[root@slave1 ~]# echo "masterauth centos" >> /apps/redis/etc/redis.conf
[root@slave1 ~]# systemctl restart redis
slave2:
[root@slave2 ~]# echo "replicaof 192.168.112.40 6379" >> /apps/redis/etc/redis.conf
[root@slave2 ~]# echo "masterauth centos" >> /apps/redis/etc/redis.conf
[root@slave2 ~]# systemctl restart redis
10.3、登录查看master和slave状态
master:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.112.50,port=6379,state=online,offset=4816,lag=0
slave1:ip=192.168.112.60,port=6379,state=online,offset=4816,lag=0
slave1:
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.40
master_port:6379
master_link_status:up
slave2:
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.40
master_port:6379
master_link_status:up
三、模拟master节点宕机
1、停止master的redis服务
[root@master ~]# systemctl stop redis
slave节点观察:
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.40
master_port:6379
master_link_status:down #显示down,表示无法连接master
2、观察slave节点日志
[root@slave1 ~]# tail /apps/redis/log/redis_6379.log
23515:S 15 Apr 2024 16:51:45.023 # Error condition on socket for SYNC: Connection refused
23515:S 15 Apr 2024 16:51:46.043 * Connecting to MASTER 192.168.112.40:6379
23515:S 15 Apr 2024 16:51:46.043 * MASTER <-> REPLICA sync started
23515:S 15 Apr 2024 16:51:46.043 # Error condition on socket for SYNC: Connection refused
23515:S 15 Apr 2024 16:51:47.055 * Connecting to MASTER 192.168.112.40:6379
23515:S 15 Apr 2024 16:51:47.056 * MASTER <-> REPLICA sync started
23515:S 15 Apr 2024 16:51:47.056 # Error condition on socket for SYNC: Connection refused
23515:S 15 Apr 2024 16:51:48.078 * Connecting to MASTER 192.168.112.40:6379
23515:S 15 Apr 2024 16:51:48.078 * MASTER <-> REPLICA sync started
23515:S 15 Apr 2024 16:51:48.079 # Error condition on socket for SYNC: Connection refused
3、观察slave状态
[root@slave1 ~]# redis-cli -a centos
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set key1 v1-slave1
(error) READONLY You can't write against a read only replica.
127.0.0.1:6379> get key1
"v1-master"
发现slave状态只读无法写入数据
四、主从复制故障恢复
1、slave节点故障与恢复
client指向另一个从节点即可,并及时修复故障从节点
2、master节点故障与恢复
需要提升slave为新的master
master故障后,只能手动提升一个slave为新master,不支持自动切换。master的切换会导致master_replid发生变化,slave之前的master_replid就和当前master不一致从而会引发所有slave的全量同步
3、主从复制故障恢复实现
当前主从复制中master节点故障
[root@master ~]# systemctl stop redis
3.1、停止slave1主从同步并提升为新的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_replid:a3bc41f15f4e2f0f701c452eeaf24a6080ade51c
master_replid2:2132feee25664555e9ef7b6c1d20d105ee308e3d
master_repl_offset:5488
second_repl_offset:5489
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:5488
127.0.0.1:6379> set keytest1 vtest1
OK
3.2、修改剩下的slave指向新的master节点
slave2:
127.0.0.1:6379> replicaof 192.168.175.20 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.50
master_port:6379
master_link_status:up
127.0.0.1:6379> set key100 v100
(error) READONLY You can't write against a read only replica. #只读
127.0.0.1:6379> get keytest1
"vtest1"
3.3、在新的master节点查看slave信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.112.60,port=6379,state=online,offset=5830,lag=1
五、实现redis的级联复制
Redis 的级联复制(Cascade Replication)是指在主从复制的基础上,通过创建多级复制链路,使得一个 Redis 从节点不仅作为其直接主节点的副本,还能充当其他从节点的主节点。这种结构允许数据复制跨越多个层级,形成一种树状拓扑结构。
1、涉及主机
角色 | 主机名 | IP地址 |
---|---|---|
主节点 | master | 192.168.112.10 |
一级从节点 | slave1 | 192.168.112.20 |
二级从节点 | slave2 | 192.168.112.30 |
二级从节点 | slave3 | 192.168.112.40 |
2、所有主机安装reids
略
3、搭建一主一从
3.1、主节点创建验证数据
master:
[root@master ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> set key-test1 test1
OK
127.0.0.1:6379> keys *
1) "key-test1"
127.0.0.1:6379> get key-test1
"test1"
3.2、一级从节点设置master的IP和端口
slave1:
[root@slave1 ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> replicaof 192.168.112.10 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.10
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:c8e3d3769a39454be02a13bec0324b01b43c81b7
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
127.0.0.1:6379> get key-test1
"test1"
4、修改二级从节点指向一级从节点作为master
slave2:
[root@slave2 ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> replicaof 192.168.112.20 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.20
master_port:6379
master_link_status:up
127.0.0.1:6379> keys *
1) "key-test1"
127.0.0.1:6379> get key-test1
"test1"
slave3:
[root@slave3 ~]# redis-cli -a centos --no-auth-warning
127.0.0.1:6379> replicaof 192.168.112.20 6379
OK
127.0.0.1:6379> config set masterauth centos
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.20
master_port:6379
master_link_status:up
127.0.0.1:6379> keys *
1) "key-test1"
127.0.0.1:6379> get key-test1
"test1"
5、在master上设置key,观察是否同步
127.0.0.1:6379> set name misaki
OK
127.0.0.1:6379> get name
"misaki"
5.1、在slave上进行验证
127.0.0.1:6379> get name
"misaki"
6、在一级从节点上查看状态
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.112.10
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6 #最近一次与master通信已经过去多少秒
master_sync_in_progress:0 #是否正在与master通信
slave_repl_offset:1332 #当前同步的偏移量
slave_priority:100 #slave优先级,master故障后优先级值越小越优先同步
slave_read_only:1
connected_slaves:2
slave0:ip=192.168.112.30,port=6379,state=online,offset=1332,lag=1
slave1:ip=192.168.112.40,port=6379,state=online,offset=1332,lag=1
master_replid:c8e3d3769a39454be02a13bec0324b01b43c81b7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1332
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1332