docker compose中redis发布订阅必须用服务名通信,因pub/sub依赖长连接且redis回连时需可达地址;填ip或127.0.0.1会导致消息静默丢弃,且redis容器必须bind 0.0.0.0并启用同一自定义网络。

直接用服务名通信,别填IP——这是 Docker Compose 下 Redis 发布订阅能跑通的唯一前提。填宿主机 IP、容器 IP 或 127.0.0.1 全都会失败,不是连不上,就是订阅收不到消息。
为什么发布订阅在 Compose 里总收不到消息
Redis 的 PUB/SUB 机制依赖客户端与服务端之间**长连接维持**,而该连接一旦建立,后续所有消息都走这条通道。当客户端(比如 Spring Boot 应用)用错误地址(如 127.0.0.1 或宿主机 IP)连接 Redis 时,虽然初始 CONNECT 可能成功(尤其开了 bind 0.0.0.0),但 Redis 在向订阅者推送消息时,会尝试回连客户端的“来源地址”——这个地址在容器网络里根本不可达,导致消息静默丢弃。
常见错误现象包括:
- 客户端执行
SUBSCRIBE channel后无报错,但PUBLISH消息后始终没回调 -
redis-cli -h 192.168.x.x能连上、能 set/get,但SUBSCRIBE卡住或无响应 - 日志里反复出现
Client closed connection或read error,但没明确异常堆栈
Spring Boot 配置必须用 redis 服务名
在 application.yml 中,spring.redis.host 值必须严格等于 docker-compose.yml 里定义的 Redis service 名称,不能是 IP、不能是 localhost、不能是 host.docker.internal(除非你额外配置了 DNS 解析)。
例如你的 docker-compose.yml 是:
services:
cache:
image: redis:7.0
container_name: redis-cache
ports:
- "6379:6379"
那么 Spring Boot 就必须配:
spring:
redis:
host: cache # ✅ 正确:服务名
port: 6379
而不是:
-
host: localhost❌(指向容器自身) -
host: 172.20.0.3❌(IP 重启即变,且跨网络不可靠) -
host: host.docker.internal❌(仅 macOS/Windows 有效,Linux 默认不支持)
Redis 容器内必须监听 0.0.0.0
默认 Redis 镜像启动时只 bind 127.0.0.1,这在 Compose 网络下会导致其他容器无法建立连接。必须显式覆盖配置,让 Redis 监听全部接口。
推荐做法是挂载自定义 redis.conf,关键项为:
bind 0.0.0.0 protected-mode no port 6379
或者用 command 覆盖启动参数:
services:
cache:
image: redis:7.0
command: redis-server --bind 0.0.0.0 --protected-mode no
不加这两项,即使服务名对了,redis-cli -h cache SUBSCRIBE test 也会卡住或报 Connection refused。
测试发布订阅必须在同一个 Compose 网络里
用 redis-cli 测试时,不能在宿主机直接运行 redis-cli -h 127.0.0.1,因为那走的是宿主机端口映射,不是容器间直连——PUB/SUB 通道会被 NAT 或代理层干扰。
正确方式是进到任意一个同网络的容器里测试:
-
docker-compose exec app sh(进你的应用容器) - 再执行:
redis-cli -h cache SUBSCRIBE mychannel - 另开一个终端:
docker-compose exec cache redis-cli PUBLISH mychannel "hello"
如果用宿主机 redis-cli 测试,哪怕连上了,也大概率收不到消息——这不是 bug,是网络模型决定的边界行为。
最容易被忽略的一点:PUB/SUB 不是「发一次就保证送达」的协议,它只保证「在线订阅者实时收到」。如果你先 PUBLISH 再 SUBSCRIBE,消息就丢了;容器重启后没自动重连逻辑,也会断订。这些不是网络配置问题,但常被误判为 IP 映射失败。











