Rustの非同期ランタイムが多すぎる?io_uringなやつを使おう!
AWS、Google、Microsoftらが、Rust Foundationを設立し、今やRustでなければクラウドネイティブじゃない、と言っても過言ではありませんよね。クラウドネイティブと言えば、スケーラブルなシステム、Goはgoroutineを標準機能として提供しますが、Rustのasync/awaitは、標準機能に含まれていない外部ライブラリを必要とします。悪いことに、複数のライブラリ(非同期処理ランタイム)が乱立し、APIの互換性もありません。Rustはクラウドネイティブなのだろうか、という疑問を抱きながら、いくつかのランタイムの性能を、いつものgRPCベンチマークで比較してみました。
比較対象
数多くのランタイムの中から、前回の記事で試した、Linuxの新しい非同期I/Oインターフェイスのio_uringを利用しているglommioと、普及している思われる、tokio、smol、async-stdランタイムの性能を比較してみました。後者3つのランタイムは、epollインターフェイスを利用しています。
ランタイムは、io_uringやepollなどのOSインターフェイスを隠蔽するため、アプリケーションはその違いを意識する必要はありません。しかし、それぞれのランタイムが提供する非同期APIには互換性がないため、複数のランタイムで動作するアプリケーションを実装するのは面倒です。
glommio
glommioは、io_uringインターフェイスしかサポートせず、比較的新しいLinuxカーネルでしか動きません。この大衆に迎合しない差別化で、先鋭的なユーザを引き付けることが期待されます。高性能なサーバを実装するためのC++のフレームワークであるSeastarに影響を受けており、CPU間でデータを共有せず、ロック競合を避けることで、CPU数に対する性能のスケーラビリティを実現するアーキテクチャが採用されています。
Tokio
Tokioは、デファクトであろうランタイムで、AWS、Microsoftなどクラウドネイティブな会社がそのユーザとして知られています。
smol
smolは、Tokioに対して、「A small and fast async runtime」というビジョンで始められたプロジェクトです。OSSプロジェクト、プロレス団体、宗教団体、どのような組織も巨大化すると、「立ち上げ時の理想が失われた」などの理由で、新たに小さな団体を立ち上げる人たちが出現しますが、そういうやつです。
async-std
glommio、Tokio、smolが、ネットワークやストレージなど、主にサーバ・クライアントの実装に必要なAPIのみを非同期化しているのに対し、async-stdは、文字列操作など、全ての標準APIを非同期化することを目指すというハードコアなやつです。
性能評価
以前の記事で実装した、gRPCベンチマークに必要な最低限の機能を実現したサーバーのコードを、上記の全てのランタイムで動作するように変更しました。
上記4つのランタイムに加えて、io_uringを使ったシンプルなランタイム(minimum)を実装し、評価対象として追加しました。glommioと違い、minimumは、io_uringを、epoll同様のソケットが読み書きできる状態になったことを通知するインターフェイスとして利用しています。従来のソケットAPIで、ソケットからの読み書きを実行しますが、epollのカーネル・ユーザ空間の引数のメモリコピーを避けることができ、性能向上が期待できます。
測定はAWSで実施し、サーバはc6gn.8xlargeインスタンス(32vCPU/64 GiB)、クライアントはc5n.9xlarge(36vCPU/96GiB)インスタンスです。1台のクライアントインスタンスは、同時に3,000個のgRPCクライアントを立ち上げ、合計で3,000,000個のリクエストを送信します。クライアント数を1、2、4、8台と増やし、サーバが1秒あたりに処理できたリクエスト数を測定した結果が下記になります。
glommioは、クライアント数が24,000の条件では、エラーが発生しベンチマークを完了させることができませんでした。
まとめ
今回の測定結果から判断するに、前回記事のio_uringの性能は、APIを効率良く使ってなかったのが原因で、高い性能が達成できる可能性がありそうですね。さらに、ベンチマークが利用しているglommioのネットワークAPIでは、不必要なメモリコピーが発生している点も改善の余地もありそうです。
Tokioもio_uringの対応を始めており、将来的には、アプリケーションの開発者が意識しなくても、適切にio_uringが使われるようになると期待できます。
Rustが標準機能として非同期処理ランタイムを提供しないことで、たくさんの仕事が生まれるという、Rustエンジニアへの愛です。NTTは仲間を募集中です。連絡お待ちしています。