跳到主要内容

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. 主库写入压力大

# 增加从库数量
# 使用读写分离
# 考虑集群模式

小结

本章我们学习了:

  1. 复制原理:全量复制和部分复制
  2. 配置方法:主库和从库的配置
  3. 复制状态:监控和排查问题
  4. 读写分离:分散读写压力
  5. 哨兵模式:实现自动故障转移

练习

  1. 配置一主两从的复制架构
  2. 测试主从数据同步
  3. 配置哨兵并测试故障转移
  4. 实现读写分离的应用程序

参考资源