1. 主从复制(Replication)
1.1 复制流程
Slave 发起同步 ──→ Master 判断同步方式 ──→ 全量或增量同步
全量同步(首次或 runid 不匹配):
1. Slave 发送 PSYNC ? -1
2. Master 执行 BGSAVE → 生成 RDB
3. Master 发送 RDB 到 Slave
4. Slave 清空内存 → 加载 RDB
5. Master 将新写入命令追加到 Replication Buffer → 发送给 Slave
6. 进入持续同步模式
增量同步(offset 在 replication backlog 内):
1. Slave 发送 PSYNC <runid> <offset>
2. Master 检查 offset 是否在 backlog 中
3. 直接发送缺失部分的命令 → Slave 执行
4. 无需全量 RDB,快速恢复
1.2 关键概念
| 概念 | 说明 |
|---|---|
| runid | Master 的唯一标识,重启后改变 |
| offset | 复制偏移量,Master 和 Slave 各自维护 |
| replication backlog | Master 的固定大小缓存区(默认 1MB),存储最近命令 |
| Replication Buffer | 每个 Slave 连接的独立输出缓存 |
# 查看复制状态
INFO replication
# role:master
# connected_slaves:2
# slave0:ip=192.168.1.2,port=6379,state=online,offset=123456,lag=0
# master_repl_offset:123456
1.3 配置
# Slave 配置
replicaof 192.168.1.1 6379
masterauth <password>
replica-read-only yes
# 允许 Slave 处理过期 key(默认)
replica-lazy-flush yes
2. Sentinel 哨兵模式
2.1 架构与职责
Client (连接 Sentinel 获取地址)
│
┌───────────────┼───────────────┐
│ │ │
Sentinel-1 Sentinel-2 Sentinel-3 (至少 3 个,奇数)
│ │ │
└───────────────┼───────────────┘
│
┌─────▼─────┐
│ Master │
└─────┬─────┘
┌────────┴────────┐
┌────▼────┐ ┌────▼────┐
│ Slave 1 │ │ Slave 2 │
└─────────┘ └─────────┘
Sentinel 职责:
1. 监控:定时 ping Master/Slave/Sentinel
2. 通知:故障时通知管理员(通过脚本)
3. 自动故障转移:Master 宕机 → 选举新 Master
4. 配置提供:客户端向 Sentinel 询问当前 Master 地址
2.2 故障转移流程
1. Sentinel-1 发现 Master 无响应(主观下线,SDOWN)
2. 询问其他 Sentinel,多数同意 → 客观下线(ODOWN)
3. 选举 Leader Sentinel(Raft 算法)
4. Leader 选择最优 Slave 提升为 Master(选择优先级最高、复制最完整的)
5. 原 Slave 重新配置为新 Master 的 Slave
6. 客户端通过 Sentinel 获取新 Master 地址
2.3 Sentinel 配置
# sentinel.conf
sentinel monitor mymaster 192.168.1.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster password
| 参数 | 说明 |
|---|---|
monitor | 监控的 Master,最后的 2 是「同意下线」的 Sentinel 数 |
down-after-milliseconds | 无响应判定为下线的时间 |
failover-timeout | 故障转移超时 |
parallel-syncs | 同时重新配置的 Slave 数 |
2.4 脑裂问题与解决
# 脑裂:网络分区时,原 Master 和 Sentinel 断开
# 原 Master 仍在写入,但已经不被 Sentinel 认可
# 分区恢复后,原 Master 的数据被覆盖 → 数据丢失
# 解决方案:主库最小从库数 + 延迟限制
min-replicas-to-write 1 # 至少有 1 个 Slave 同步才能写入
min-replicas-max-lag 10 # Slave 延迟超过 10 秒则拒绝写入
3. 读写分离
// Spring Boot + Lettuce 读写分离
@Bean
public RedisConnectionFactory lettuceConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED) // 优先从 Slave 读
.build();
RedisStaticMasterReplicaConfiguration config =
new RedisStaticMasterReplicaConfiguration("master", 6379);
config.addNode("slave1", 6379);
config.addNode("slave2", 6379);
return new LettuceConnectionFactory(config, clientConfig);
}
// 纯 Lettuce
RedisClient client = RedisClient.create("redis://master:6379");
StatefulRedisMasterReplicaConnection<String, String> conn = MasterReplica.connect(
client, StringCodec.UTF8,
RedisURI.create("redis://slave1:6379"),
RedisURI.create("redis://slave2:6379")
);
conn.setReadFrom(ReadFrom.REPLICA_PREFERRED);
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。