
我們將 Node.js 替換為 Bun 以獲得 5 倍吞吐量
我們在對延遲敏感的服務中將 Node.js 替換為 Bun,在優化熱點路徑並解決了 Bun HTTP 模型特有的記憶體洩漏問題後,成功獲得了 5 倍的吞吐量提升並顯著降低了 CPU 使用率。
背景
Trigger.dev 團隊分享了將其延遲敏感服務 Firestarter 從 Node.js 遷移至 Bun 的過程,宣稱獲得了五倍的吞吐量提升。該服務主要處理數千個長輪詢連接,開發團隊透過移除 SQLite 查詢引擎、替換 Zod 驗證以及改用 Bun 內建的 HTTP 伺服器,成功優化了 CPU 密集型的瓶頸,但也同時記錄了在 Bun 環境下遇到的記憶體洩漏挑戰。
社群觀點
這篇案例研究在 Hacker News 引發了兩極化的討論,爭議核心在於「效能提升」的歸因是否誠實。許多資深開發者指出,標題宣稱的五倍提升具有誤導性,因為文章中大部分的效能增益實際上來自於演算法的優化,而非運行時環境的更迭。批評者認為,將複雜且低效的 SQLite 關聯查詢替換為簡單的 Map 查找,以及移除昂貴的 Zod 模式驗證,這兩項改動在任何運行時環境都能帶來顯著進步。更有評論直言,原先的 SQL 查詢設計過於業餘,開發者不應將自身工程設計的失誤轉化為對特定工具效能的背書。
關於 Bun 與 Node.js 的技術對比,社群展開了細緻的討論。支持者讚賞 Bun 提供的開發者體驗,特別是內建的單一執行檔編譯功能,這簡化了部署流程並減少了容器映像檔的體積。雖然 Node.js 現在也具備單一執行檔模式,但評論者指出其對 ESM 的支援仍不如 Bun 直覺。然而,安全性成為了 Bun 的一大短板,有開發者提到 Deno 在權限控管上遠優於 Bun,且 Bun 針對安全性權限的開發進度緩慢,這成為許多企業級專案猶豫遷移的主因。
此外,針對效能極限的追求,部分留言者質疑為何在如此重視延遲的場景下仍堅持使用 JavaScript 生態系。他們認為若改用 Go、Rust 或 C++,效能提升將遠超更換運行時環境帶來的邊際效益。但也有觀點反駁,前端與後端語言的統一能極大化開發效率與代碼遷移的便利性。針對 Bun 的速度優勢,社群共識傾向於這並非源自 JavaScript 引擎本身的差異,而是因為 Bun 大量使用 Zig 語言編寫的高效能綁定,減少了系統調用的開銷。
最後,關於開發細節也有不少技術辯論。例如文中提到的「空字元分隔字串」作為 Map 鍵值的做法,被部分開發者批評會增加垃圾回收負擔,建議改用嵌套 Map。而關於編譯為位元組碼(Bytecode)反而導致效能下降的現象,也引起了對即時編譯(JIT)暖機機制與記憶體映射開銷的深入探討。
延伸閱讀
- Deno Compile:與 Bun 類似的單一執行檔編譯工具,被認為產出的二進位檔更小且更優化。
- Node.js Single Executable Applications (SEA):Node.js 官方提供的單一執行檔打包方案。
- Vercel ncc:用於將 Node.js 專案及其依賴項編譯為單一 JavaScript 檔案的工具,常配合 SEA 使用。
- Bun 安全權限 PR (#25911):社群高度關注但尚未合併的 Bun 安全性功能實作。