Redis 主从复制
主从复制是 Redis 高可用架构的基础,允许数据从一个 Redis 服务器(主库)复制到一个或多个 Redis 服务器(从库)。
复制概述
什么是主从复制?
主从复制将主库的数据异步复制到从库,实现读写分离和数据备份。
┌─────────────────────────────────────────────────────────────┐
│ Redis 主从复制架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Master │ ──── 写入操作 │
│ │ (主库) │ │
│ └─────────────┘ │
│ │ │
│ │ 复制数据 │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Slave 1 │ │ Slave 2 │ │ Slave 3 │ │
│ │ (从库) │ │ (从库) │ │ (从库) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └─────────────────┴─────────────────┘ │
│ 读取操作 │
│ │
└─────────────────────────────────────────────────────────────┘
复制的作用
| 作用 | 说明 |
|---|---|
| 读写分离 | 主库写入,从库读取,分散负载 |
| 数据备份 | 从库作为实时数据副本 |
| 高可用 | 主库故障时可切换到从库 |
| 负载均衡 | 多个从库分担读请求 |
复制原理
复制流程
┌─────────────────────────────────────────────────────────────┐
│ Redis 复制流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Slave Master │
│ │ │ │
│ │ 1. 发送 SYNC/PSYNC 命令 │ │
│ │ ─────────────────────────────────────────────> │ │
│ │ │ │
│ │ 2. 执行 BGSAVE 生成 RDB │ │
│ │ ┌───────────┤ │
│ │ │ fork │ │
│ │ └───────────┤ │
│ │ │ │
│ │ 3. 发送 RDB 文件 │ │
│ │ <───────────────────────────────────────────── │ │
│ │ │ │
│ │ 4. 加载 RDB 文件 │ │
│ │ ┌───────────┤ │
│ │ │ 加载 │ │
│ │ └───────────┤ │
│ │ │ │
│ │ 5. 发送积压的写命令 │ │
│ │ <───────────────────────────────────────────── │ │
│ │ │ │
│ │ 6. 持续接收写命令(命令传播) │ │
│ │ <───────────────────────────────────────────── │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘
复制类型
全量复制:
- 从库首次连接或断开太久时发生
- 主库执行 BGSAVE 生成 RDB
- 发送 RDB 和积压命令给从库
部分复制:
- 从库短暂断开后重连
- 如果偏移量在复制积压缓冲区内
- 只发送缺失的命令
配置主从复制
主库配置
# redis.conf
# 绑定地址
bind 0.0.0.0
# 端口
port 6379
# 保护模式(设置密码后可以关闭)
protected-mode yes
# 设置密码
requirepass your_password
# 复制积压缓冲区大小(用于部分复制)
repl-backlog-size 1mb
# 积压缓冲区保留时间
repl-backlog-ttl 3600
从库配置
# redis.conf
# 绑定地址
bind 0.0.0.0
# 端口
port 6380
# 指定主库地址
replicaof 192.168.1.100 6379
# 主库密码
masterauth your_password
# 从库只读
replica-read-only yes
# 从库连接密码
requirepass your_password
启动从库
# 方式一:配置文件启动
redis-server /etc/redis/redis-slave.conf
# 方式二:命令行指定
redis-server --port 6380 --replicaof 192.168.1.100 6379
# 方式三:运行时设置
redis-cli -p 6380
> REPLICAOF 192.168.1.100 6379
取消复制
# 取消从库身份
redis-cli -p 6380 REPLICAOF NO ONE
查看复制状态
在主库查看
redis-cli INFO replication
# 输出示例:
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.101,port=6380,state=online,offset=12345,lag=0
slave1:ip=192.168.1.102,port=6381,state=online,offset=12345,lag=1
master_replid:abc123...
master_repl_offset:12345
在从库查看
redis-cli INFO replication
# 输出示例:
# Replication
role:slave
master_host:192.168.1.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:12345
slave_read_only:1
关键指标说明
| 指标 | 说明 |
|---|---|
role | 角色(master/slave) |
connected_slaves | 连接的从库数量 |
master_link_status | 主库连接状态(up/down) |
master_sync_in_progress | 是否正在同步 |
slave_repl_offset | 从库复制偏移量 |
lag | 从库延迟秒数 |
读写分离
实现方式
# 写入主库
redis-cli -h master -p 6379 SET key value
# 读取从库
redis-cli -h slave -p 6380 GET key
应用层配置
# Python 示例
import redis
# 主库连接(写)
master = redis.Redis(host='192.168.1.100', port=6379, password='your_password')
# 从库连接(读)
slave = redis.Redis(host='192.168.1.101', port=6380, password='your_password')
# 写入主库
master.set('key', 'value')
# 读取从库
value = slave.get('key')
哨兵模式(Sentinel)
哨兵用于监控主从复制,实现自动故障转移。
哨兵架构
┌─────────────────────────────────────────────────────────────┐
│ 哨兵架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Sentinel 1 │ │ Sentinel 2 │ │ Sentinel 3 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └─────────────────┴─────────────────┘ │
│ 监控 │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Master │ │ Slave 1 │ │ Slave 2 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
哨兵配置
# sentinel.conf
# 端口
port 26379
# 监控主库
# sentinel monitor <master-name> <ip> <port> <quorum>
# quorum: 多少个哨兵同意才认为主库下线
sentinel monitor mymaster 192.168.1.100 6379 2
# 主库密码
sentinel auth-pass mymaster your_password
# 主库多久无响应认为下线(毫秒)
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 180000
# 同时可以有多少从库对新主库同步
sentinel parallel-syncs mymaster 1
启动哨兵
# 启动哨兵
redis-sentinel /etc/redis/sentinel.conf
# 或使用 redis-server
redis-server /etc/redis/sentinel.conf --sentinel
哨兵常用命令
# 查看主库信息
redis-cli -p 26379 SENTINEL master mymaster
# 查看从库信息
redis-cli -p 26379 SENTINEL slaves mymaster
# 查看哨兵列表
redis-cli -p 26379 SENTINEL sentinels mymaster
# 获取当前主库地址
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 手动故障转移
redis-cli -p 26379 SENTINEL failover mymaster
复制常见问题
1. 主从连接断开
# 检查网络连通性
ping master_ip
# 检查防火墙
sudo ufw allow 6379
# 检查主库状态
redis-cli -h master -p 6379 PING
2. 从库数据不一致
# 全量重新同步
redis-cli -p 6380 REPLICAOF NO ONE
redis-cli -p 6380 FLUSHALL
redis-cli -p 6380 REPLICAOF master_ip 6379
3. 复制延迟
# 查看延迟
redis-cli -p 6380 INFO replication | grep lag
# 优化网络
# 使用内网连接
# 增加复制积压缓冲区
4. 主库写入压力大
# 增加从库数量
# 使用读写分离
# 考虑集群模式
小结
本章我们学习了:
- 复制原理:全量复制和部分复制
- 配置方法:主库和从库的配置
- 复制状态:监控和排查问题
- 读写分离:分散读写压力
- 哨兵模式:实现自动故障转移
练习
- 配置一主两从的复制架构
- 测试主从数据同步
- 配置哨兵并测试故障转移
- 实现读写分离的应用程序