project reactor背压本质是下游通过request(n)显式控制数据接收时机与数量;需手动调用或借助limitrate等操作符触发,忽略则流停滞,滥用long.max_value则关闭背压;onbackpressurexxx处理缓冲溢出,自定义发布者须检查requestedfromdownstream,链路中flatmap等操作符可能破坏背压完整性。

Project Reactor 中的变量流背压控制,本质是让下游决定“什么时候收、收多少”,而不是上游一股脑地发。关键不在数据本身,而在 request(n) 这个请求信号——它驱动整个流的节奏。
背压不是自动发生的,而是靠 request(n) 显式触发
Flux 或 Mono 的订阅一旦建立,初始时下游没有发出任何请求,上游默认不发送任何数据。只有调用 subscription.request(n),上游才开始推送最多 n 个元素。这个动作可以多次发生,比如处理完一批再要下一批。
- 手动控制最典型:继承
BaseSubscriber,在hookOnSubscribe里首次request(1),在hookOnNext处理完再request(1)实现逐个拉取 - 自动封装常见:使用
limitRate(10)等操作符,底层仍是周期性调用request(10) - 注意:如果忘了 request,流就卡住不动;如果 request(Long.MAX_VALUE),等于关闭背压,退化为无控推送
onBackpressureXXX 系列操作符解决“发太快、收太慢”时的溢出问题
当上游已按需发射,但下游处理延迟导致缓冲区堆积(例如 publishOn 切换线程后消费变慢),就需要策略性处理“已发出但未被消费”的数据。Reactor 提供几种预置策略:
-
onBackpressureBuffer():把来不及处理的数据暂存在内存队列中,适合短时突发、内存可控场景;但要注意设置容量上限,否则仍可能 OOM -
onBackpressureDrop():新数据到达时若缓冲区满或无人请求,直接丢弃;适合日志、监控等允许丢失的流 -
onBackpressureLatest():只保留最新一条未消费数据,旧的全丢;典型用于传感器状态更新,只关心当前值 -
onBackpressureError():缓冲区满时立即终止流并抛出异常;适合强一致性要求、不容错过的业务流
变量流(如 Flux.create)必须自己尊重 requestedFromDownstream
自定义发布者(比如用 Flux.create 封装第三方 SDK 或事件源)最容易忽略背压。它不会自动感知下游请求量,必须主动检查 sink.requestedFromDownstream() 再决定是否发射:
- 返回值 ≤ 0:说明下游还没 request 或已取消,应暂停发射
- 返回值 > 0:可安全发射最多该数量的数据,且每次
sink.next()后建议递减计数 - 不检查这个值,就等于绕过背压机制,可能造成内存泄漏或数据丢失
背压效果依赖完整链路,中间操作符可能破坏它
某些操作符会隐式改变请求行为,导致背压失效或失真:
-
flatMap默认并发度 256,内部每个内层流都独立 request,容易放大总请求数,建议显式设flatMap(..., 4) -
bufferTimeout或sample类操作符可能跳过部分数据,不体现真实消费节奏 - 混用阻塞调用(如
block()、Thread.sleep())会让线程挂起,间接冻结 request 流动,应改用delayElements等非阻塞替代











