線上支付服務Stripe在GitHub上,開源其生產環境正在使用的Sorbet編譯器,該編譯器使用Sorbet和LLVM,根據Ruby原始碼檔案產生符合Ruby的C擴充套件API。目前這個編譯器仍處於實驗階段,雖然Sorbet編譯器與Sorbet在同一個儲存庫中,但是並不影響Sorbet的內容,Sorbet也不依賴Sorbet編譯器,官方目前並沒有計畫要釋出預建置的Sorbet編譯器二進位檔案。

Stripe在2019年的時候,開源了Ruby類型檢查工具Sorbet,Sorbet能夠靜態分析專案程式碼,以找出類型不一致的錯誤,並且在程式執行時動態檢測類型,以發現Ruby程式中所存在的安全性風險。由於Stripe中絕大多數的程式碼都是由Ruby撰寫而成,因此Stripe進行了多項能夠提高Ruby效能與安全性的專案,Sorbet編譯器便是其中一項,過去Sorbet編譯器的程式碼放在私有儲存庫,只與少數對象共享,但因為更新專案手續麻煩,因此Stripe決定將編譯器開源在Sorbet儲存庫中,以方便與Sorbet共用同一個內部資料結構。

Stripe的主要產品是API,他們必須壓低延遲來提供更好的服務,Stripe採取兩個策略降低延遲,除了減少I/O時間,他們也著手加速運算時間,而建構Sorbet編譯器,是他們加速Ruby程式的解決方案之一。之所以將Sorbet編譯器設計為AOT(Ahead-Of-Time)而非JIT編譯器,官方提到,是因為不需要將整個語言Runtime都部署到生產環境,使用AOT編譯器,就只要在CI階段中使用,經過編譯的構件,也可以剛好適用於現有的建置工作管線,即便發生問題,可以停止載入有問題的編譯構件,讓Ruby虛擬機器執行原始程式碼就可以減輕問題帶來的影響。

AOT編譯器在概念上更簡單,Stripe認為,實作一個能夠改進效能的AOT編譯器,比起JIT編譯器所花費的時間更少。而且使用Sorbet對專案進行類型檢查,AOT編譯器就可以使用Sorbet所產生的靜態類型資訊,雖然JIT在執行時也能觀察類型,來得知編碼的方式,但是以Stripe的用例來說,Ruby程式碼庫大量使用Sorbet,因此使用靜態類型資訊有其優勢。

Sorbet編譯器產生Ruby原生擴充套件,這些套件能夠與其他Ruby程式碼互通,因此使用Sorbet編譯器不需要放棄Ruby虛擬機器,並且可以繼續使用現有的Gems和擴充套件。

Sorbet編譯器建基在LLVM和現有的Ruby虛擬機器之上,當編譯程式碼的時候,起點從普通的*.rb程式碼檔案開始,這些檔案會進入到Sorbet中進行類型檢查,類型檢查的輸出為自定義中間語言(Intermediate Representation,IR),Sorbet編譯器使用這些IR來生成LLVM IR,LLVM接著使用LLVM IR來產生原生共用物件*.so檔案,這些共用物件就是Ruby原生擴充套件,符合且使用與Gems相同的API,也就是說,編譯後的構件,使用與其他Ruby程式碼相同的物件模型和Runtime表示。

目前Stripe已經在內部的生產環境,使用Sorbet編譯器約1年的時間,程式碼增加的效能,根據不同工作負載而有所差異,Stripe並沒有分享更多效能資訊,但是在程式碼庫中,提供了一些綜合基準檢查,但官方提到,這些基準測試並沒有代表性,只能用來除錯和減少效能問題。


熱門新聞

Advertisement