[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fWVg4n5GaKz2KAepqsbH9HgVjaYOm1Oyeuy8KcCfCJxo":3},{"item":4,"related":48},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":41,"status":42,"seoTitle":7,"seoDescription":9,"canonicalUrl":39,"isFeatured":43,"sno":44,"sortOrder":45,"publishedAt":46,"updatedAt":47,"createdAt":47},"41d50774-50df-4e2f-b1b3-ab6d9f329726","article","Backpressure：生产者太快时，系统怎样不被数据淹没？","backpressure-reactive-streams-explained","Backpressure 让下游处理能力反过来影响上游生产速度，避免异步流水线靠无限缓存硬撑。本文用水管和阀门解释响应式流、需求信号、数据丢弃与容量设计，也说明它和普通限流的区别。","在数据流系统里，生产者和消费者的速度经常不一样。传感器、网络连接或上游服务可能持续高速产生数据，而下游数据库、浏览器或模型处理得更慢。如果系统只会不断接收，内存最终会被队列填满，延迟和故障会一起上升。Backpressure，中文常译为“背压”或“反压”，就是让下游的处理能力反过来影响上游生产速度。\n\n## 它像水管里的阀门\n\n可以把数据流想成水流。生产者是水源，消费者是水池，中间有管道和阀门。消费者处理不过来时，需要通过请求数量、窗口大小、暂停读取或降低采样率告诉上游：“先慢一点”。这比无限堆积更健康，因为系统主动把压力传回源头。\n\nReactive Streams 规范把非阻塞背压作为异步流处理的核心目标。消费者可以请求自己能处理的数量，生产者再按需求发送。不同框架的 API 不完全一样，但基本思想都是把“需求”纳入数据流协议，而不是靠一个没有上限的缓冲区兜底。\n\n## 背压和限流不是一回事\n\n限流通常由系统预先设定一个允许速率，背压则更强调根据消费者当前状态动态调整。限流可以保护服务不被突发流量打垮，背压可以让一条流水线内部的每一段协同工作。两者可以同时使用。\n\n背压也有代价。数据可能需要丢弃、降采样、写入持久队列，或者让用户看到“处理中”。如果业务不能丢数据，就要明确队列容量、重试、顺序和恢复策略。把数据简单塞进内存，只是把问题延后。\n\n## AI 应用中的背压\n\n流式模型输出、日志管道、检索结果和工具调用都可能出现生产过快。AI 生成的异步代码若没有取消信号、队列上限和消费反馈，短时间演示可能正常，长时间运行就会积压。\n\n## 读者应该记住\n\nBackpressure 不是让系统“更快”，而是让快的一方知道什么时候必须慢下来。它把系统稳定性从无限缓存，转移到明确的流量协商和容量设计上。\n\n资料：[Reactive Streams Specification](https:\u002F\u002Fgithub.com\u002Freactive-streams\u002Freactive-streams-jvm)","\u002Fuploads\u002F2026-09-20\u002F35c47792-3d4b-46ae-9375-c68e4c53330e.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","foundit-ai-editorial",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"144abe77-0dc6-4f66-a176-20bddb1c0bfa","编程","coding",{"id":28,"name":29,"slug":30},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":32,"name":33,"slug":34},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse",{"id":36,"name":37,"slug":38},"a202d639-99a6-488a-a712-4d4c6ffd7e15","开发","dev",null,"Reactive Streams Specification","https:\u002F\u002Fgithub.com\u002Freactive-streams\u002Freactive-streams-jvm","published",false,45,0,"2026-09-20T00:00:00.000Z","2026-09-20T03:58:08.835Z",[49,57,65],{"id":50,"type":6,"title":51,"slug":52,"summary":53,"coverUrl":54,"authorName":14,"sno":55,"publishedAt":46,"createdAt":56},"d0700249-defa-43a1-a66a-4455c6889072","ABI：为什么源码能编译，二进制却不能互相调用？","application-binary-interface-abi-explained","ABI 是二进制世界的调用合同，规定参数传递、对象布局、符号命名和异常处理。本文区分 ABI 与 API，解释动态库、C++ 兼容性和跨语言绑定为什么不能只看函数签名。","\u002Fuploads\u002F2026-09-20\u002F33666a48-4e8f-42a3-9ffd-f4c490498689.jpg",42,"2026-09-20T03:58:01.058Z",{"id":58,"type":6,"title":59,"slug":60,"summary":61,"coverUrl":62,"authorName":14,"sno":63,"publishedAt":46,"createdAt":64},"c9f4e936-9533-4b9c-a1de-f03ef09fed37","WAL：为什么数据库要先写日志，再写真正数据？","write-ahead-logging-wal-database-explained","WAL 要求描述数据变化的日志先于数据页持久化，让数据库可以延迟刷写并在崩溃后通过重放恢复。本文用账本和收据解释 REDO、检查点、复制与持久性设置的关系。","\u002Fuploads\u002F2026-09-20\u002F6260c953-345b-4c9d-b3d6-6202c7e5539c.jpg",43,"2026-09-20T03:58:15.082Z",{"id":66,"type":6,"title":67,"slug":68,"summary":69,"coverUrl":70,"authorName":14,"sno":71,"publishedAt":46,"createdAt":72},"cd4e2aae-cbf2-4428-aab0-a6fa7911a424","Type Erasure：泛型信息为什么运行时消失了？","type-erasure-java-generics-explained","Java 的类型擦除让泛型主要承担编译期检查，生成字节码时把参数化类型替换为上界，并插入必要的转换。本文解释它带来的兼容性优势、反射限制，以及它和 Rust 单态化路线的区别。","\u002Fuploads\u002F2026-09-20\u002Fad612fe0-a1dd-4c46-a5dc-2ddfedefb22d.jpg",46,"2026-09-20T03:57:57.276Z"]