BACKEND ADVANCED · 143
Streams / Backpressure:資料不一定要一次全部放進 Memory
Request body、檔案、network response 都可能是逐塊到達的資料流。Stream 讓程式邊讀邊處理;backpressure 則避免 producer 比 consumer 快太多把 memory 撐爆。
Learning outcomes
- 能解釋 chunk/stream。
- 能區分 buffering whole payload 與 streaming。
- 能理解 backpressure 的問題。
- 能使用 pipeline 思考錯誤傳遞。
1. 一次全部讀 vs stream
const file =
await readFile(
"huge.csv"
);整個檔案先進 memory。對巨大資料不一定合適。
const stream =
createReadStream(
"huge.csv"
);資料分 chunks 到達,可逐段處理。
2. Backpressure
如果 consumer 跟不上,stream system 需要暫停/調節 producer,而不是無限堆 buffer。
3. pipeline
await pipeline(
createReadStream(
"courses.csv"
),
transformCourses(),
createWriteStream(
"report.csv"
)
);Pipeline 讓資料流與 error propagation 更集中。
4. Byte stream、Object mode 與 Transform
Node stream 可以處理 bytes/strings,也能在 object mode 傳 JavaScript values。Transform stream 同時是 readable 與 writable:收到 chunk 後轉換,再把新 chunk 往下游送。
source
.pipe(parser)
.pipe(transformer)
.pipe(destination);
真正 production code 還要處理 source error、transform error、destination error;這也是為什麼 pipeline() 比手工串很多 pipe() 更容易建立統一 failure boundary。
5. Backpressure 不只是記憶體問題
當 downstream 變慢,buffer 增長也會提高 latency,甚至讓 process 被 OOM killer 終止。高流量 server 要觀察 throughput、buffer、memory 與 response latency,而不是只看「最後有沒有傳完」。
Project checkpoint:Course export
Course API 新增大型 CSV export,不先把十萬筆全部串成一個 giant string,而是逐步產生 response stream。
Knowledge check
- 為什麼大檔案 readFile 可能是 memory 問題?
- backpressure 解的是 producer/consumer 哪種不平衡?
- HTTP request body 為什麼本質上適合 stream model?
- 設計一個 CSV export pipeline。