redis pub/sub单条消息安全上限为100kb,因主线程串行处理序列化、拷贝、遍历订阅者及发送,超限会导致get/set等命令排队阻塞;proto-max-bulk-len不解决该问题,需预检原始bytes长度并采用轻量通知+按需拉取或迁移到stream。

Redis Pub/Sub 单条消息实际安全上限是 100KB,不是配置能改出来的“理论值”。
为什么 100KB 是硬门槛,而不是 warning
Redis 处理 PUBLISH 命令时完全不校验大小,所有操作(序列化、内存拷贝、遍历每个订阅者、逐个发送)都在单线程里串行执行。一个 2MB 的 JSON 消息可能让主线程卡住 200ms 以上——期间 GET、SET、甚至 PING 全部排队。这不是慢,是“独占”。监控上会看到 redis-cli --stat 中 pubsub_channels 内存持续上涨,INFO memory 的 used_memory_dataset 异常跳升。
-
proto-max-bulk-len默认 512MB,但别信这个数字——它只管协议层解析,不管主线程是否被拖死 - 真正起作用的是行为限制:主线程必须把整条消息处理完才能干别的事
- 100KB 是大量压测后确认的“不明显影响其他命令响应”的经验阈值
client-output-buffer-limit pubsub 不是消息大小限制,而是缓冲区保护
很多人误以为调大 client-output-buffer-limit pubsub 就能发大消息,其实它管的是“订阅端没及时读走的消息在 Redis 内存里能存多少”。默认配置 client-output-buffer-limit pubsub 8mb 2mb 60 含义是:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 单个订阅连接输出缓冲区超过 8MB → 立即断连
- 或持续 60 秒超过 2MB → 断连
- 这个限制和
PUBLISH消息体大小无关,只和消费速度、网络吞吐、客户端处理延迟有关 - 哪怕你发的是 1KB 消息,如果订阅端每秒只处理 5 条,积压 3000 条也照样触发断连
订阅端预检必须在反序列化之前
很多 Python 代码写成 json.loads(msg["data"]) 后再判断长度,这已经晚了:大对象早已分配,GC 压力陡增,OOM 风险拉满。正确姿势是拿到原始 bytes 后立刻测长:
if len(data) > 102400: # 100KB
logger.warning("drop oversized")
continue
- 禁用自动解码(如 redis-py 的
decode_responses=True) - 用
redis.Redis(decode_responses=False)获取 raw bytes - 检查必须在
json.loads()或pickle.loads()之前
真要传大数据,别硬扛 Pub/Sub
拆成多个 PUBLISH 发到不同频道(比如 order:12345:part1)反而更危险:订阅端要维护状态、拼顺序、做超时重试,出错概率翻倍,且单条 PUBLISH 还是会卡主线程。可靠做法只有两种:
- 发布端只发轻量通知:
PUBLISH order:updated '{"id":"12345","ts":1716645720}',订阅端异步查GET order:12345或调 API - 必须保序+防丢+分片?直接迁移到
Stream,用XADD+XREADGROUP,天然支持 ACK 和重试
最易被忽略的一点:Pub/Sub 本身不持久、无 ACK、不保证送达。所谓“调大缓冲区”只是延缓断连,解决不了根本问题——消息体越大,系统越脆弱,越不像一个通信机制,越像一个定时炸弹。










