背压需下游显式驱动而非默认启用,缺失将导致内存溢出;应排查无界缓冲、未调用request、不兼容操作符等问题,并采用onbackpressuredrop等兜底策略及limitrate等长期设计方式。

核心问题在于:背压不是默认开启的“自动安全阀”,而是必须由下游显式驱动的请求机制。没配置,就等于放任上游全速发射——内存爆掉只是时间问题。
确认是否真因背压缺失导致内存膨胀
先排除其他干扰因素:
- 检查是否用了 无界缓冲操作符(如未设容量的
onBackpressureBuffer()或publishOn(Schedulers.parallel())默认队列) - 确认订阅者有没有调用
request(n)—— 比如自定义BaseSubscriber忘了在hookOnSubscribe里首次请求 - 观察是否在链路中混用了不支持背压的操作符(例如某些第三方
Flux.create封装未检查sink.requestedFromDownstream()) - 用
.log()插入关键节点,看onRequest信号是否发出、何时中断
立即生效的兜底配置策略
针对已上线服务,优先加一层防御性操作符,避免OOM:
审查 React Router 代码,确保数据加载、变更、错误处理和导航模式符合规范,适用于 React Router v6.4+ 代码、加载器及其他特性。
-
用
onBackpressureDrop():适合日志、埋点、监控等允许丢失的流。新数据来时若无人请求或缓冲满,直接丢弃 -
用
onBackpressureLatest():适合状态类流(如设备心跳、用户在线状态),只保留最新值,旧值自动覆盖 -
用
onBackpressureBuffer(capacity, ...):必须指定明确容量(如1024),并配BufferOverflowStrategy.DROP_OLDEST或DROP_LATEST防止溢出时抛异常
示例(防止百万级消息堆积):
Flux.range(1, 1_000_000).onBackpressureDrop(d -> logger.warn("Dropped: {}", d))
.publishOn(Schedulers.boundedElastic())
.subscribe(data -> { /* 处理 */ });
长期健壮的背压设计方式
不能只靠兜底,要让整个链路尊重背压契约:
- 用
limitRate(n)替代手动 request:它会在每次消费完 n 个后自动补发 request(n),适合大多数批处理场景 - 自定义发布者(如
Flux.create)必须主动轮询sink.requestedFromDownstream(),返回 ≤0 时暂停发射 - 避免
request(Long.MAX_VALUE)—— 这等于关闭背压,退化为火球式推送 - 慎用
flatMap:默认并发数 256,可能放大背压断裂风险;改用flatMapSequential或显式设concurrency=1
验证与监控建议
上线后需确认背压真正起效:
- 通过
Micrometer暴露reactor.buffer.size、reactor.drop.count等指标 - 在测试环境模拟慢消费者(如
Thread.sleep(100)),观察是否稳定在设定速率 - 用
VirtualTimeScheduler单元测试背压行为,验证 request 节奏是否符合预期










