Akemi

Redis主从复制

2024/09/22

主从刚连接的时候,会进行全量同步,全量同步结束后进行增量同步
如果有需要会在任何时候发起全量同步,首先进行增量同步,如果不行就进行全量同步

redis主从复制的特点
1.是异步复制,实时性较差
2.一个主redis可以含有多个redis
3.可以使用级联结构
4.非阻塞的同步(因为是异步复制),同步时依然可以处理请求
5.提高的可用性和扩展性(可扩展,读负载均衡

redis主从复制过程

全量同步阶段(disk方式)
slave第一次启动时,初始化阶段,此时slave将master节点数据复制一遍
在2.8版本之前,重启slave节点也会进行全量同步
此时slave无法提供服务
1.slave连接master,发送sync
2.master收到sync,执行bgsave,生成快照文件
3.master向所有slave发送快照文件(会缓存此时写入的命令)
4.slave节点清空自己的数据,并且载入快照
5.master发送之前缓存的写命令
6.slave执行之前缓存的写命令

注: 需要关闭master节点的自启,因为可能会导致数据被清空

这种方式可以让多个slave节点同时进行读取rdb文件

全量同步会对从服务器产生很大的压力,所以启动后的同步都是增量同步

增量同步阶段
增量同步是从redis2.8后新增的功能(或slave重启后的阶段)
正常情况:
slave初始化后开始正常工作时,将master发生的写操作同步到slave
master每执行一个写命令,都会给slave发送同步写命令

slave节点宕机重启情况(2.8版本后):
增量同步依赖于master内存中给每个slave维护了一份同步日志和同步标识
具体而言,主服务器为复制流维护了一个内存缓冲区。维护复制偏移量和master run id

当slave重新连接上时,会进行判断
1.主从服务器的master run id是否相同
2.指定偏移量在内存缓冲区还有效(如果时间太久或短时间内大量写入就会失效)

如果满足就会从上次中断的点继续同步
如果其中一个不满足就会进行全量同步

无磁盘复制(socket方式)

在redis2.8.18版本后增加的功能,是串行复制
全量同步需要再磁盘上创建RDB文件,然后加载文件发送数据,如果使用低速磁盘会造成压力
使用无磁盘复制时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘进行中间存储,避免IO性能问题
如果硬盘性能高(比如使用SSD作为内存)而网络性能紧张时,建议使用disk方式复制
如果硬盘性能低,而网络性能高时,建议使用socket方式复制

开启方式:redis.conf文件
repl-disless-sync yes开启无磁盘复制
repl-diskless-sync-delay传输延迟时间sec,设置尽量大
在这个时间范围内等待slave注册,注册了就传;如果没有注册,就需要等待下一批传输

主从复制的宕机情况

1.slave节点宕机
重新启动后,redis从库重启后自动加入主从结构,2.8版本前会全量同步,2.8版本后如果偏移量大就会全量同步,反之增量同步

2.master节点宕机
(1)在slave节点执行SLAVEOF NO ONE,断开主从关系,并提升为主库继续服务
(2)主库修复启动后,执行SLAVEOF,将其设置为其他库的从库,把数据更新回来
哨兵模式可以自动进行切换

主从复制配置与优化参数

相关参数

1
2
3
4
5
6
7
8
9
10
11
12
slaveof 192.168.10.100 6379 开启主从复制(启动后自动开启)
masterauth 123456 主从密码验证(slave需要有master的密码)
slave-serve-stale-data yes
yes: slave失去连接或正在同步时,slave会继续响应客户端请求
no: slave失去连接或正在同步时,除了info和slaveof以外的命令都会报错SYNC with master in progress
slave-read-only yes 只读状态,默认为yes
repl-diskless-sync no 是否使用socket方式复制(无磁盘复制)
repl-diskless-sync-delay 5 传输延迟时间
repl-ping-slave-period 10 slave向master发送ping的时间间隔
repl-timeout 60 复制连接超时时间,如果上次slave发送时间超过60s就认为其离线
repl-backlog-size 5mb 复制缓冲区,用来保存新的缓存的命令:缓冲区越大,slave可以离线的时间更长
repl-backlog-ttl 3600 没有slave时释放缓冲区内存的时间3600s

简单演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
mkdir /var/log/redis -p

cat >redis-6379.conf<<EOF
bind 127.0.0.1
dir ./
protected-mode yes
port 6379
slave-serve-stale-data yes
Logfile "/var/log/redis/redis-6379.log"
databases 16
daemonize yes
save 900 1
save 300 10
save 60 10000
EOF

cat >redis-6380.conf<<EOF
bind 127.0.0.1
dir ./
protected-mode yes
port 6380
slave-serve-stale-data yes
Logfile "/var/log/redis/redis-6380.log"
databases 16
daemonize yes
save 900 1
save 300 10
save 60 10000
EOF

redis-server redis-6379.conf
redis-server redis-6380.conf
ss -tunlp |grep redi
tcp LISTEN 0 128 127.0.0.1:6379 *:* users:(("redis-server",pid=19067,fd=6))
tcp LISTEN 0 128 127.0.0.1:6380 *:* users:(("redis-server",pid=19072,fd=6))

#启动主从复制,从库执行复制
redis-cli -p 6379 SLAVEOF 127.0.0.1 6380

#查看日志
tail -f /var/log/redis/redis-6379.log
19067:S 21 Sep 2024 22:49:58.054 * MASTER <-> REPLICA sync started
19067:S 21 Sep 2024 22:49:58.054 * Non blocking connect for SYNC fired the event.
19067:S 21 Sep 2024 22:49:58.054 * Master replied to PING, replication can continue...
19067:S 21 Sep 2024 22:49:58.054 * Trying a partial resynchronization (request f93a36cd8e21e9b4b66ab7700436d7542898011c:1).
19067:S 21 Sep 2024 22:49:58.104 * Full resync from master: a8860a38e64e9b953173dcb04d20f06c38349198:0
19067:S 21 Sep 2024 22:49:58.104 * Discarding previously cached master state.
19067:S 21 Sep 2024 22:49:58.155 * MASTER <-> REPLICA sync: receiving 175 bytes from master
19067:S 21 Sep 2024 22:49:58.155 * MASTER <-> REPLICA sync: Flushing old data
19067:S 21 Sep 2024 22:49:58.155 * MASTER <-> REPLICA sync: Loading DB in memory
19067:S 21 Sep 2024 22:49:58.155 * MASTER <-> REPLICA sync: Finished with success

tail -f /var/log/redis/redis-6380.log
19072:M 21 Sep 2024 22:48:49.743 * DB loaded from disk: 0.000 seconds
19072:M 21 Sep 2024 22:48:49.743 * Ready to accept connections
19072:M 21 Sep 2024 22:49:58.054 * Replica 127.0.0.1:6379 asks for synchronization
19072:M 21 Sep 2024 22:49:58.054 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'f93a36cd8e21e9b4b66ab7700436d7542898011c', my replication IDs are 'e95f6a7290a9971653e08814f2f20db13e88ae43' and '0000000000000000000000000000000000000000')
19072:M 21 Sep 2024 22:49:58.054 * Starting BGSAVE for SYNC with target: disk
19072:M 21 Sep 2024 22:49:58.054 * Background saving started by pid 19141
19141:C 21 Sep 2024 22:49:58.105 * DB saved on disk
19141:C 21 Sep 2024 22:49:58.105 * RDB: 4 MB of memory used by copy-on-write
19072:M 21 Sep 2024 22:49:58.155 * Background saving terminated with success
19072:M 21 Sep 2024 22:49:58.155 * Synchronization with replica 127.0.0.1:6379 succeeded

搞个脚本写入一些数据
#!/bin/bash
# Redis 端口
PORT=6380
# 遍历 1 到 1002
for (( i=1; i<=1002; i++ ))
do
# 构造键和值
KEY="k_$i"
VALUE="v_$i"
# 使用 redis-cli 设置键值对
redis-cli -p $PORT set "$KEY" "$VALUE"
done

CATALOG
  1. 1. redis主从复制过程
  2. 2. 无磁盘复制(socket方式)
  3. 3. 主从复制的宕机情况
  4. 4. 主从复制配置与优化参数