Redis主从(Master-Slave)复制(Replication)设置

本文介绍了Redis的主从复制功能,包括复制原理、配置方法、只读从服务器、部分重同步等内容,并通过实战演示了如何配置主从服务器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、复制(Replication)

Redis 支持简单且易用的主从复制(master-slave replication)功能, 该功能可以让从服务器(slave server)成为主服务器(master server)的精确复制品。

以下是关于 Redis 复制功能的几个重要方面:

  1. Redis 使用异步复制。 从 Redis 2.8 开始, 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。

  2. 一个主服务器可以有多个从服务器。

  3. 不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。

  4. 复制功能不会阻塞主服务器: 即使有一个或多个从服务器正在进行初次同步, 主服务器也可以继续处理命令请求。

  5. 复制功能也不会阻塞从服务器: 只要在 redis.conf 文件中进行了相应的设置, 即使从服务器正在进行初次同步, 服务器也可以使用旧版本的数据集来处理命令查询。

  6. 不过, 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。

  7. 你还可以配置从服务器, 让它在与主服务器之间的连接断开时, 向客户端发送一个错误。

  8. 复制功能可以单纯地用于数据冗余(data redundancy), 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说, 繁重的 SORT 命令可以交给附属节点去运行。

  9. 可以通过复制功能来让主服务器免于执行持久化操作: 只要关闭主服务器的持久化功能, 然后由从服务器去执行持久化操作即可。

2、复制功能的运作原理

无论是初次连接还是重新连接, 当建立一个从服务器时, 从服务器都将向主服务器发送一个 SYNC 命令。

接到 SYNC 命令的主服务器将开始执行 BGSAVE , 并在保存操作执行期间, 将所有新执行的写入命令都保存到一个缓冲区里面。

当 BGSAVE 执行完毕后, 主服务器将执行保存操作所得的 .rdb 文件发送给从服务器, 从服务器接收这个 .rdb 文件, 并将文件中的数据载入到内存中。

之后主服务器会以 Redis 命令协议的格式, 将写命令缓冲区中积累的所有内容都发送给从服务器。

你可以通过 telnet 命令来亲自验证这个同步过程: 首先连上一个正在处理命令请求的 Redis 服务器, 然后向它发送 SYNC 命令, 过一阵子, 你将看到 telnet 会话(session)接收到服务器发来的大段数据(.rdb 文件), 之后还会看到, 所有在服务器执行过的写命令, 都会重新发送到 telnet 会话来。

即使有多个从服务器同时向主服务器发送 SYNC , 主服务器也只需执行一次 BGSAVE 命令, 就可以处理所有这些从服务器的同步请求。

从服务器可以在主从服务器之间的连接断开时进行自动重连, 在 Redis 2.8 版本之前, 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作, 但是从 Redis 2.8 版本开始, 从服务器可以根据主服务器的情况来选择执行完整重同步还是部分重同步(partial resynchronization)。

3、部分重同步

从 Redis 2.8 开始, 在网络连接短暂性失效之后, 主从服务器可以尝试继续执行原有的复制进程(process), 而不一定要执行完整重同步操作。

这个特性需要主服务器为被发送的复制流创建一个内存缓冲区(in-memory backlog), 并且主服务器和所有从服务器之间都记录一个复制偏移量(replication offset)和一个主服务器 ID (master run id), 当出现网络连接断开时, 从服务器会重新连接, 并且向主服务器请求继续执行原来的复制进程:

  1. 如果从服务器记录的主服务器 ID 和当前要连接的主服务器的 ID 相同, 并且从服务器记录的偏移量所指定的数据仍然保存在主服务器的复制流缓冲区里面, 那么主服务器会向从服务器发送断线时缺失的那部分数据, 然后复制工作可以继续执行。
  2. 否则的话, 从服务器就要执行完整重同步操作。

Redis 2.8 的这个部分重同步特性会用到一个新增的 PSYNC 内部命令, 而 Redis 2.8 以前的旧版本只有 SYNC 命令, 不过, 只要从服务器是 Redis 2.8 或以上的版本, 它就会根据主服务器的版本来决定到底是使用 PSYNC 还是 SYNC :

  1. 如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 PSYNC 命令来进行同步。
  2. 如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 SYNC 命令来进行同步。

4、配置

配置一个从服务器非常简单, 只要在配置文件中增加以下的这一行就可以了:

slaveof [ip address] [port]

另外一种方法是调用 SLAVEOF 命令, 通过redis客户端工具连接到从(slave)服务器,输入主服务器的 IP 和端口, 然后同步就会开始:

SLAVEOF [ip address] [port]

5、只读从服务器

从 Redis 2.6 开始, 从服务器支持只读模式, 并且该模式为从服务器的默认模式。

只读模式由 redis.conf 文件中的 slave-read-only 选项控制, 也可以通过 CONFIG SET 命令来开启或关闭这个模式。

只读从服务器会拒绝执行任何写命令, 所以不会出现因为操作失误而将数据不小心写入到了从服务器的情况。

即使从服务器是只读的, DEBUG 和 CONFIG 等管理式命令仍然是可以使用的, 所以我们还是不应该将服务器暴露给互联网或者任何不可信网络。 不过, 使用 redis.conf 中的命令改名选项, 我们可以通过禁止执行某些命令来提升只读从服务器的安全性。

你可能会感到好奇, 既然从服务器上的写数据会被重同步数据覆盖, 也可能在从服务器重启时丢失, 那么为什么要让一个从服务器变得可写呢?

原因是, 一些不重要的临时数据, 仍然是可以保存在从服务器上面的。 比如说, 客户端可以在从服务器上保存主服务器的可达性(reachability)信息, 从而实现故障转移(failover)策略。

6、从服务器相关配置

如果主服务器通过 requirepass 选项设置了密码, 那么为了让从服务器的同步操作可以顺利进行, 我们也必须为从服务器进行相应的身份验证设置。

对于一个正在运行的服务器, 可以使用客户端输入以下命令:

config set masterauth <password>

要永久地设置这个密码, 那么可以将它加入到配置文件中:

masterauth <password>

另外还有几个选项, 它们和主服务器执行部分重同步时所使用的复制流缓冲区有关, 详细的信息可以参考 Redis 源码中附带的 redis.conf 示例文件。

7、主服务器只在有至少 N 个从服务器的情况下,才执行写操作

从 Redis 2.8 开始, 为了保证数据的安全性, 可以通过配置, 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 才执行写命令。

不过, 因为 Redis 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的。

以下是这个特性的运作原理:

  1. 从服务器以每秒一次的频率 PING 主服务器一次, 并报告复制流的处理情况。
    主服务器会记录各个从服务器最后一次向它发送 PING 的时间。
  2. 用户可以通过配置, 指定网络延迟的最大值 min-slaves-max-lag , 以及执行写操作所需的至少从服务器数量 min-slaves-to-write 。
  3. 如果至少有 min-slaves-to-write 个从服务器, 并且这些服务器的延迟值都少于 min-slaves-max-lag 秒, 那么主服务器就会执行客户端请求的写操作。

你可以将这个特性看作 CAP 理论中的 C 的条件放宽版本: 尽管不能保证写操作的持久性, 但起码丢失数据的窗口会被严格限制在指定的秒数中。

另一方面, 如果条件达不到 min-slaves-to-write 和 min-slaves-max-lag 所指定的条件, 那么写操作就不会被执行, 主服务器会向请求执行写操作的客户端返回一个错误。

以下是这个特性的两个选项和它们所需的参数:

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

详细的信息可以参考 Redis 源码中附带的 redis.conf 示例文件。

以上内容摘自:http://doc.redisfans.com/topic/replication.html

8、Redis主从复制实战

安装两台虚拟机,虚拟机ip地址分别为:192.168.199.126,192.168.199.249(具体情况具体分析,以实际虚拟机ip地址为准)

在两台虚拟机中下载并安装Redis,具体可参考http://blog.youkuaiyun.com/zyhlwzy/article/details/78366265

将192.168.199.126上的Redis配置成master,所以配置很简单,我们开启守护进程即可。

进入redis配置文件目录(/data/redis/redis-4.0.1/redis.conf)。

# vi redis.conf

设置如下

daemonize yes

将192.168.199.249上的Redis配置成slave。

进入redis配置文件目录(/data/redis/redis-4.0.1/redis.conf)。

# vi redis.conf

设置如下:

daemonize yes
slaveof 192.168.199.126 6379

Master我们没设置密码,所以这儿也就不用设置Master的密码。

启动两台虚拟机中的Redis,成功启动之后,用Redis客户端工具连接到Master服务器。输入info replication命令可查看主从配置信息。

192.168.199.126:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.199.249,port=6379,state=online,offset=7237,lag=0
master_replid:4234e3e110e1acfcc89bcba0f204138f615d3d61
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:7237
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:7237

我们在master服务器上写入一条数据:

192.168.199.126:6379> set tfs 'hello replication'
OK
192.168.199.126:6379> get tfs
"hello replication"

在从(Slave)服务器上,我们通过get命令,也可以get到数据:

[root@localhost bin]# ./redis-cli -h 192.168.199.249 -p 6379
192.168.199.249:6379> get tfs
"hello replication"
<think>我们正在讨论Redis主从复制模式下Slave节点如何处理读请求,以及客户端如何路由读请求到Slave节点。根据引用[1]和[5],主从复制模式中,Master节点负责写操作,Slave节点负责读操作,实现读写分离。但是,Redis本身并不提供自动的路由机制,需要客户端或中间件来实现。具体分析:1.Slave节点处理读请求:Slave节点启动后会连接到Master节点同步数据,之后Master的数据变更会异步复制Slave。因此,Slave节点上的数据可能不是最新的(存在延迟,见引用[2])。客户端可以直接连接Slave节点执行读命令。2.客户端路由实现方式:a.手动配置:在客户端代码中,显式指定写操作发送到Master节点,读操作发送到Slave节点。例如,在Java中使用Jedis,可以创建两个连接池,分别指向MasterSlave,然后在业务代码中根据操作类型选择连接。b.代理中间件:使用如Twemproxy、Codis等代理,由代理层自动将读请求路由到Slave节点,写请求路由到Master节点。这样客户端只需连接代理,无需关心后端拓扑。c.支持读写分离的客户端库:一些高级的Redis客户端库(如Lettuce)内置了读写分离功能,通过配置主从节点地址,客户端库会自动路由请求。3.注意事项:-数据一致性:由于主从复制是异步的,Slave节点可能存在数据延迟。对于一致性要求高的场景,可能需要强制从Master读(引用[2]提到可以通过外部监控程序检测延迟,或者使用WAIT命令等待同步)。-负载均衡:如果有多个Slave节点,客户端或代理需要实现负载均衡(如轮询、随机等)来分配读请求。4.示例配置(引用[4]提到复制缓冲区配置,这会影响复制性能和延迟,但和客户端路由无关):在客户端实现读写分离的伪代码示例:```java//伪代码示例:使用两个连接池JedisPoolmasterPool=newJedisPool("master_ip",6379);JedisPoolslavePool=newJedisPool("slave_ip",6379);//写操作使用mastertry(Jedismaster=masterPool.getResource()){master.set("key","value");}//读操作使用slavetry(Jedisslave=slavePool.getResource()){Stringvalue=slave.get("key");}```或者使用Lettuce(支持读写分离):```javaRedisClientclient=RedisClient.create();StatefulRedisMasterSlaveConnection<String,String>connection=MasterSlave.connect(client,newUtf8StringCodec(),Arrays.asList(newRedisURI("master_ip",6379,30,TimeUnit.SECONDS),newRedisURI("slave1_ip",6379,30,TimeUnit.SECONDS),newRedisURI("slave2_ip",6379,30,TimeUnit.SECONDS)));connection.setReadFrom(ReadFrom.SLAVE);//设置读策略:优先从Slave读//使用连接时,写操作自动发往Master,读操作发往SlaveRedisCommands<String,String>commands=connection.sync();commands.set("key","value");//写操作发往MasterStringvalue=commands.get("key");//读操作发往Slave(根据策略选择一个)```总结:-Slave节点直接处理读请求,但数据可能不是最新。-客户端路由实现方式包括:手动配置、代理中间件、智能客户端库。-需要根据数据一致性要求和系统复杂度选择合适的方案。相关问题:1.Redis主从复制数据延迟如何监控和解决?2.如何配置RedisSentinel以实现自动故障转移和读写分离?3.RedisCluster模式下如何实现读写分离?</think>### Redis 主从复制模式:Slave 读请求处理与客户端路由实现 #### 一、Slave 节点处理读请求的机制 1. **读写分离架构** - **Master**:**独占写权限**(所有写操作必须发送到 Master- **Slave**:**只读副本**(接收客户端读请求,数据通过异步复制Master 同步)[^1][^5] - **数据一致性**:异步复制导致 Slave 数据可能**延迟**(取决于网络带宽和命令阻塞)[^2] 2. **Slave 读请求处理流程** ```mermaid sequenceDiagram Client->>Slave: 发送读请求 (GET key) Slave-->>Slave: 检查本地数据 alt 数据存在且最新 Slave->>Client: 返回数据 else 数据过期或不存在 Slave->>Master: 请求最新数据 Master->>Slave: 发送增量数据 Slave->>Client: 返回更新后数据 end ``` 3. **关键特性** - **无写权限**:Slave 拒绝所有写命令(返回 `READONLY` 错误) - **复制延迟容忍**:业务需能接受**最终一致性**(如商品展示页) - **负载分担**:多个 Slave 可**水平扩展读吞吐量**(理论上限 10万+/秒)[^3] #### 二、客户端路由实现方式 ##### 方式1:手动配置路由(基础方案) ```java // Java 伪代码示例 JedisPool masterPool = new JedisPool("master_ip", 6379); // 写连接池 JedisPool slavePool = new JedisPool("slave_ip", 6379); // 读连接池 public void handleRequest(String key, String value) { if (isWriteOperation()) { try (Jedis master = masterPool.getResource()) { master.set(key, value); // 写操作路由到Master } } else { try (Jedis slave = slavePool.getResource()) { String result = slave.get(key); // 读操作路由到Slave } } } ``` **缺点**:需业务代码显式区分读写,故障转移需手动干预[^4] ##### 方式2:代理中间件(推荐生产使用) - **常用工具**:Twemproxy、Predixy、AWS ElastiCache Proxy - **路由逻辑**: ```mermaid graph LR Client-->Proxy Proxy-->|Write| Master Proxy-->|Read| Slave1 Proxy-->|Read| Slave2 ``` - **配置示例**(Predixy): ```yaml # predixy.conf ProxyServer: Bind: 0.0.0.0:6379 ClusterServerPool: Master: 192.168.1.10:6379 # Master节点 Slaves: - 192.168.1.11:6379 # Slave节点1 - 192.168.1.12:6379 # Slave节点2 ReadStrategy: RoundRobin # 读负载均衡策略 ``` ##### 方式3:智能客户端库(现代方案) - **支持库**:Lettuce(Java)、redis-py-cluster(Python)、go-redis(Go) - **Lettuce 示例**: ```java List<RedisURI> nodes = Arrays.asList( RedisURI.create("redis://master:6379"), RedisURI.create("redis://slave1:6379"), RedisURI.create("redis://slave2:6379") ); RedisClient client = RedisClient.create(); StatefulRedisMasterSlaveConnection<String, String> connection = MasterSlave.connect(client, StringCodec.UTF8, nodes); connection.setReadFrom(ReadFrom.SLAVE); // 设置读策略:优先Slave RedisCommands<String, String> commands = connection.sync(); commands.set("key", "value"); // 自动路由到Master String value = commands.get("key"); // 自动路由到Slave ``` **优势**:自动感知拓扑变化,支持读写分离策略配置[^5] #### 三、关键优化策略 1. **降低复制延迟** - 增大复制缓冲区:`repl-backlog-size 256mb`(默认1MB)[^4] - 网络优化:主从节点同机房部署,万兆网络 - 监控延迟:使用 `INFO replication` 查看 `slave_repl_offset` 2. **读负载均衡** ```mermaid pie title 读请求分配策略 “轮询(RoundRobin)” : 45 “权重(Weighted)” : 30 “就近路由(Geo)” : 25 ``` 3. **一致性保障** - **强制读Master**:对一致性要求高的操作,客户端显式指定读Master - **WAIT命令**:`WAIT <numreplicas> <timeout>` 等待N个副本同步(牺牲性能)[^2] #### 四、适用场景与限制 | 场景 | 适用性 | 说明 | |---------------------|--------|--------------------------| | 读密集型应用 | ★★★★★ | 电商商品列表、资讯类网站 | | 写后立即读 | ★★☆☆☆ | 需配合WAIT或强制读Master | | 跨地域部署 | ★★★☆☆ | 需考虑网络延迟 | | 强一致性要求 | ★☆☆☆☆ | 建议改用Redis Cluster | > **最佳实践**: > 1. 读请求占比 >80% 时使用主从复制 > 2. 使用代理或智能客户端减少代码侵入 > 3. 监控 `master_link_down_since_seconds` 和 `lag` 指标
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RonTech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值