go-redis PubSub 连到端口 0,核对 TLS 集群地址
TLS-only Redis 集群普通命令正常,PubSub 却拨向端口 0。核对 CLUSTER SLOTS 与实际节点地址,采用包含零端口处理的客户端,保留 TLS 和原有订阅恢复流程。
Redis 集群的 GET、SET 正常,PubSub 却在建立连接时报告下面这样的错误,先看地址最后的端口:
dial tcp 172.30.0.12:0: connect: connection refused
这里的 IP 是示例。若实际日志同样拨向 :0,继续增加重试次数或等待时间不会把它变成正确的 TLS 端口。需要核对客户端取得的集群拓扑,以及建立订阅连接时最终使用的地址。
这类症状出现在 go-redis v9.18.0 的 TLS-only 集群环境中。服务器用 port 0 关闭普通 TCP 监听,另用 tls-port 提供连接;种子地址可以正常访问,不代表拓扑中的每个节点地址都能直接拨号。
先对应端口来自哪一层
保留应用实际使用的 go-redis 版本、种子地址,以及发生错误时收到的 CLUSTER SLOTS 节点地址。有权限时,通过原有 TLS 和认证连接取得该只读拓扑;不要把密码放进要分享的命令行或日志。
还要区分 CLUSTER SLOTS 与 CLUSTER SHARDS。后者包含 port、tls-port 等字段,不能只看到它提供了 TLS 端口,就认为当前客户端的订阅路径已经采用了这个字段。
v9.18.0 的 newClusterState 会把 CLUSTER SLOTS 返回的节点地址交给节点客户端。它处理了部分回环主机地址,却没有把端口 0 替换为可连接端口。PubSub 直接使用节点客户端地址建立连接时,这个值就可能出现在拨号错误里。
如果当时的实际 SLOTS 地址全都正确,而只有另一层产生了 :0,还需要追查地址转换或上层包装。不能仅凭同一条错误,就把所有故障归到这段旧代码。
采用包含零端口处理的正式客户端
正式 v9.23.0 已有 replaceZeroPort:节点公布的端口是 0 时,使用获取这份拓扑的 origin 地址端口。非零端口保持原样;origin 端口不存在或也是 0 时,不会凭空猜测一个端口。
这项处理依赖一个前提:通过 origin 端口访问对应节点在当前部署中确实可行。节点使用不同端口、端口映射或代理规则的环境,应继续核对每个最终地址,不把所有节点一律硬改为 6379。
选择 v9.23.0 前还要核对 Go 工具链,该模块要求 Go 1.26。升级应沿项目既有依赖管理和兼容性验证进行,保留认证、TLS 校验、协议选择及连接池配置。不要为了绕过 :0 开启原来关闭的明文监听,也不要关闭证书验证。
如果 go-redis 藏在另一个产品的发布包里,应采用确实更新了依赖的产品版本;仅更新机器上的 Go,不能替换已经编进旧二进制的客户端。
验收订阅连接,不能只做 PING
在获准的测试集群上,用原来的 TLS 配置建立独立订阅连接,确认实际拨号端口、订阅确认及消息接收,再覆盖断线后的重新订阅。GET 或 PING 正常只能验证相应命令路径,不能代替 PubSub 检查。
若订阅连接已经建立,确认帧却一直不返回,症状已不同,可再检查go-redis 短订阅确认的预读问题。一个是拨错地址,一个是完整回复到达后仍被读取器等待,不应混用处理办法。
恢复连接不能补回断开期间的普通 Pub/Sub 消息。业务需要补偿时,继续按原有消息持久化或确认机制核对,不把连接恢复算成历史消息也恢复了。


