Double your performance: virtual threads (fibers) and JDK 15/16!

原文はこちら。
The original article was written by Bela Ban (Visiting Researcher, Dept. of Computer Science, Cornell University).
http://belaban.blogspot.com/2020/07/double-your-performance-virtual-threads.html

トランスポートにUDPをお使いで、そのパフォーマンスを倍増させたい場合には是非お読みください。

TCPを使っている場合、パフォーマンスはあまり変わりませんが、最近の JDK や仮想スレッド (virtual thread、以前はfiberと呼ばれていました)がもたらすものに興味関心をお持ちの方がいらっしゃるかもしれません。

Loom – Fibers, Continuations and Tail-Calls for the JVM
https://openjdk.java.net/projects/loom/

Virtual threads

仮想スレッドは軽量なスレッドで、以前のグリーンスレッド(Green Threads)のコンセプトに近いものです。カーネルではなく、JVMがこの軽量スレッドを管理します。多くの仮想スレッドは同じOSネイティブ(キャリア)スレッド(もちろん1度に1個だけです)にマッピングできるため、数百万もの仮想スレッドを持つことができます。

仮想スレッドは継続(continuation)を使って実装されていますが、それは枝葉の部分です。重要なのは、(LockSupport.park()などの)JDKでの全てのブロッキング呼び出しが、ブロックせずにyield(明け渡す)ように変更された、という点です。つまり、貴重なネイティブキャリアスレッドを無駄にするのではなく、シンプルに非実行状態(non-RUNNING state)に移行する、ということです。ブロックが終わると、スレッドはRUNNABLEとして再度マークされるだけで、スケジューラは引き続き中断した箇所からcontinuation(継続)を続けます。

主な利点は以下の通りです。

  • ブロッキング呼び出しを(例えばリアクティブ呼び出しに)変更する必要はありません
  • スレッドプールは不要です。仮想スレッドを作るだけでOKです
  • (ブロッキング呼び出しの削減および廃止により)コンテキストスイッチが減ります
  • 数多くの仮想スレッドを持つことができます

仮想スレッドがJDKで使えるようになるまでには少々時間がかかりますが、JGroupsではすでにこのサポートを追加しています。トランスポートに

set use fibers = "true"

と指定するだけで利用できます。JVMが仮想スレッドをサポートするようになれば仮想スレッドを使います。サポートされていないJVMの場合はフォールバックして、通常のネイティブスレッドを使います。

UDP: networking improvements 

仮想スレッドは JGroups に利点をもたらしますが、その他のパフォーマンスの向上は、より新しいJDKを試すことで得ることができます。

JDK 15から、DatagramSocketsとMulticastSocketsの実装は、DatagramChannelsとMulticastChannelsに委譲するように変更されました。さらに仮想スレッドもサポートされます。

JEP 373: Reimplement the Legacy DatagramSocket API
http://openjdk.java.net/jeps/373

これにより、DatagramChannelsとMulticastChannelsを使うUDPのパフォーマンスが向上します。

ネットワークのコード改善と仮想スレッドの組み合わせは、以下のような、UDPの驚くべき結果をもたらします。

Performance

JDK 11、16-ea5、16-loom+2-14を載せた物理ノード(1Gbit Ethernet)8個で構成されるクラスタで、UPerfを使ってテストしました。JDK 11、JDK 16-ea5はネイティブスレッド、16-loom+2-14は仮想スレッドを使っています。

UPerf
http://www.jgroups.org/manual5/index.html#UPerf

こちらを見ると分かるように、UDPのパフォーマンスは、JDK 11では44,691でしたが、JDK 16-ea5では81,402と82%も向上しました。仮想スレッドを有効にすると、16-loom+2-14では88,252と、16-ea5からさらに8%も向上しています。

結果、JDK 11と16-loomの間では、97%ものパフォーマンスの差が出ました。

TCPのパフォーマンスの差はごくわずかです。これは、TCP コードがJDK 11で既に最適化されていたからだと思われます。

JDK 16-loom+2-14 で実行すると、UDP のパフォーマンスが TCP と同等になっていることがわかります。実際のところ、UDPはTCPよりも3%速いのです。

ご自身で試したい場合には、JGroupsのGithubリポジトリにアクセスし、JAR (ant jar) を作成してください。または、この変更を含んだ45.0.0/Finalをまもなくリリースするので、それをお待ちください。私はすぐに変更を含む 5.0.0.0.Final をリリースする予定です。

JGroups – A Framework for Group Communication in Java
https://github.com/belaban/JGroups

4.x ブランチに変更をバックポートするかどうかはわかりませんけど。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中