C/C ++/Rust/Golang/Java/Python
比較不同語言如何處理網路I / O並檢查Rust是否保持其高效能承諾這篇文章是衡量網路服務效能的延續。
當我的計算機沒有網際網路連線時,我發現我無能為力。確實,我們主要使用膝上型電腦和智慧手機訪問其他地方儲存或生成的資訊。甚至很難想象沒有網路通訊的非面向使用者的應用程式的實用性。儘管I / O操作與資料處理的比例可能有所不同,但此類操作對服務延遲的貢獻可能很明顯。
有許多用於實現後端服務的程式語言。因此,人們對比較這些語言的效能具有天然的興趣,並且存在各種基準。例如,有一個基準遊戲,它比較瞭解決不同離線任務的不同語言。另一組基準TechEmpower用於衡量Web框架的效能。這些度量非常有用,可以粗略地瞭解語言效能。但是,它們通常會度量一些特定的用例和操作集,而這些用例和操作集並不一定具有代表性。
所有這些使我對不同平臺上的準系統I / O的不可降低的成本感到好奇。對TCP代理進行基準測試可能是最簡單的情況。沒有資料處理,僅處理傳入/傳出連線和中繼原始位元組資料。微服務幾乎不可能比TCP代理更快,因為它不能做得比TCP代理快。它只能做更多的事情。在此基礎上構建任何其他功能-解析,驗證,遍歷,打包,計算等。
比較以下解決方案:
快速說明-我試圖選擇Golang,Java和Python中最好的解決方案,但是如果您知道更好的選擇,請隨時與我聯絡。
實際的後端是Nginx,它配置為在HTTP模式下提供10kb的資料。
基準結果分為兩組:
基準,C,C ++,Rust-高效能語言。Rust,Golang,Java,Python-記憶體安全的語言。是的,Rust屬於兩個世界。
方法的簡要說明為TCP代理分配了兩個核心(使用cpuset)。為後端分配了兩個核心(Nginx)。請求速率從10k開始,每秒上升到25k請求(rps)。連線被重用為50個請求(每個請求10kb)。基準測試在同一臺VM上執行,以避免任何網路噪音。VM例項型別經過計算最佳化(完全擁有所有分配的CPU),以避免出現“嘈雜的鄰居”問題。延遲測量解析度為微秒(µs)。我們將比較以下統計資料:
百分位數(從p50到p99)—關鍵統計資料。離群值(p99.9和p99.99)—對於大型分散式系統的元件而言至關重要。最大延遲-最壞的情況永遠不容忽視。修整後的均值tm99.9-沒有最佳/最差0.1%的均值,以捕獲中心趨勢(沒有異常值)。標準偏差-評估延遲的穩定性。隨時瞭解有關該方法的更多資訊以及選擇這些統計資訊的原因。為了收集資料,我使用了perf-gauge。
好吧,我們來談談結果!
比較高效能語言:C,C ++,Rust我經常聽說Rust在效能方面可與C / C ++媲美。讓我們看看“同等”處理網路I / O的確切含義。
請按以下順序檢視以下四個圖形:基準,C,C ++,Rust:
Green — p50, Yellow — p90, Blue— p99 in µs (on the left). Orange — rate (on the right)
在下面,您將看到每個統計資訊在後端頂部添加了多少微秒。下面的數字是最大請求速率下間隔的平均值(不包括加速):
> Overhead, µs
相對而言(開銷為基線的百分比):
> Overhead in % of the baseline statistic
有趣的是,雖然在c99.9級別上用C ++編寫的代理要比HAProxy和Rust稍快,但在p99.99和max9級別上則更糟。但是,它可能是實現的一個屬性,在這裡是非常基本的(並且透過回撥實現,而不處理期貨)。
此外,還測量了CPU和記憶體消耗。您可以在這裡看到這些。
總之,用C,C ++和Rust編寫的所有三個TCP代理都表現出相似的效能:精簡和穩定。
比較記憶體安全語言:Rust,Golang,Java,Python現在,讓我們比較一下記憶體安全的語言。不幸的是,Java和Python的解決方案無法僅在兩個核心上處理25,000 rps,因此Java的基準測試為15,000 rps,Python的基準測試為10,000 rps。
請按以下順序檢視以下四個圖形:Rust,Golang,Java,Python。
> Green — p50, Yellow — p90, Blue— p99 in µs (on the left). Orange — rate (on the right)
好吧,現在我們看到了巨大的不同。在上一張圖表上,在新的規模上似乎“嘈雜”的內容對於Rust來說似乎相當穩定。另外,請注意Java的冷啟動高峰期。下面的數字是最大請求速率下間隔的平均值(不包括加速):
> Overhead, µs
如您所見,Golang在p50 / p90級別上具有一定的可比性。但是,對於更高的百分位數,差異會急劇增加,這反映在標準偏差上。但是,請看一下Java數字!
值得一提的是離群值(p99.9和p99.99)。可以很容易地說出Rust與Rust的區別是巨大的:
> Green — p99.9, Blue — p99.99 in µs (on the left). Orange — rate (on the right)
相對而言(相對於基準Nginx的百分比):
> Overhead in % of the baseline statistic
總之,Rust的延遲差異遠低於Golang,Python,尤其是Java。Golang在Rust的p50 / p90延遲水平上是可比的。
最大產量另一個有趣的問題-每個代理可以處理的最大請求速率是多少?同樣,您可以閱讀完整的基準測試以獲取更多資訊,但是現在,這裡是一個簡短的摘要。
Nginx能夠處理超過60,000 rps。如果我們在客戶端和後端之間放置一個TCP代理,它將降低吞吐量。如下所示,C,C ++,Rust和Golang實現了Nginx直接提供的服務的70%–80%,而Java和Python的效能則更差:
> Left axis: latency overhead. Right axis: throughput
藍線是尾部等待時間(Y軸在左側)-越低越好。灰色條表示吞吐量(右側的Y軸)-越高越好。結論這些基準測試並不全面,目標是比較不同語言的基本I / O。
但是,它們與Benchmarks Game和TechEmpower一起顯示,如果可預測的效能對您的服務至關重要,Rust可能是Golang,Java或Python的更好替代方案。另外,在開始使用C或C ++編寫新服務之前,值得考慮Rust。因為它具有與C / C ++一樣的效能,所以最重要的是: