Redis Sentinel是官方提供的高可用方案,它通过一组独立的Sentinel进程监控主从节点,在master不可用时自动完成故障检测、选举和切换。但很多人忽略了一点:Sentinel只负责服务端的切换,客户端必须以正确的姿势接入,才能真正享受高可用能力。如果客户端把连接地址写死成master的IP和端口,那么切换发生的那一刻,所有写请求都会打到一台已经降级为slave(甚至已经下线)的机器上,业务直接报错。这篇文章就来聊聊客户端侧到底该怎么配置。

一、先搞清楚Sentinel模式下客户端的工作机制
在传统主从模式下,客户端只需要知道master的地址。而在Sentinel架构中,客户端的连接流程发生了本质变化:它先连接Sentinel节点(注意是Sentinel,不是数据节点),通过执行SENTINEL get-master-addr-by-name mymaster命令获取当前master的真实地址,然后再与这个master建立连接进行读写。这个过程可以理解为“问路”——Sentinel知道谁是当前的主节点,客户端每次初始化时都要先问一遍。
一个容易被忽略的细节是:客户端需要订阅Sentinel的+switch-master频道。当故障切换完成后,Sentinel会向该频道发布消息,告知新的master地址。订阅了这个频道的客户端能在秒级感知到切换并重建连接池;而没有订阅机制的客户端只能依赖连接报错后的重试,感知速度会慢很多,期间还会产生大量失败请求。成熟的客户端库(如Lettuce、go-redis)内部都实现了这套订阅逻辑,这也是为什么强烈建议使用官方或社区维护完善的库,而不是自己手写Socket连接。
另外要理解Sentinel的判定条件。默认配置下,一个Sentinel需要down-after-milliseconds时间内连续收不到master响应才会标记其主观下线,再需要达到quorum个Sentinel同意才会判定客观下线,之后还要经过选举和切换流程。整个过程通常需要十几秒到几十秒,客户端的重试策略必须覆盖这个时间窗口,否则切换期间的用户请求会大量失败。
二、主流客户端的配置代码示例
1. Java环境:Jedis与Lettuce
Jedis是老牌客户端,配置Sentinel时通过JedisSentinelPool完成,需要传入Sentinel节点集合和master名称:
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.10:26379");
sentinels.add("192.168.1.11:26379");
sentinels.add("192.168.1.12:26379");
String masterName = "mymaster";
String password = "yourPassword";
JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels,
new JedisPoolConfig(), 2000, 2000, password);
try (Jedis jedis = pool.getResource()) {
jedis.set("demo:key", "hello");
System.out.println(jedis.get("demo:key"));
}
注意这里的地址必须是Sentinel的地址,而不是master地址,这是新手最常见的错误。JedisSentinelPool会从Sentinel查询master地址并维护连接池,切换时会自动刷新。
如果用的是Spring Boot加Lettuce(默认组合),配置更简洁,直接在application.yml中写:
spring:
redis:
password: yourPassword
sentinel:
master: mymaster
nodes:
- 192.168.1.10:26379
- 192.168.1.11:26379
- 192.168.1.12:26379
timeout: 2000
Lettuce基于Netty实现,连接是线程安全的单个共享连接,并且内置了对Sentinel事件频道的订阅,故障切换的感知速度比Jedis更快。生产环境一般推荐这个组合。
2. Go环境:go-redis
go-redis的v9版本对Sentinel支持很完善,配置时使用FailoverClient模式:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"192.168.1.10:26379", "192.168.1.11:26379", "192.168.1.12:26379"},
Password: "yourPassword",
DialTimeout: 3 * time.Second,
ReadTimeout: 2 * time.Second,
MaxRetries: 3,
})
val, err := rdb.Get(context.Background(), "demo:key").Result()
fmt.Println(val, err)
}
如果还需要读写分离,把NewFailoverClient换成NewFailoverClusterClient,它会自动发现slave节点并将读命令路由过去。要注意写命令依然只会发往master,不要指望读写分离能分担写压力。
3. Python环境:redis-py
redis-py从3.x开始推荐使用redis.asyncio或同步客户端的Sentinel封装:
from redis.sentinel import Sentinel
sentinel = Sentinel(
[("192.168.1.10", 26379), ("192.168.1.11", 26379), ("192.168.1.12", 26379)],
socket_timeout=2,
)
master = sentinel.master_for("mymaster", password="yourPassword")
master.set("demo:key", "hello")
slave = sentinel.slave_for("mymaster", password="yourPassword")
print(slave.get("demo:key"))
这里的master_for和slave_for返回的客户端会在每次操作前检查连接可用性,故障切换后能自动指向新的master。不过要注意slave_for读到的数据可能有复制延迟,对一致性敏感的读操作仍然走master更稳妥。
三、配置中的常见坑与排查思路
1. Sentinel自身设置了密码怎么办
较新版本的Redis支持给Sentinel进程单独设置密码(配置项为requirepass),这时候客户端连接数据节点和连接Sentinel需要两个不同的密码。以go-redis为例,数据节点密码用Password字段,Sentinel密码用SentinelPassword字段。Jedis方面,需要在构造函数中分别传入这两个参数,版本太老的Jedis不支持这个特性,遇到认证失败又确认密码正确时,先升级客户端版本再排查。
2. 连接超时与重试策略要覆盖切换窗口
故障切换完成前,master地址实际上是失效的。客户端的超时设置过短会导致大量请求快速失败,设置过长又会让用户等待过久。实践经验是:连接超时控制在1到3秒,命令超时1到2秒,并配合3次左右的指数退避重试。这样单个请求最多重试几秒,正好能扛过切换窗口。同时在业务代码里,对写操作要做好幂等设计,因为重试可能导致同一条数据被写入两次。
3. 网络与防火墙问题
Sentinel默认端口是26379,客户端部署环境必须能访问所有Sentinel节点的26379端口以及数据节点的6379端口。有一个隐蔽的坑:Sentinel会在故障切换后主动用SENTINEL announce-ip或自动发现的地址广播新的master地址,如果Redis服务器有多块网卡,它可能广播一个客户端无法路由的内网地址。解决办法是在redis.conf中显式配置replica-announce-ip和replica-announce-port,或者给Sentinel配置announce-ip,确保广播出去的地址客户端可达。
4. 验证配置是否生效
配置完成后,建议做一次切换演练:用redis-cli -p 6379 shutdown nosave直接关掉master,观察客户端日志中是否出现重连记录,业务是否在十几秒后自动恢复。也可以通过redis-cli -p 26379 sentinel masters查看Sentinel记录的master地址是否已经更新。演练通过的高可用配置才算真正可用,否则上线后第一次故障就是事故现场。
四、几点最佳实践总结
第一,Sentinel节点至少部署3个且分布在不同的物理机或可用区,quorum一般设为节点数的一半加一,避免脑裂。第二,客户端配置里写Sentinel地址列表而非master地址,并且把所有Sentinel都列上,单个Sentinel挂掉不影响客户端发现master。第三,读写分离要谨慎,复制延迟在没有强一致要求的场景(如缓存、统计)下才适合走slave。第四,监控不能少,对sdown、odown、+switch-master等事件配置告警,切换发生时运维能第一时间知道,而不是等用户投诉才发现。把这些细节都处理好,Sentinel方案才能真正为业务提供稳定的高可用保障。
Redis Sentinel客户端配置高可用修改时间:2026-09-16 10:06:54