RPC 框架 Kitex 實踐入門:效能測試指南

語言: CN / TW / HK

2021 年 9 月 8 日,位元組跳動宣佈正式開源 CloudWeGo。CloudWeGo 是一套位元組跳動內部微服務中介軟體集合,具備高效能、強擴充套件性和穩定性的特點,專注於解決微服務通訊與治理的難題,滿足不同業務在不同場景的訴求。CloudWeGo 第一批開源了四個專案:Kitex、Netpoll、Thriftgo 和 netpoll-http2,以 RPC 框架 Kitex 和網路庫 Netpoll 為主。

日前, 位元組跳動服務框架團隊正式開源 CloudWeGo ,在抖音、今日頭條均有深度應用的 Golang 微服務 RPC 框架 Kitex 也包含在其中。

本文旨在分享開發者在壓測 Kitex 時需要了解的場景和技術問題。這些建議有助於使用者更好地結合真實 RPC 場景對 Kitex 進行調優,使之更貼合業務需要、發揮最佳效能。使用者也可以參考官方提供的壓測專案 kitex-benchmark[4]瞭解更多細節。

微服務場景的特點

Kitex 誕生於位元組跳動大規模微服務架構實踐,面向的場景自然是微服務場景,因此下面會先介紹微服務的特點,方便開發者深入理解 Kitex 在其中的設計思考。

  • RPC 通訊模型

微服務間的通訊通常以 PingPong 模型為主,所以除了常規的吞吐效能指標外,每次 RPC 的平均時延也是開發者需要考慮的點。

  • 複雜的呼叫鏈路

一次 RPC 呼叫往往需要多個微服務協作完成,而下游服務又會有其自身依賴,所以整個呼叫鏈路會是一個複雜的網狀結構。

在這種複雜呼叫關係中,某個中間節點出現的延遲波動可能會傳導到整個鏈路上,導致整體超時。當鏈路上的節點足夠多時,即便每個節點的波動概率很低,最終匯聚到鏈路上的超時概率也會被放大。所以單一服務的延遲波動 —— 即 P99 延遲指標,也是一個會對線上服務產生重大影響的關鍵指標。

  • 包體積大小

雖然一個服務通訊包的大小取決於實際業務場景,但在位元組跳動的內部統計中,我們發現線上請求大多以小包(<2KB)為主,所以在兼顧大包場景的同時,也重點優化了小包場景下的效能。

針對微服務場景進行壓測

確定壓測物件

衡量一個 RPC 框架的效能需要從兩個視角分別去思考:Client 視角與 Server 視角。在大規模的業務架構中,上游 Client 不見得使用的也是下游的框架,而開發者呼叫的下游服務也同樣如此,如果再考慮到 Service Mesh 的情況就更復雜了。

一些壓測專案通常會把 Client 和 Server 程序混部進行壓測,然後得出整個框架的效能資料,這其實和線上實際執行情況很可能是不符的。

如果要壓測 Server,應該給 Client 儘可能多的資源,把 Server 壓到極限,反之亦然。如果 Client 和 Server 都只給了 4 核 CPU 進行壓測,會導致開發者無法判斷最終得出來的效能資料是哪個視角下的,更無法給線上服務做實際的參考。

對齊連線模型

常規 RPC 的連線模型主要有三種:

  • 短連線:每次請求都建立新連線,得到返回後立即關閉連線

  • 長連線池:單個連線同時只能處理一次完整請求與返回

  • 連線多路複用:單個連線可以同時非同步處理多個請求與返回

每類連線模型沒有絕對好壞,取決於實際使用場景。連線多路複用雖然一般來說效能相對最好,但應用上必須依賴協議能夠支援包序列號,且一些老框架服務可能也並不支援多路複用的方式呼叫。

Kitex 最早為保證最大程度的相容性,在 Client 端預設使用了短連線,而其他主流開源框架預設使用連線多路複用,這導致一些使用者在使用預設配置壓測時,出現了比較大的效能資料偏差。

後來為了契合開源使用者的常規使用場景,Kitex 在 v0.0.2 中也加入了預設使用長連線的設定。

對齊序列化方式

對於 RPC 框架來說,不考慮服務治理的話,計算開銷主要都集中在序列化與反序列化中。

Kitex 對於 Protobuf 的序列化使用的是官方的 Protobuf 庫[6],對於 Thrift 的序列化,則專門進行了效能優化,這方面的內容在官網部落格中有介紹。

當前開源框架大多優先支援 Protobuf,而部分框架內建使用的 Protobuf 其實是做了許多效能優化的 gogo/protobuf 版本,但由於 gogo/protobuf 當前有失去維護的風險,所以出於可維護性角度考慮,我們依然決定只使用官方的 Protobuf 庫,當然後續我們也會計劃對 Protobuf 進行優化。

使用獨佔 CPU

雖然線上應用通常是多個程序共享 CPU,但在壓測場景下,Client 與 Server 程序都處於極端繁忙的狀況,如果同時還共享 CPU 會導致大量上下文切換,從而使得資料缺乏可參考性,且容易產生前後很大波動。

所以我們建議是將 Client 與 Server 程序隔離在不同 CPU 或者不同獨佔機器上進行。如果還想要進一步避免其他程序產生影響,可以再加上 nice -n -20 命令調高壓測程序的排程優先順序。

另外如果條件允許,相比雲平臺虛擬機器,使用真實物理機會使得測試結果更加嚴謹與具備可復現性。

效能資料參考

在滿足上述要求的前提下,我們對多個框架使用 Protobuf 進行了壓測對比,壓測程式碼在 kitex-benchmark 倉庫。在充分壓滿 Server 的目標下,Kitex 在連線池模式下的 P99 Latency 在所有框架中最低。而在多路複用模式下,Kitex 在各指標上也都具有更加明顯的優勢。

配置:

  • Client 16 CPUs,Server 4 CPUs

  • 1KB 請求大小,Echo 場景

參考資料:

  • KITEX:連線池模式(預設模式)

  • KITEX-MUX:多路複用模式

  • 其他框架均使用多路複用模式

結語

在當前主流的 Golang 開源 RPC 框架中,每個框架其實在設計目標上都各有側重:有些框架側重於通用性,有些側重於類似 Redis 這種輕業務邏輯的場景,有些側重於吞吐效能,而有些則更側重 P99 時延。

位元組跳動的業務在日常迭代中,常常會出現因某個 feature 導致一個指標上升,另一個指標下降的情況,因此 Kitex 在設計之初就更傾向於解決大規模微服務場景下各種問題。

Kitex 釋出後,我們接到了大量來自使用者的自測資料,感謝社群對我們的關注和支援,也歡迎廣大開發者基於本文提供的測試指南,針對自己的實際場景選擇合適的工具。更多問題,請在 GitHub 上提 Issue 交流。

相關連結

  • [1] CloudWeGo 官網:

    https://www.cloudwego.io

  • [2] Kitex:

    https://github.com/cloudwego/kitex

  • [3] Netpoll:

    https://github.com/cloudwego/netpoll

  • [4] kitex-benchmark:

    https://github.com/cloudwego/kitex-benchmark

  • [5] netpoll-benchmark:

    https://github.com/cloudwego/netpoll-benchmark

  • [6] 官方 Protobuf 庫:

    https://github.com/golang/protobuf

  • [7] Thriftgo:

    https://github.com/cloudwego/thriftgo