RustのgRPCがGoよりも遅い?

FUJITA Tomonori
nttlabs
Published in
5 min readSep 10, 2020

夏のある日、GoのgRPCが、Rustよりも2倍早いという記事を見つけました。「おいおい、測定ミスだろ」と強がっていましたが、日々、不安は高まっていきます。真実の愛であれば、疑うことは許されませんが、エンジニアの言語への愛など、所詮、状況に応じて使い分けるような打算的な愛。確認してみました。

性能測定結果

上記の記事と同じく、gRPCのサーバソフトウェアは、Goはgrpc-go、Rustはtonicのgreeterの性能を、gRPCのクライアントソフトウェアghzを使って、測定しました。ハードウェアは、AWSを利用し、サーバはc5a.8xlarge(32 vCPU/64 GiB)インスタンス、クライアントはc5a.16xlarge(64 vCPU/128 GiB)インスタンスを使いました。

1台のクライアントインスタンスは、同時に3,000個のgRPCクライアントを立ち上げ、合計で6,000,000個のリクエストを送信します。クライアント数を1、2、4、8台と増やし、サーバが1秒あたりに処理できたリクエスト数を測定した結果が下記になります。

gRPCのクライアント数が3,000、6,000の条件では、tonicが少し性能が高いですが、gRPCクライアント数が12,000では、tonicの方が遅い!その上、gRPCクライアント数が24,000では、tonicはエラーのため測定できませんでした。私たちのRustへの愛は裏切られたのでしょうか!

Throughput (requests per second)

OSからみたRustとGoのコネクション処理

愛には困難や誤解がつきもの、落ち着いて考えてみましょう。gRPCの中身は、HTTP/2のサーバとクライアントであり、今回は、TCPコネクション数が多い条件で、tonicの性能が低いということになります。

tonicが複数のコネクションを処理する方法は、Rustで一般的に用いられているasync/awaitを用いた非同期プログラミングです。grpc-goは、Goが提供する言語レベルの軽量なスレッド(Goroutine)を用います。2つの方法はプログラミグモデルは違いますが、オペレーティングシステムからは大きな違いはありません。

共に、OSの提供するスレッドをコネクションごとに作成するのではなく、1つのスレッドが、ブロックしないソケットAPIを用いて、パケット待ちなどでブロックすることなく、準備ができたコネクションを順番に処理します。

Rustの非同期プログラミングも、Goの軽量なスレッドも、Linuxではepollシステムコールを使って実装されていますが、その詳細は、クラウドネイティブ時代にふさわしい話題ではないので、省略しましょう。大切なのは、システムコールを直接使ってプログラミングするのはしんどいので、非同期プログラミングや、軽量なスレッドなど、低いレイヤを隠蔽するおしゃれな手法が発明されてきたということです。

Rustでの新たな実装

コネクション数が増えると、tonicが遅い原因は非同期プログラミングの処理にありそうです。Rustは、標準の非同期プログラミングの処理機能(ランタイム)を提供しておらず、様々な実装が存在しています。tonicは、おそらく一番人気があるtokioランタイムを利用しています。

今回は、Rustの性能の限界をさぐるため、ランタイムを使わず、OSのシステムコールを直接使って、gRPCサーバを実装してみましょう。まずは、HTTP/2のサーバ機能が必要ですが、既存のRustのHTTP/2サーバ実装はtokioなどのランタイムを前提としているため使えません。クラウドネイティブ時代に、システムコールを直接使ってHTTP/2サーバを実装するのが許されるのは、学生の課題ぐらいですからね。パーサとして使えるライブラリを利用して、ベンチマークに必要な最低限の機能を実装します。次に、Protocol Buffersのフォーマットで、gRPCのメッセージをHTTP/2のリクエストとレスポンスとして処理する機能を実装します。

新たな実装は、gRPCのクライアント数が24,000の場合、grpc-goよりも1.5倍ほど高速になりました。あとは、性能を落とさず、ランタイムを実装するだけですね!

Throughput (requests per second)

まとめ

「エラー処理など、HTTP/2の機能をきちんと実装すると遅くなるのでは?」「Goでもシステムコールを直接使えば高速になるのでは?」「ランタイムのオーバヘッドは避けられないのでは?」などなど、様々な疑問がある?NTTでは、仲間を募集中です。連絡お待ちしています。

--

--

FUJITA Tomonori
nttlabs

Janitor at the 34th floor of NTT Tamachi office, had worked on Linux kernel, founded GoBGP, TGT, Ryu, RustyBGP, etc. https://twitter.com/brewaddict