报错“redis: cluster has no slots assigned”根本原因是redis集群未真正运行,而非代码错误;必须确保6节点(3主3从)已通过redis-cli --cluster create正确启动,且cluster nodes显示至少3个master状态为connected,golang客户端须用redis.newclusterclient并配置至少2个可连通主节点地址。

go-redis 连 Redis 集群失败,报错 redis: cluster has no slots assigned
这基本不是代码问题,而是集群根本没跑起来。Redis 集群要求至少 6 个节点(3 主 3 从)才能完成握手并分配 slot,少一个就卡在初始化。
- 用
redis-cli --cluster create启动集群,别手写redis.conf拼凑 - 启动后立刻执行
redis-cli -c -p 7000 CLUSTER NODES,确认输出里有至少 3 个master且状态为connected - Golang 客户端必须用
redis.NewClusterClient,传入Addrs至少含 2–3 个可连通的 master 地址(如[]string{"127.0.0.1:7000", "127.0.0.1:7001"}),不能只填一个 - Docker 环境里避免用
localhost,改用host.docker.internal或宿主机实际 IP
用 Go 模拟网络丢包和延迟做分布式协调服务压测
真实丢包难复现,但用本地代理层注入延迟 + 随机错误,就能覆盖大部分通信异常路径。不需要改业务逻辑,也不依赖外部工具。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 起一个带可控延迟的反向代理,用
httputil.NewSingleHostReverseProxy实现,在RoundTrip中time.Sleep模拟延迟,或按概率return nil, errors.New("timeout")模拟丢包 - 测试客户端指向该代理(如
http://localhost:8081),后端服务跑在另一端口(如:8082) - 配合
http.Client的细粒度超时:设置Timeout(总耗时)、Transport.DialContext.Timeout(建连)、Transport.ResponseHeaderTimeout(首字节) - 丢包场景下,重点观察
context.DeadlineExceeded和net.OpError是否被正确捕获并触发重试
SetReadDeadline 和 SetWriteDeadline 在分布式协调中为什么不能省略
TCP 自身虽有重传机制,但应用层不设 deadline 就等于把“等多久”完全交给内核——可能卡住几十秒甚至更久,导致 etcd 或 ZooKeeper 类服务的心跳超时、会话失效、节点误判下线。
- 每个读/写操作前都调用
conn.SetReadDeadline和conn.SetWriteDeadline,时间建议 ≤ 心跳间隔的 1/3(如心跳 3s,则 deadline 设 1s) - 不要只在连接建立时设一次;每次 I/O 前都要重置,否则过期后后续操作直接失败
- 注意:UDP 连接不支持 deadline,若用 UDP 做协调通信(如某些自研协议),需自己实现超时+重发
重试逻辑里 SetMaxRetries 和指数退避怎么配才不雪崩
简单 for 循环重试在高并发下容易放大故障,尤其当后端已过载时。go-redis 的 SetMaxRetries 是开关,但真正起作用的是退避策略。
-
SetMaxRetries(2)是底线,但必须配合自定义RetryBackoff函数,返回每次重试前 sleep 时间 - 推荐指数退避:第 1 次重试前 sleep 10ms,第 2 次 30ms,第 3 次 100ms(而非固定 100ms × 3)
- 幂等性是前提:对
SET、GET可重试;但INCR、LPUSH等非幂等操作,重试前得先查状态或加唯一 key 标识 - 别在重试里无脑重连:连接对象复用比新建更稳,除非明确收到
connection refused或i/o timeout
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










