<b>本文講的是頂級 Swift 服務端架構對決 Node.js,</b>
最近我在做服務端 Swift 工作時,我被問到這樣的問題:
「在服務端 Swift 能否擊敗 Node.js?」
Swift 是一個可以被用來做包括服務端在内的任何事情,從他第一次開源并且移植到 Linux 上就一直很引人入勝。你們肯定有很多人像我一樣好奇,是以我非常樂意來分享我的學習成果。
在寫這篇文章的時候,按照 Github 上獲得 star 的數量順序排列最受歡迎的服務端 Swift 架構如下:

7,956

5,183

4,017

1,186
本文将以以下方式呈現:
這份快速指引
結果摘要
方法學
詳細的結果
結論和說明
以下是主要測試的結果摘要,我想說的是:
無論各項得分怎樣,這些架構内所有的表現都非常棒
搭部落格比列印 "Hello, World!" 到螢幕上有常見的用途,JSON 也是一種很常見的用例。良好的基準測試需要考慮每個架構在相似負載下的表現,它需要比簡單的列印兩個單詞到螢幕上承載更多的壓力。
在每一個主題測試項目中我都會盡量保證部落格盡可能相似,同時貼合每個架構的文法風格來完成。為了在許多資料結構中一字不差的使用不同架構生成相同的内容,讓每個架構都使用相同的資料模型工作,但是有些方面例如 URL 路由等方式會有很大的差别來适應每個不同架構中的文法和風格。
在不同的 Swift 服務端架構直接有一些微小的差别需要注意。
在 Kitura 和 Zewo 中,如果絕對路徑中存在空格都會在建構時引發一些問題,在 Xcode 中建構任何架構也存在相同的問題。
Zewo 使用 05-09-a 的 Swift 快照版本,這意味着他在 release 模式下的建構存在一些問題,是以他運作在 debug 模式下。因為這個問題存在是以所有關于 Zewo 的測試都運作在 debug 模式下(這将不包含 release 優化)。
靜态檔案的處理是一個衆多服務端 Swift 架構争議的焦點。Vapor 和 Zewo 都建議使用 Nginx 來作為靜态檔案的代理,然後使用架構來作為後端使用。Perfect 的建議是使用其内置的處理程式,但我并沒有有看見 IBM 對此相關的任何評論。由于這項研究不是為了探讨架構如何連接配接 Nginx 這樣的伺服器應用,是以靜态檔案都使用了每個架構本身來處理。你或許可以為了性能考慮而在選擇 Vapor 和 Zewo 的時候考慮這個問題,這也是為什麼我考慮包含 JSON 測試的一個原因。
[在 9 月 1 日更新的結果] Zewo 是一個單線程應用程式,你可以通過在每一個 CPU 上都運作一個執行個體來獲得額外的性能提升,因為他們是并發運作而不是在多線程模式下工作。在本研究中,每個應用程式隻會有一個執行個體運作。
工具鍊 (Toolchains),每個架構都從 Apple 釋出的工具鍊中選擇了不同的快照版本,在本文釋出時測試的版本如下:
DEVELOPMENT-SNAPSHOT-2016-08–24-a for Perfect
DEVELOPMENT-SNAPSHOT-2016-07–25-a for Vapor & Kitura
DEVELOPMENT-SNAPSHOT-2016-05–09-a for Zewo
Vapor 運作 release 特殊文法。如果你隻是簡單的去執行二進制包,你将會在控制台中獲得一些可以幫助開發和調試過程的日志記錄。這将會帶來一些額外的性能開銷,為了讓 Vapor 運作在 release 模式下你需要添加 <code>--env=production</code> 來運作,例如:
[在 9 月 1 日更新的結果] 當使用 Zewo 的時候,即使你不能在 05-09-a 工具鍊上使用 release 模式,你依然可以通過添加以下代碼來進行 release 優化:
Node.js / Express 沒有建構編譯,因為他沒有 debug 和 release 的差別。
靜态檔案處理包括了 Vapor 的預設中間件。如果你沒有使用靜态檔案并且想要優化速度(譯注:原作者的意思是如果沒有用到它來處理靜态檔案,那麼用這個方法來忽略掉 Vapor 預設的中間件以提高速度。),你必須包含如下代碼(就像我在 VaporJSON 中所做的一樣):
我決定使用 Node.js 的 Express 來作為一個對照包含在測試中。因為他和 Swift 服務端架構具有非常相似的文法并且被廣泛應用。他有助于建立一個基線來展示 Swift 能夠多麼的讓人印象深刻。
在某些時候開始,我稱之為「追逐彈球」。目前 Swift 服務端架構處于非常活躍的開發狀态,因為 Swift 3 的每一個預覽版相對于上一個都有成堆的改動。是以 Apple 的 Swift 團隊導緻所有的服務端 Swift 架構需要頻繁的釋出新版本。他們沒有擁有完善的文檔,是以我非常感謝架構的小組成員和廣大 Swift 服務端架構社群。我也要對無數的社群成員和架構團隊在我前進道路上給予的幫助表示感謝。這有很多的樂趣,我很樂意這樣做。
為了盡量消除不同環境帶來的影響,我使用了一個 2012 款的 Mac mini 并且重新安裝了 El Capitan (10.11.6),然後下載下傳了 Xcode 8 beta 6,并且設定 command-line-tools 為 Xcode 8。然後使用 swiftenv 安裝了必要的快照版本,克隆倉庫并且在 release 模式下清潔的編譯每一個部落格,并且不會同時進行兩個測試。測試伺服器的規格是這樣的:
而在開發中我使用的是 2015 款的 rMBP。我在這裡進行了建構測試,因為它是我現實生活中的開發裝置是以更有意義。我用 wrk 來獲得評分,并且我使用 Thunderbolt 2 線纜來連接配接兩台裝置,因為 Thunderbold 橋接能擁有一個令人難以置信的帶寬使得你的路由器不會成為限制條件,他能更可靠的在部落格單獨運作在一台機器上的時候用另一個獨立的機器去生成負載以壓倒性的測試伺服器。這提供了一個一緻的測試環境,是以我可以說每個部落格都是在相同的硬體和條件下運作,為了滿足一些好奇心,我開發裝置的規格是:
在測試中,我決定使用 4 個線程各生成 20 個連接配接并持續 10 分鐘。4 秒鐘不能稱之為測試,而 10 分鐘是一個合理的時間,因為能獲得大量的資料并且 4 個線程運作 20 個連接配接會對部落格造成沉重的負擔而不至于斷開連結。
如果你想探索這個項目的源代碼或者做任何自己的測試,我把這些測試代碼都整合到了一個倉庫中,你可以在這裡找到:
<a href="https://github.com/rymcol/Server-Side-Swift-Benchmarking">https://github.com/rymcol/Server-Side-Swift-Benchmarking</a>
我認為可能需要先看一眼建構時間。建構時間在日複一日的開發中占據了很大一部分開發時間,并且他也能算作是架構的性能表現,我覺得我在探索的是真實的數字和持續時間的感覺。
對于每一個架構,
然後
運作完之後,進行第二次測試
最後
這兩次建構都使用了 SPM(Swift Package Manager, Swift 包管理器) 來管理依賴關系,包括正常的、清潔的依賴都已經下載下傳好了。
這運作在我本地的 2015 款 rMBP 上并且建構在 debug 模式,因為在使用 Swift 開發應用時這是正常的過程。
我第二在意的就是在架構運作時候記憶體的占用量。
第一步 開始記憶體占用(單純的啟動程序)
第二步 測試我伺服器上峰值記憶體占用
第三步 用下面的方法第二次測試記憶體占用
這個測試在一個幹淨的 Mac mini 專用測試伺服器上運作。反映了每個架構在 release 模式可能存在的狀況。同一時間隻有一個架構在指令行中運作并且會在下一次測試前重新開機。在測試期間唯一打開的視窗是活動螢幕,我用它來可視化記憶體占用。在每個架構運作的時候,我隻是簡單的指出峰值出現在活動螢幕中的時候。
我第三看重的事情是每個架構在負載下的線程使用情況
第二部 在我的測試伺服器上用下面的指令來産生線程使用:
這是一個用幹淨的 Mac mini 來搭建的專用測試伺服器,每個架構都盡可能的在 release 模式下執行的。同一時間隻有一個架構在指令行中運作并且會在下一次測試前重新開機。在測試期間唯一打開的視窗是活動螢幕,我用它來可視化記憶體占用。在每個架構運作的時候,我隻是簡單的指出峰值出現在活動螢幕中的時候。
這裡沒有「勝出」這一類。許多不同的應用程度對于線程的管理方式不同,并且這些架構也不例外。例如 Zewo 就是一個單線程應用程式,他永遠不會使用大于一個線程(如果你沒有主動在每一個 CPU 上運作的話)。而 Perfect 則會使用每一個可用的 CPU,Vapor 則是為每個線程模型使用一個 CPU。是以該圖的目的是使線程負載峰值更容易看到。
第一個基準測試是處理 <code>/blog</code> 的路由,這是一個為每個請求傳回 5 個随機圖檔的假部落格文章接口。
從我的 rMBP 上用 Thunderbolt 橋接運作每個部落格。
在記憶體測試中,每個架構都在 release 模式運作,每次測試之前都會被重新啟動。同一時間隻有一個架構會被運作在伺服器上。所有的活動都保持在最小的改變以保證環境盡可能相似。
由于每個人對于靜态檔案的處理方法都各有風格,是以看上去更加公平的方式是使用簡單的接口來進行相同的測試,是以我增加了 <code>/json</code> 路由來測試每個應用從沙盒内傳回 0~1000 之間的随機數。這個測試是單獨進行的,以保證靜态檔案處理程式和中間件不會影響到接結果。
對每個 JSON 項目都運作
在其他測試中,每個架構都在 release 模式運作,每次測試之前都會被重新啟動。同一時間隻有一個架構會被運作在伺服器上。所有的活動都保持在最小的改變以保證環境盡可能相似。
我的問題得到的回答是壓倒性的 是。Swift 能做的不僅能作為服務端架構使用,并且所有的 Swift 服務端架構性能都表現得令人難以置信的好,而 Node.js 在每個測試中都排在最後兩名。
由于服務端 Swift 架構可以和其它 Swift 應用共享基本代碼庫,是以它可以為你節省大量的時間。而從這裡的結果可以看出,服務端 Swift 架構在程式設計領域是非常強有力的競争者。我個人會在程式設計中(特别是在服務端)盡可能的使用 Swift。我也迫不及待地想看到社群湧現出更多令人感到驚奇的項目。
如果你對服務端 Swift 感興趣,現在是時候參與其中了!這些架構還有大量的工作需要完成,比如說他們的文檔。并且有一些非常炫酷的應用程式作為示例(有開源也有閉源)。你可以在這裡了解更多資訊:
<b></b>
<b>原文釋出時間為:2016年09月28日</b>
<b>本文來自雲栖社群合作夥伴掘金,了解相關資訊可以關注掘金網站。</b>