この記事は、新しいJavaソケット・ダイレクト・プロトコル (SDP)の技術について概説します。SDPは、最近、Java7 SDKで導入された、非常に画期的な技術です。SDPにより、ウルトラ・ハイ・パフォーマンス・コンピューティング(UHPC)環境において、Javaのどこにでもある共通の機能とめったにないユースケースの利点を利用できるようになります。それが、InfiniBandのリモート・ダイレクト・メモリ・アクセス (RDMA) 機能へのネイティブアクセスです。RDMAは、オペレーティングシステムを介さずに、直接、他のコンピュータのメモリにアクセスするように、低遅延アプリケーションのプロトコルを提供します。UHPC環境は、最も厳しい、妥協を許さない低遅延で高いスループットの要求を可能なものにします。そのため、UHPCが最高のRDMA機能を利用できるようにする必要があるのは当然でしょう。Java 7でソケット・ダイレクト・プロトコルを提供するようになり、ネイティブのInfiniBand RDMA機能の全部の力を直接利用できるJavaアプリケーションコードを書けるようなJavaプラットフォームを、今ではUHPC環境で提供しています。
新しいJavaソケット・ダイレクト・プロトコルを掘り下げてみる前に、JavaのネットワーキングとソケットAPIの歴史を簡単に見てみよう。
1995年、Sun Microsystemsは世界にJavaを示し、すぐに「Java - 一度書けば、どこでも実行できる(Write Once, Run Everywhere)」というどこででも認識されるキャッチフレーズで、このプラットフォームを広く知らせ始めました。私たちがみんな知っているように、この背後にある考え方はシンプルです。C++コードでアプリケーションを書く代わりに(「どこでも実行できる」という移植性をいくらか持っていても、ビルドやデプロイが非常に難しい)、Javaというものでアプリケーションコードを書き、仮想マシンでビルド/デプロイができます(OS実行環境下ではありません)。これにより、Javaアプリケーションプログラマは、Java仮想マシン(JVM)に移植性を完全に任せ、移植性をまったく気にしなくてよくなりました。JVMは、次のような約束をしました。1つのJava VM(ある特定の基本OS)で動くJavaコードをビルド/デプロイできれば、プラットフォームは、まったく同じコードがどのOSでも(対応するJava VMが利用できれば)動くことを保証します。条件付のコンパイルやプリプロセッサマクロはもう必要ありませんでした。(C++と#ifdefの地獄を覚えていますか? アプリケーションプログラマを苦しめていた重荷を、今ではJVMが解放しているのです。)
これは、すべて非常に役に立つことであり、アプリケーションプログラミングコミュニティに快く受け入れられました。私たちが知っているように、Javaは、素早く、強烈に、世界中で受け入れられました。コンピューティングの数多くのプログラミング言語プラットフォームの歴史において、それほどのペースで受け入れられたものはありませんでした。
最初、Sunは、ちょうど3つのオペレーティングシステムで動くJava VMを提供しました。(i) Solaris (ii) Linux (iii) Windowsです。Microsoftは、その2、3年前(1993)に、WindowsでWinSOCKプロトコルスタックを提供したところだったので、WindowsはMicrosoftが完全にサポートするAPIを使って、TCP/IPネットワーキングを実施できました。様々な*nixシステムは、(もちろん)1970年代からTCP/IPを使っていました。MicrosoftのWinSOCKの導入は、Javaがなるべき姿になるためには、絶対に必要なものでした。WinSOCKなしでは、java.net.* やjava.io.* APIをサポートするWindows VMを提供することはできませんでした。それなしでは、Javaは、世界のデスクトップを独占するOSを動かす、完全なネットワーク機能を持つVMをビルドできませんでした。「もしかすると100万デスクトップ」に届くJavaの代わりに、完全にTCP/IPをサポートするWindowsと共に、Javaは今では「もしかすると100億」に届くものになりました。
状況が変わる。
確かに、Javaは、今でも「一度書けば、どこでも実行できる」ものです。移植性は、今でも最重要事項です。しかし、Java 7とソケット・ダイレクト・プロトコルで、Java VMではもっとずっと多くのことができます。移植性は、唯一の優先事項ではありません。今、ウルトラ・ハイ・パフォーマンスのユースケースに適応させることが、Java VMの重要な優先事項です。ソケット・ダイレクト・プロトコルで、Java VMは、同じネットワーキングと、InfiniBandの本来の力に直接アクセスするソケットAPIを提供できます。InfiniBandは、Ethernetよりもずっと速いものです。InfiniBandは、UHPコンピューティング環境で最適な物理ネットワークレイヤのプロバイダです。
InfiniBandが何か、Java 7 VMによって、どのようにアプリケーションがネイティブのInfiniBandの機能を使えるようになるのかについて、すぐ後で説明します。
注目すべきことの1つ(特に歴史的観点から)は、Javaが2つのオペレーティングシステム上でソケット・ダイレクト・プロトコルを提供すると決めたことです。Microsoft Windowsは、これらのオペレーティングシステムのうちの1つではありません。Java 7 SDPをサポートする2つのオペレーティングシステムは、SolarisとLinuxです。Solaris SDPサポートは、Solaris 10以降、すべてのバージョンで標準になっています。物理的なInfiniBand NICを持つ限り、Java 7 SDPはすぐに使えるでしょう。Linuxでは、SDPサポートは、Open Fabrics Enterprise Distributionパッケージで配布されます。使っているLinuxのバージョンがOFEDデバイスドライバで設定されているかどうか、そして、物理的なInfiniBand NICアダプタを持っていることを確認するには、単に次のようにタイプします。
egrep "^[ \t]+ib" /proc/net/dev
このコマンドで何か出力されたら、このオペレーティングシステムでJava 7 SDPを使う準備ができています。
すべてのjava.net.*とjava.io.*アプリケーションコードは、もちろんJava 7 VMを使うMicrosoft Windowsで動きますが、ソケット・ダイレクト・プロトコルを使わずに動きます。(そのため、物理レイヤプロバイダとしてEthernetで動きます。) WinSOCK Directを経由して、InfiniBandのサポートを提供するWindows Serverバージョンで動かしても、同じでしょう。もう一度言いますが、すべてMicrosoftで動くでしょう。ただ、Microsoftではないところ (例えば、*nix)と同じくらい速くは動きません。
実際に変わったこと。
オペレーティングシステムのネットワークプロトコルスタックへのJava APIブリッジについてお話しましょう。まず初めに、ネットワークレイヤの標準開放型システム間相互接続(OSI)モデルを見てみましょう。
# |
レイヤ |
プロトコル |
Java SDKコアAPI |
7. |
アプリケーションレイヤ |
HTTP、FTP、SSL等 |
java.net.HttpURLConnection、javax.servlet.HttpServlet |
6. |
プレゼンテーションレイヤ |
#Javaでは、アプリケーション/プレゼンテーションOSIレイヤを区別しない |
|
5. |
セッションレイヤ |
NetBios、RCP |
#OSIセッションレイヤのJava SDKコアサポートはない |
4. |
トランスポートレイヤ |
TCP、UDP |
java.net.Socket、java.net.ServerSocket、java.net.Datagram |
3. |
ネットワークレイヤ |
IP |
Java.net.InetAddress |
2. |
データリンクレイヤ |
PPP |
#OSIデータリンクレイヤのJava SDKコアサポートはない |
1. |
物理レイヤ |
Ethernet、InfiniBand |
#OSI物理レイヤのJava SDKコアサポートはない ただし …
Java 7 ソケット・ダイレクト・プロトコル (InfiniBandからjava.net.* and java.io.* コアAPIへのVMブリッジ) |
OSIネットワークレイヤビューにおけるJava 7ソケット・ダイレクト・プロトコルの技術は、Javaアプリケーションコードをできる限り「ハードウェアに近い」ものにします。Java SDPは、VMを通して、アプリケーションコードから*ネイティブ*で*物理的*なInfiniBandへ、*ダイレクト* (SDPの‘D’)ブリッジを提供します。アプリケーションでコアのjava.net.* や java.io.* APIの使用を変えずに、Java 7 SDPの技術によって実現できます。それだけでなく、InfiniBand OSデバイスドライバやライブラリ(別名InfiniBand VERBレイヤAPI)へJAVA VMの特別なジョイントポイントを構成することで、トランスポートレイヤOSリソース(OSIレイヤ4)のJava APIであるjava.net.* や java.io.* のアプリケーションコードの使用は、従来のネットワークプロトコルスタック(例えば、OSIレイヤ3をバイパスしたり、OSIレイヤ2をバイパスしたりできる)をバイパスしたり、*直接* InfiniBand(OSIレイヤ1)に行ったりできます。パフォーマンス上得られるものは非常に大きくなります。
Java 7とソケット・ダイレクト・プロトコルで、JavaはRDMA(リモート・ダイレクト・メモリ・アクセス)をサポートする
RDMAとは、リモート・ダイレクト・メモリ・アクセスのことです。RDMAは、ネットワーク上の(*nixユーザアドレス空間を実行している)2つのJava VMプロセス間で、アプリケーションのバッファを動かす方法です。RDMAは従来のネットワークインタフェースとは異なり、オペレーティングシステムをバイパスします。これにより、RDMAを使ってJava SDPは、以下のことを実行できます。(i) 絶対的な低遅延 (ii) 最高のスループット (iii) 最小CPUフットプリント
RDMAへJavaジョイントポイントを公開することで、SDPは暗黙的にJavaが無理やり「ゼロコピー」の機能を提供するようにします。「ゼロコピー」とは、CPUが1つのメモリから別のメモリにデータをコピーするタスクを実行しないコンピュータの操作のことです。ネットワークプロトコルスタックのゼロコピーバージョンは、特定のアプリケーションプログラムのパフォーマンスを大幅に向上させ、より効率的にシステムリソースを利用します。マシンの別の部分で並行してデータをコピーしながら、CPUが別のタスクに進めるようにして、パフォーマンスを向上させます。また、ゼロコピー操作は、ユーザ空間とカーネル空間の間の時間消費モードの切り替え数を減らし、システムリソースをより効率的に利用できるようにします。単純なシステムコンポーネントでコピーできる時に、高性能のCPUを使って、比較的簡単なタスクである大量のコピー操作を実行するのは無駄なことです。ここで私たちが話しているゼロコピーの機能は、java.nio.channels.FileChannelのtransferTo() APIを使って達成できるゼロコピー機能ではないことに注意する必要があります。これは、もっとずっと高性能です。Java 7 SDPで、ネイティブのInfiniBandゼロコピープロトコル実装を直接使います。
典型的なJavaデプロイメントビューの中で、ソケット・ダイレクト・プロトコル機能がどのように見えるのか描いてみよう
下図では、Node 1(java.net.Socket writer)とNode 2(java.net.ServerSocket listener)が、SDPをサポートするために構成、起動されたJava 7 VMにどのようにデプロイされるかを描いています。OSのシステムコールやサービスが呼び出されることなく、InfiniBandネットワークの中で、2つのJVMが1つのVMから別のVMヘアプリケーションデータバッファを交換できるようにしています。信じられないことですが、Javaのデータ転送は完全に両方のオペレーティングシステムをバイパスします。
- Java 7アプリケーション=Node 1 (SDPを使うために起動されたJVM)は、java.net.Socket APIを使用し、ネットワーク内のアプリケーションデータのブロックをjava.net.ServerSocket listenerへ書き出す。
- JVMはSDPを使うために起動されたので、オペレーティングシステムTCP/IPスタックは完全にバイパスされる。アプリケーションデータは、InfiniBandのRDMA機能に直接書き込まれる。(InfiniBandがネットワークインタフェースカードの物理プロバイダでなければならない)
- Java 7アプリケーション=Node 2 (SDPを使用するために起動されたJVM)は、java.net.ServerSocket APIを使用し、アプリケーションデータのブロックがjava.net.Socketライタからネットワーク内のRDMAを通って到着するのを聞き出す。(InfiniBandがネットワークインタフェースカードの物理プロバイダでなければならない)
- データは、*直接*、Java 7 VMアプリケーションバッファに送られた! Node 1のOSやNode 2のOSから呼ばれるOSシステムやサービスコールは関係していない。これがJava 7ソケット・ダイレクト・プロトコルの力だ。
SDPを使ったJava 7とJava 6で同じアプリケーションを動かす場合、論理的パフォーマンスの違いは何か?
下図のさらに詳細な図は、2つの異なるシナリオでNode 2を示しています。(前述した図から)
- 構成されたSDPでJava 7を使う(下図の左側) Node 1の伝達データをNode 2で受け取ったものは、どのようにOSIネットワークレイヤプロトコルスタックを移動し、Javaアプリケーションに入るのか? 何段階のステップが必要か? たった1段階だ! (下図を参照してください。これはUHPC Javaアプリにとって、素晴らしいニュースです。今、UHPC環境は、Java 7を使って必要なことをできます。)
- Java 6を使う(SDPはない - 下図の右側) Node 1の伝達データをNode 2で受け取ったものは、どのようにOSIネットワークレイヤプロトコルスタックを移動し、Javaアプリケーションに入るのか? 何段階のステップが必要か? 5段階必要だ。(下図を参照してください。これは、よく見るTCP/IPプロトコルスタックです。SDPではありません。これは、大抵は動きますが、UHPC環境ではうごきません。UHPC環境は、Java 6を使って必要なことができません。)
ソケット・ダイレクト・プロトコルを使用するためにJava 7 VMをどのように管理し、構成するか?
以下は、Java 7 SDPを紹介するOracleのチュートリアルページの構成セクションからまとめています。
SDP構成ファイルは、Java VMが起動時にローカルファイルシステムから読み込むテキストファイルです。SDP構成ファイルは、ちょうど2つの異なるタイプのエントリがあります。エントリの各タイプは、1行毎に書かれています。
- SDP構成コメント行
- SDP構成ルール行
コメントは、行の最初にハッシュキャラクタ(#)が置かれています。ハッシュキャラクタの後はすべて無視されます。
構成ルール行には、ちょうど2つのタイプのルールがあります。
- BINDルール
- CONNECTルール
「バインド」ルールは、TCPソケットがルールに合うアドレスとポートにバインドされた時に、SDPプロトコルトランスポートがいつでも使われるというルールです。「コネクト」ルールは、バインドされていないTCPソケットがルールに合うアドレスとポートに接続しようとした時に、SDPプロトコルトランスポートが使われるというルールです。
ルールはSDP構成ファイルで決められていますが、Java VMは、InfiniBandのVERBS/RDMAプロトコルスタックを持つ、通常のTCP/IPプロトコルスタックをいつ置き換えるかを、正確に知ることができます。
最初のキーワードは、ルールがbindルールかconnectルールかを示します。次のトークンは、ホスト名かリテラルIPアドレスかを指定します。 リテラルIPアドレスを指定する場合、IPアドレスの範囲を示すプレフィックスも指定できます。3番目と最後のトークンはポート番号かポート番号の範囲です。
このサンプルの構成ファイルの以下の記述を考慮してください。
# Use SDP when binding to 192.0.2.1
bind 192.0.2.1 *
# Use SDP when connecting to all application services on 192.0.2.*
connect 192.0.2.0/24 1024-*
サンプルファイルの最初のルールは、SDPがローカルIPアドレス192.0.2.1のどのポート(*)で使われるかを指定します。InfiniBandアダプタに割り当てられたローカルアドレス毎にバインドルールを追加できます。(InfiniBandアダプタは、InfiniBandのネットワークインタフェースカード(NIC)と同じです。) いくつかIBアダプタを持っている場合、それらのアダプタに割り当てられた各アドレスに、バインドルールを使いましょう。
サンプルファイルの2番目のルールは、192.0.2.*に接続する時やターゲットポートが1024かそれよりも大きい時にはいつでもSDPが使われることを指定します。IPアドレスのプレフィックス /24 は、32ビットIPアドレスの最初の24ビットが指定したアドレスに合わなければいけないことを示しています。IPアドレスの各部分は、8ビットを使用します。そのため、24ビットは、IPアドレスが192.0.2で、最後の値は何でも指定できることを示しています。ポートトークンの-*という記述は、「それ以上」であること指定します。1024から2056のようなポートの範囲は有効であり、指定した範囲の終点を含んでいます。
ソケット・ダイレクト・プロトコルを使うためにどのようにJava 7 VMを起動するか?
&> java \ -Dcom.sun.sdp.conf=sdp.conf \ -Djava.net.preferIPv4Stack=true \ Application.class
起動されるネットワーク形式として、IPv4Stackを使うことに注意してください。Java 7とInfiniBandは、よりモダンなIPv6ネットワーク形式を使いますが、SolarisとLinuxの2つの間のマッピングはサポートされていません。そのため、SDPを使うJava 7 VMを起動する時は、基礎となって、よく使われる(そして、何十年もの間信頼されている)IPv4ネットワーク形式を常に使ってください。
SDPをサポートして起動したJava 7 VMでアプリケーションを動かす時、どのくらいパフォーマンスの改善が期待できるか?
これは、もちろん究極の質問です! Java 7 SDPを使うことで、一体何が得られるのでしょうか? この質問に対する答えは、絶対にこの記事の内容から決められるものではありません。パフォーマンスの向上は、様々な要因によります。この記事は終わりに近づいていますが、以下のことは常に本当であることを忘れないでください。
InfiniBandはEthernetよりもかなり速く、High Performance Computing Advisory Councilが発表した総合的な研究によると、InfiniBandは、Ethernet(10GE)よりも600%の低遅延と370%のスループットパフォーマンスを提供することを示す、具体的な測定結果を出しています。
また、Java 7 SDPはRDMAと最高のゼロコピーの実装を使います。OSネットワークTCP/IPスタックを100%バイパスして伝達されます。そして、カーネルのアドレス空間にあるシステムコールとユーザのアドレス空間にあるアプリケーションコードバッファの間でデータを伝達する時に起こるコンテキストの切り替えも同様です。
これらのことはすべてJava SDK APIが完全に見える状態で行われます。java.net.*やjava.io.*は1行も変更する必要がありません。
最後に、物事はいろいろと変化してきましたが、コアJavaの精神は同じままです。今また、Javaの初期の頃のように(地獄のような移植性の複雑さからアプリケーションコードを切り離すためにJVMが重荷を背負った時)、プライオリティ機能を提供するという完全な重荷を、もう一度JVMが背負ったのです。今回は、ソケット・ダイレクト・プロトコル機能です。実際に、オリジナルのJavaのスローガンは、ほぼそのまま残ります。(この刺激的な現代を反映する小さな新しいフレーズです。Java 7 SDP – 一度書けば、どこでも実行できる。ある場所では驚くほどに!
著者について
Ben D. Cotton III氏は、J.P.Morgan ChaseのITコンサルタントであり、現在、UHPC LinuxプラットフォームでJavaのデータグリッド技術を使い、リアルタイムの流動性リスクに関する情報を集めています。Ben氏は、Java Community Processのメンバであり、2つのJCPエキスパートグループに属しています。1つは、キャッシングのJava標準APIを定義するグループ(JSR-107)であり、もう1つは分散データグリッドのグループ(JSR-347)です。Ben氏は、1985年5月にRutgers Universityを卒業し、コンピュータサイエンスの学位を取得しました。最初の11年間、AT&T Bell LaboratoriesでC++コードを書き、数多くの特許を持つテレコミュニケーションネットワークの分析をサポートし、プロトコルを規定しました。その後、14年間、低遅延と取引債権/デリバティブ電子商取引、手形交換、値付け、リスクシステムをサポートするJavaコードを書いています。