因为哨兵只响应sentinel指令,不处理get等redis数据命令,协议不匹配导致err unknown command 'get';必须用newfailoverclient自动连接哨兵、获取主节点并监听故障转移事件,不可用newclient直连哨兵地址。

为什么用 NewClient 连哨兵地址会报 ERR unknown command 'GET'
因为哨兵节点只响应 SENTINEL 指令(比如 SENTINEL GET-MASTER-ADDR-BY-NAME),不处理 GET、SET 这类 Redis 数据命令。你用 redis.NewClient(&redis.Options{Addr: "127.0.0.1:26379"}) 直连哨兵端口,协议不匹配,自然返回 ERR unknown command 'GET' 或连接被拒绝。
真正该做的是让客户端主动跟哨兵“对话”,拿到当前主节点地址后再连过去——这个逻辑封装在 redis.NewFailoverClient 里,不是手动拼地址能替代的。
-
MasterName必须和哨兵配置中sentinel monitor mymaster 127.0.0.1 6379 2的第一个参数完全一致(大小写敏感),填错会导致初始化时反复打印failed to resolve master -
SentinelAddrs填的是哨兵节点地址列表,端口默认26379,不是 Redis 实例的6379 - 至少填一个哨兵地址,但生产环境建议写全,比如
[]string{"10.0.1.10:26379", "10.0.1.11:26379", "10.0.1.12:26379"},避免单点失效
Gin 启动时怎么确认哨兵连接真生效了
仅调 rdb.Ping(ctx).Err() 成功不代表高可用已就绪——它可能只是连上了某个哨兵,还没拉到主节点地址,或者主已切换但客户端没收到 +switch-master 事件。
可靠验证方式:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 启动后立刻查日志,确认有没有类似
resolved master mymaster -> 10.0.1.20:6379的输出 - 手动
kill当前主 Redis 进程,观察 Gin 接口是否在几秒内自动恢复写入(而不是持续报connection refused) - 用
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster对比客户端实际使用的地址是否一致
最容易被忽略的是哨兵配置里的 quorum 值(比如 sentinel monitor mymaster 127.0.0.1 6379 2 中的 2)必须 ≤ 实际运行的哨兵数,否则故障转移根本不会触发。
哨兵模式下密码和用户名怎么配才不丢请求
哨兵和 Redis 实例的认证是两套独立体系,填错一个字段就会卡在初始化或后续操作失败。
- 如果哨兵启用了认证,必须设
SentinelPassword;Redis 主从自己的密码是另一个字段Password,别混在一起 -
Username在哨兵模式下仅对 Redis 6+ ACL 生效,且需额外配SentinelUsername(哨兵自己的用户)和Username(Redis 实例的用户),两者不同源 - 密码字段不能多空格,
""和" "效果完全不同
Gin 中初始化 Redis 客户端的典型写法
别在 handler 里每次新建 client,必须在 Gin 启动时初始化并注入全局或通过依赖注入传递。
func initRedis() *redis.Client {
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"10.0.1.10:26379", "10.0.1.11:26379"},
SentinelPassword: "sentinel-pass",
Password: "redis-pass",
Username: "default", // Redis 6+ ACL 用户
SentinelUsername: "sentinel-user",
DB: 0,
MaxRetries: 3,
MinRetryBackoff: 8 * time.Millisecond,
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := rdb.Ping(ctx).Err(); err != nil {
log.Fatal("redis ping failed:", err)
}
return rdb
}
注意:DB 字段有效,但 Username 和 SentinelUsername 必须同时存在才能支持 ACL 场景;MaxRetries 和 MinRetryBackoff 决定重连节奏,主节点恢复慢时可能来不及切回来,得按业务容忍调整。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










