Redis PUB/SUB在K8s中不能用ClusterIP Service,因其长连接+服务端主动推送模型与kube-proxy无状态转发冲突,导致静默断连;必须用Headless Service+StatefulSet+publishNotReadyAddresses和定制readinessProbe实现稳定直连。

Redis 的 PUB/SUB 模式在 Kubernetes 里不能直接用 ClusterIP Service,这不是配置没写对的问题,而是模型冲突——它根本就跑不通。
为什么 ClusterIP Service 会让 SUBSCRIBE 静默断连?
因为 Redis 的订阅连接是长 TCP 连接,服务端主动往这个连接上持续写数据;而 ClusterIP 背后是 kube-proxy 做的无状态四层转发,不维护连接状态。结果就是:
- 连接空闲超时(比如云厂商 SLB 默认 60s 断连)后,客户端收不到新消息,但也不报错
- 滚动更新 Redis Pod 时,旧连接不会被主动关闭,新消息发到已销毁的 Pod 上,客户端彻底卡死
-
sessionAffinity: ClientIP没用——它只影响新建连接分发,对已建立的 SUB 连接零作用,还可能把多个订阅压到同一 Pod 上
必须用 Headless Service + StatefulSet
核心目标不是“暴露端口”,而是让客户端能稳定直连某个 Pod 的 IP。这需要三件事同时成立:
-
StatefulSet:确保每个 Redis 实例有固定名字和 DNS 可解析地址,比如redis-0.redis-headless.default.svc.cluster.local -
Headless Service(clusterIP: None):禁用 kube-proxy 转发,让 DNS 直接返回 Pod IP 列表 -
publishNotReadyAddresses: true:否则 Pod 启动中(readiness probe 还没通过)时 DNS 记录为空,客户端connect refused
示例关键字段:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
apiVersion: v1
kind: Service
metadata:
name: redis-headless
spec:
clusterIP: None
publishNotReadyAddresses: true
selector:
app: redis
ports:
- port: 6379readinessProbe 怎么写才真正有用?
别用 INFO 或 PING 命令——它们只说明进程活着,不保证 SUBSCRIBE 能正常工作。真实可用的探针要验证:
- TCP 端口可达
- Redis 进程响应命令(非阻塞)
- 最好避开主从同步延迟影响(比如不查
role字段)
推荐写法:
readinessProbe:
exec:
command:
- sh
- -c
- redis-cli --raw -h $(hostname -i) -p 6379 PING | grep -q 'PONG'外部客户端怎么连?
跨 Namespace 或集群外访问,不能靠 ClusterIP 或普通 NodePort。必须:
- 用
LoadBalancer类型 Service,并确认底层负载均衡器支持 TCP 长连接保活(AWS NLB、阿里云 CLB 的 TCP 监听可配 idle timeout ≥ 300s) - 或手动配置
externalIPs,指向某台 Node 的 IP,且该 Node 上运行了对应 Pod(需配合反亲和性调度) - 客户端连接字符串必须指定具体 Pod DNS 名(如
redis-0.redis-headless.default.svc.cluster.local:6379),不能只写 Service 名
复杂点在于:你得让业务代码知道该连哪个 Pod。如果用 Python 的 redis-py,就得自己做 Pod 列表发现+健康检查+重试,而不是扔给 ConnectionPool 自动轮询。

















