redis主从复制

Redis 主从复制详解

Redis 主从复制(Master-Slave Replication)是 Redis 提供的高可用性和数据冗余机制之一。它允许将一个 Redis 实例(主节点,Master)的数据实时复制到其他实例(从节点,Slave 或 Replica),从而实现读写分离、数据备份和故障转移的基础。主从复制从 Redis 2.2 开始支持,并在后续版本中不断优化(如 Redis 5.0 引入 PSYNC2 部分重同步)。下面我将详细讲解其机制,包括工作原理、配置方式、例子、优缺点、数据一致性考虑、与哨兵/集群的集成,以及最佳实践。内容基于 Redis 的最新版本(截至 2025 年 9 月 25 日,Redis 8.x),但核心概念兼容旧版。

1. Redis 主从复制的概述

主从复制的核心是数据同步:主节点处理写操作,从节点复制主节点的数据,并可处理读操作。这提高了系统的读吞吐量和容错能力。

  • 关键角色
    • 主节点(Master):处理所有写操作(SET、DEL 等),并将变化推送给从节点。主节点可有多个从节点。
    • 从节点(Replica):只读(默认),实时同步主节点数据。可配置为级联复制(从节点下挂从节点)。
  • 适用场景:读多写少的应用(如缓存系统)、数据备份、地理分布(跨数据中心复制)。
  • 不适用场景:需要自动故障转移时(需结合 Sentinel);大规模分布式时(用 Cluster)。
  • 优势:简单、无需额外组件;支持异步复制,性能高。
  • 术语更新:从 Redis 5.0 开始,“slave” 被重命名为 “replica”,但旧命令兼容。

主从复制不保证强一致性(异步),但可配置为半同步(Redis 6.0+)以提高一致性。

2. 工作原理

主从复制分为全量同步(Full Synchronization)和增量同步(Partial Synchronization)两个阶段。

全量同步(初次或异常时)
  • 当从节点连接主节点时,如果是首次或数据差异太大,主节点会执行全量同步。
  • 流程:
    1. 从节点发送 PSYNC ? -1(或旧版 SYNC)命令给主节点。
    2. 主节点 fork 子进程,生成 RDB 快照(即使未启用持久化,也会临时生成)。
    3. 主节点发送 RDB 文件给从节点,同时缓冲期间的写命令(replication backlog)。
    4. 从节点加载 RDB 文件清空自身数据,然后应用缓冲命令。
  • 开销:大数据集下,fork 和传输 RDB 会耗时(GB 级数据可能几分钟)。
增量同步(正常运行时)
  • 全量后,进入增量模式:主节点将每个写命令实时转发给从节点(通过 replication feed)。
  • 从节点执行这些命令,保持与主一致。
  • 如果网络中断,从节点会使用 replication ID 和 offset 尝试部分重同步(PSYNC)。
    • Redis 2.8 引入 PSYNC,支持断点续传。
    • Redis 5.0 的 PSYNC2 优化了多从节点场景,支持 replication ID 变化。
  • 主节点维护一个 replication backlog 缓冲区(默认 1MB),存储最近命令。如果从节点 offset 在 backlog 内,可增量同步;否则回退全量。
数据一致性
  • 异步复制:默认,主节点不等待从节点确认,写操作立即返回。可能有延迟(毫秒级)。
  • 半同步(WAIT 命令):Redis 3.2+ 支持 WAIT numreplicas timeout,主节点等待至少 numreplicas 个从节点确认后返回,提高一致性。
  • 最终一致性:从节点最终与主一致,但不保证实时。
其他机制
  • 读写分离:从节点默认只读(replica-read-only yes),客户端可连接从节点读数据。
  • 级联复制:从节点可配置为另一个从节点的主,减轻主节点负载(树状结构)。
  • 无盘复制(Diskless):Redis 2.8.18+ 支持,主节点不生成 RDB 文件,直接通过 socket 传输数据流(适合 SSD 慢环境)。

3. 配置选项

配置主要通过 redis.conf 文件或运行时命令。

  • 主节点配置(默认所有节点都是主):

    • repl-backlog-size 1mb:backlog 大小,越大越能容忍长中断。
    • repl-backlog-ttl 3600:backlog 过期时间(秒)。
    • repl-diskless-sync yes:启用无盘复制。
    • min-replicas-to-write 1 / min-replicas-max-lag 10:最小从节点数和最大延迟,低于阈值主拒绝写(提高一致性)。
  • 从节点配置

    • replicaof <masterip> <masterport>:指定主节点 IP 和端口。
    • masterauth <password>:如果主有密码。
    • replica-read-only yes:从节点只读。
    • replica-priority 100:优先级,用于 Sentinel 选举(越低越优先)。
  • 运行时命令

    • REPLICAOF host port:动态设置从节点(旧版 SLAVEOF)。
    • REPLICAOF NO ONE:从节点升级为主。
    • INFO replication:查看复制状态(master_replid、connected_replicas 等)。

4. 例子

下面提供实际例子,包括配置和命令。假设有两个 Redis 实例:主节点(127.0.0.1:6379),从节点(127.0.0.1:6380)。使用 Docker 或本地多实例模拟。

示例 1: 通过配置文件设置主从
  1. 主节点 redis.conf(端口 6379):

    1
    2
    3
    4
    bind 127.0.0.1
    port 6379
    requirepass "masterpass" # 可选密码
    repl-backlog-size 1mb
  2. 从节点 redis.conf(端口 6380):

    1
    2
    3
    4
    5
    bind 127.0.0.1
    port 6380
    replicaof 127.0.0.1 6379
    masterauth "masterpass"
    replica-read-only yes
  3. 启动实例:

    1
    2
    redis-server /path/to/master.conf
    redis-server /path/to/slave.conf
  4. 测试同步:

    • 连接主节点:redis-cli -p 6379 -a masterpass
      1
      SET key "value"
    • 连接从节点:redis-cli -p 6380
      1
      2
      GET key  # 输出 "value"
      SET key "new" # 错误:READONLY You can't write against a read only replica.
    • 查看状态:主节点执行 INFO replication,输出类似:
      1
      2
      3
      role:master
      connected_slaves:1
      slave0:ip=127.0.0.1,port=6380,state=online,offset=123,lag=0
示例 2: 运行时动态设置(使用命令)
  1. 启动两个独立 Redis(无 replicaof)。
  2. 在从节点 CLI:
    1
    REPLICAOF 127.0.0.1 6379
  3. 如果主有密码,先在从节点设置 CONFIG SET masterauth "masterpass"
  4. 模拟中断:关闭从节点,重启后自动重连(如果 backlog 覆盖中断期,则增量同步)。
示例 3: 半同步复制(使用 WAIT)

在客户端代码中使用(这里用 Go 的 go-redis/v9 库示例,假设连接主节点):

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
package main

import (
"context"
"fmt"
"time"

"github.com/redis/go-redis/v9"
)

func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "masterpass",
})

// 假设有1个从节点,等待确认,超时5秒
_, err := rdb.Set(ctx, "key", "value", 0).Result()
if err != nil {
fmt.Println("Set error:", err)
return
}

// WAIT: 等待至少1个从节点确认
res, err := rdb.Wait(ctx, 1, time.Second*5).Result()
if err != nil {
fmt.Println("Wait error:", err)
} else {
fmt.Printf("Confirmed by %d replicas\n", res) // 输出: Confirmed by 1 replicas
}
}
  • 这确保写操作被至少一个从节点复制后才继续。
示例 4: 级联复制
  • 配置从节点 A(replicaof 主),从节点 B(replicaof 从节点 A 的 IP:端口)。
  • 主写数据,最终传播到 B。

5. 优点

  • 高可用:从节点可作为备份,主宕机时手动/自动(Sentinel)切换。
  • 负载均衡:读操作分担到从节点,提高吞吐。
  • 数据冗余:多份数据副本,防丢失。
  • 异步高效:不阻塞主节点写操作。
  • 易扩展:添加从节点无停机。

6. 缺点与局限性

  • 不自动 failover:主宕机需手动切换(REPLICAOF NO ONE)。
  • 异步延迟:高负载下,从节点可能落后几秒。
  • 全量开销:大数据集同步耗资源(CPU/网络)。
  • 写一致性弱:无内置回滚,主从不一致时需手动修复。
  • 单点瓶颈:所有写在主,规模大时需 Cluster。
  • 安全:复制流量不加密,生产用 stunnel 或 Redis 6+ 的 TLS。

7. 与哨兵(Sentinel)和集群(Cluster)的比较

  • Sentinel:监控主从,自动 failover(选举新主)。配置 sentinel.conf,需至少 3 个 Sentinel 节点。主从是 Sentinel 的基础。
  • Cluster:分布式,自动分片(16384 槽),内置主从。适合大数据(TB 级),但更复杂。
  • 选择:简单高可用用主从 + Sentinel;大规模用 Cluster。

8. 数据一致性与恢复

  • 一致性:用 WAITmin-replicas-to-write 加强。
  • 恢复:主宕机后,从节点升级为主(REPLICAOF NO ONE),其他从指向新主。
  • 持久化集成:主从都启用 AOF/RDB,确保重启后数据恢复。
  • 监控:用 INFO replication 或工具如 Prometheus 监控 lag(延迟)。

9. 最佳实践

  • 多从节点:至少 2 个从,分布不同机器/区域。
  • 配置 backlog:根据写负载调大(e.g., 256MB),减少全量同步。
  • 网络优化:用专用网络,启用压缩(Redis 6+ 支持 LZ4)。
  • 安全:设置 requirepass 和 masterauth;用 firewall 限制端口。
  • 测试:模拟主宕机,验证切换;用 redis-benchmark 测试读写分离性能。
  • 避免坑:不要在从节点写数据;大数据集用无盘复制;升级到 Redis 7.0+ 以获 PSYNC 优化。
  • 监控工具:Redis Exporter + Grafana 查看 replica 状态。
  • 版本注意:Redis 6.0+ 引入 replica-announce-ip 等,优化云环境;Redis 8.x 提升了复制稳定性。
[up主专用,视频内嵌代码贴在这]