1. repl_backlog 是什么?
repl_backlog(复制积压缓冲区)是 Redis Master 维护的一块固定大小的内存,用于保存最近发送给 Slave 的复制流(Replication Stream)。
它的主要作用:
-
支持主从断线后的增量同步(PSYNC)
-
避免每次断线都重新进行全量同步(RDB)
注意:保存的是复制流,通常表现为写命令,但本质上是 Master 发给 Slave 的同步数据,而不是简单的客户端历史命令。
2. repl_backlog 的数据结构
底层采用:
固定大小的环形缓冲区(Circular Buffer)
例如:
+------------------------------+
| |
| repl_backlog |
| |
+------------------------------+
特点:
-
大小固定
-
写满后不会扩容
-
从头开始覆盖最旧的数据
例如:
第一次:
cmd1
cmd2
cmd3
cmd4
继续写:
cmd5
↓
覆盖 cmd1
因此:
数组内容会循环覆盖。
3. 什么是 offset?
除了 backlog,还有一个非常重要的概念:
复制偏移量(Replication Offset)
它表示:
复制流中的第几个字节。
Master 维护:
master_repl_offset
Slave 也维护:
slave_repl_offset
它们记录当前已经同步到了哪里。
4. offset 与环形数组的关系
这是最容易混淆的地方。
backlog
是一个固定大小的数组。
例如:
100 字节
数组下标:
0
1
2
...
99
写满以后:
99
↓
0
重新开始
因此:
数组下标会循环。
offset
offset 不属于数组。
它代表整个复制流的位置。
例如:
offset
1
2
3
...
100
101
102
...
100000
...
特点:
-
一直递增
-
不会因为数组覆盖而重新计数
-
理论上会持续增长(Redis 使用 64 位整数,正常情况下几乎不用担心溢出)
因此:
数组内容是环状的,会发生覆盖;offset 会一直累加,不会回绕。
5. Master 如何判断是否可以增量同步?
假设:
当前 backlog 保存:
offset
901 ~ 1000
Slave 汇报:
我同步到了950
Master 发现:
951~1000
还在 backlog 中。
于是:
PSYNC
↓
发送951~1000
完成:
增量同步。
如果 Slave 汇报:
800
Master 查看:
801~900
已经被覆盖。
于是:
FULLRESYNC
重新:
-
生成 RDB
-
全量同步
-
再同步 RDB 生成期间的新命令
6. 为什么 backlog 要设计成环形?
如果一直保存所有复制数据:
历史命令越来越多
↓
内存无限增长
↓
Redis 内存耗尽
因此 Redis 采用:
固定容量 + 覆盖旧数据
优点:
-
内存固定
-
写入效率高(O(1))
-
非常适合缓存最近的数据
7. 如果 Master 一直工作,Slave 长时间宕机怎么办?
假设:
Master
↓
持续写入
↓
backlog 不断覆盖旧数据
Slave 长时间离线后恢复:
如果缺失的数据:
-
还在 backlog 中 → 增量同步(PSYNC)
-
已经被覆盖 → 全量同步(FULLRESYNC)
因此:
Redis 只能保证一定时间内的增量同步,无法永久保存复制历史。
8. 生产环境如何减少全量同步?
主要方法:
(1)增大 backlog
例如:
repl-backlog-size 256mb
或:
repl-backlog-size 1gb
保存更多复制数据。
(2)保证 Slave 尽快恢复
减少长时间离线。
(3)接受全量同步
如果 Slave 离线太久,这是 Redis 的正常机制。
9. 核心总结(★★★★★)
-
repl_backlog是 Master 保存最近复制流的固定大小环形缓冲区。 -
backlog 中的数据会不断覆盖最旧的数据。
-
Master 和 Slave 都维护自己的复制 offset。
-
数组内容会循环覆盖,但 offset 会一直递增。
-
Slave 重连时,会上报自己的 offset。
-
如果缺失的数据仍在 backlog 中,则执行 PSYNC(增量同步)。
-
如果缺失的数据已被覆盖,则执行 FULLRESYNC(全量同步)。
-
backlog 的大小决定了 Slave 最长可以离线多久而仍能进行增量同步。