1991年愛立信實驗室里,幾個工程師為電話交換機寫了個容錯系統。33年后,這套系統被用來跑Ruby on Rails——而且只需要5MB內存。
這就是QuickBEAM干的事。它把完整的Rails應用塞進Erlang虛擬機(BEAM),讓JavaScript代碼獲得電信級的故障恢復能力。同一套代碼,Node.js上跑45MB,崩潰即全掛;BEAM上跑5MB,單核崩潰秒級重啟,用戶無感知。
開發者Sam Ruby上周放出了演示:一個標準Rails博客應用,Turbo Streams實時同步,Action Cable協議原封不動。瀏覽器開兩個標簽頁,創建文章,兩邊同時刷新。這部分沒什么新鮮。
新鮮的是后臺。故意制造一個JavaScript運行時崩潰,Node.js方案會拖垮整個進程——連接斷開、狀態丟失、從頭重啟。BEAM方案里,OTP supervisor只重啟那個出問題的運行時,其他運行時繼續服務,WebSocket連接保持,Turbo從斷點續傳。
應用層代碼完全沒變。Ruby源碼一模一樣。變的是執行目標。
瀏覽器用BroadcastChannel,Node.js用WebSocket,BEAM用Erlang進程組
三端同步機制各不相同,但用戶看到的效果完全一致。瀏覽器端靠BroadcastChannel API實現跨標簽頁通信;Node.js端跑獨立的WebSocket服務器;BEAM端則調用Erlang的進程組(process groups)——默認支持分布式,零外部依賴。
這套架構的核心是QuickBEAM,一個專為Erlang虛擬機設計的JavaScript運行時。它基于QuickJS-NG構建,后者是一個輕量級、標準兼容的JavaScript引擎。與Node.js把V8嵌進C++進程不同,QuickBEAM把QuickJS嵌進Erlang NIF(原生接口函數),讓JavaScript直接調用BEAM的并發和容錯原語。
每個QuickBEAM運行時都是一個輕量級隔離體。Elixir可以啟動一個運行時池,把請求輪詢分發到各個運行時,每個跑在獨立的操作系統線程上。一個崩潰,OTP supervisor重啟它,其他的繼續干活。這就是Erlang為電信交換機設計的"let it crash"哲學——崩潰不可怕,恢復速度才是關鍵。
QuickJS不是V8,沒有JIT編譯器,純計算性能確實慢一些。但Web應用的主要開銷是I/O:數據庫查詢、模板渲染、HTTP響應。這部分瓶頸上,兩者差距可以忽略。換來的收益很實在:運行時體積從45MB壓到5MB,啟動時間壓到亞毫秒級,外加整個OTP生態系統的調用權。
Elixir管它最擅長的,JavaScript管業務邏輯
完整的調用鏈長這樣:
瀏覽器(Turbo、Stimulus、Action Cable客戶端)? HTTP + WebSocket ? Bandit(Elixir HTTP服務器)? Plug路由 ? QuickBEAM(JavaScript運行時池)? Beam.callSync ? Elixir(:pg廣播、SQLite NIF、OTP監控)
JavaScript層處理請求路由、控制器邏輯、視圖渲染、模型操作——和Node.js上跑的代碼完全一致。Elixir層專注它三十年來打磨的領域:并發調度、故障容錯、分布式消息。
瀏覽器端跑的是真正的@hotwired/turbo-rails npm包,Rails官方同款Action Cable客戶端。自定義元素連接到/cable端點,說著標準的Action Cable線協議。
服務器端由Elixir實現協議的另一頭:Bandit處理WebSocket升級,:pg管理訂閱關系,廣播消息以Action Cable的JSON格式投遞。當模型的broadcasts_to回調觸發時,數據通過Beam.callSync('__broadcast'...)從JavaScript跨入Elixir,完成全網廣播。
5MB vs 45MB,不只是數字游戲
Node.js的內存 footprint 來自V8的復雜架構:優化編譯器、垃圾回收器、隱藏類系統。這些對計算密集型任務有價值,對典型的CRUD Web應用是過度配置。QuickJS走另一條路:解釋執行、引用計數GC、極簡運行時——剛好夠跑標準JavaScript,不多一分。
亞毫秒級啟動意味著運行時可以被頻繁創建和銷毀。Elixir的進程池可以按負載動態伸縮,冷啟動懲罰幾乎為零。對比Node.js的啟動延遲,這對Serverless場景和邊緣部署是結構性優勢。
OTP supervision tree是另一張牌。Node.js的cluster模塊能做多進程,但進程間狀態隔離、故障恢復、代碼熱更新都需要自己搭。BEAM把這些內建在虛擬機層面,supervisor策略可配置:one-for-one重啟單個失敗子進程,rest-for-one級聯重啟依賴鏈,one-for-all全量重啟——按業務場景選。
分布式是默認能力。:pg模塊的進程組跨節點透明,兩臺BEAM節點自動形成集群,廣播消息自然擴散。Node.js要做到同等效果,需要引入Redis或專門的消息隊列。
Rails社區會買賬嗎
技術債是真實的。Rails生態大量依賴C擴展(nokogiri、pg、redis等),這些需要重新編譯為BEAM的NIF或移植為純JavaScript實現。QuickBEAM目前用SQLite NIF演示,關系型數據庫的完整支持還在路上。
但演示本身已經說明可行性邊界。Turbo、Stimulus、Action Cable——Rails 7的核心前端棧——全數跑通。這不是"理論上可以",是`npx github:ruby2js/juntos --demo blog`一行命令能復現的東西。
Sam Ruby的背景值得注意。他是Ruby核心團隊成員,JSON gem維護者,W3C HTML工作組成員。這個項目的權威性不來自營銷話術,來自作者對兩個生態的深度理解。
Ruby語言的發明人松本行弘(Matz)說過,Ruby的設計目標是"讓程序員快樂"。Elixir的發明人José Valim是Rails核心團隊出身,設計目標是"高并發、高容錯、低延遲"。QuickBEAM像是兩條路徑的交匯點——用Rails的寫法,拿Elixir的運行時特性。
一個懸而未決的問題:如果5MB運行時就能跑Rails,且自帶分布式和容錯,Rails 8會不會官方支持BEAM作為部署目標?DHH(Rails創始人)近年對#nobuild、默認SQLite的激進轉向,說明核心團隊對"簡化部署"有執念。QuickBEAM的方向與此暗合。
但DHH也是出了名的技術審美固執。他會把Rails綁上BEAM這艘船,還是堅持Ruby解釋器的正統性?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.