Java マルチテナンシーの紹介

クラウド・システムを対象とした IBM Java 7 R1 リリースの新機能について学ぶ

最近、IBM マルチテナント型 JVM がテクノロジー・プレビューとしての Java 7 R1 で利用できるようになりました。単一のマルチテナント型 JVM で複数のアプリケーションを実行すれば、クラウド・システムでアプリケーションの起動時間を短縮できるとともに、アプリケーションのメモリー・フットプリントを削減することができます。この記事では、マルチテナント型クラウド JVM を支えるテクノロジーを紹介し、この JVM を使用することでもたらされるメリットとそれに伴う代償の主なものを説明します。

2014年 5月 12日 ― 著者からのリクエストに従い、記事全体を通じて「IBM Java 727 R1」を「IBM Java 7 R1」リリースに変更しました。

2014年 5月 09日 ― 記事全体を通じて、「IBM Java 8 ベータ版」を「IBM Java 7 R1」リリースに変更しました。「参考文献」では、Java 7 へのリンク項目を追加して、Java 8 へのリンク項目を削除しました。

Graeme Johnson, J9 Virtual Machine Development Manager, IBM  

Photo of Graeme JohnsonGraeme Johnson は、IBM J9 Virtual Machine チームの開発マネージャー兼技術リーダーです。1994年に IBM (以前の Object Technology International) に入社してからは、仮想マシンとデバッガーの開発に携わり、VisualAge for Java および IBM/OTI Smalltalk ランタイムの両方に取り組みました。最近では、Apache Harmony プロジェクト、そして IBM Project Zero の Java/PHP ランタイム・サポートにフォーカスしていました。彼は定期的にカンファレンスで講演を行っています。JavaOne 2006 では Apache Harmony について、EclipseCon 2007 ではマルチプラットフォームの C 言語開発について、International PHP 2006 では PHP ランタイムの調査について講演しました。



Michael Dawson, Software Developer, IBM  

Photo of Michael DawsonMichael Dawson は、これまで 9 年間、J9 JVM チームと協力して、コアとなる JVM コンポーネントを実装してきました。彼は、さまざまなプラットフォームにわたる WebSphere Real Time plus Java 6 and Java 7 リリースをはじめ、何年も IBM Java の成果物に貢献してきました。この 2、3 年は、Java テクノロジーを対象とした IBM クラウドおよび仮想化の取り組みに貢献しました。EDI 通信サービス、クレジット・カード処理、オンライン・オークション、電子請求書などの e-コマース・アプリケーションを開発してサービスとして提供するチームで指導的役割を担った経験もあります。



2014年 7月 10日 (初版 2013年 10月 17日)

クラウド・プロバイダーは、システムを実行してサービスを提供するために必要なインフラストラクチャーのコストと、サービスがプロバイダーにもたらす利益を天秤にかけなければなりません。このような費用便益の検討では、プロバイダーは各種のアーキテクチャーを検討することになります。その選択範囲は、非共有型のアーキテクチャーから共有マルチテナント型アーキテクチャーにまで及びます。非共有型アーキテクチャーの場合、プロバイダーは完全に個々の顧客に専用のハードウェア、ソフトウェア、アプリケーションを提供します。一方、共有型のマルチテナンシーでは、複数の顧客のアプリケーションを単一のアプリケーションでサポートし、ベースとなるハードウェアとソフトウェアのすべてを共有します。

この各種アーキテクチャーの間での主なトレードオフは、分離と密度です。密度とは、特定のハードウェアとソフトウェアのセットで提供可能なシステムとサービスの数であり、共有されるリソースが多くなればなるほど、密度が高くなります。密度が高くなると、プロバイダーのコストは低くなりますが、それと同時に共有の増加によって、テナント (提供されている個々のシステムまたはサービス) 間の分離レベルが下がることになります。分離とは、あるテナントが他のテナントのアクティビティーやデータに影響を与える可能性の度合いです。

Java ベースのテナントの場合、アーキテクチャーの選択範囲には、JVM の共有/非共有も含まれます。最上位レベルのアプリケーションを共有するアーキテクチャーでは、必ず JVM を共有しなければなりません。JVM を共有すれば、メモリーとプロセッサー時間の両方が節約されますが、従来の JVM テクノロジーで JVM を共有すると、通常はインフラストラクチャー層の他の部分での分離がすべて解消されるため、最上位のアプリケーションでその分離を行わなければならなくなります。この記事では、IBM のテクノロジー・プレビューとしての Java 7 R1 リリース (「参考文献」を参照) で試用できるマルチテナント機能を紹介します。この機能を使用すると、デプロイ済みのアプリケーションには JVM を共有することによるメリットがもたらされる一方で、従来型の JVM を共有した場合に実現可能なレベルを上回る分離が維持されます。

マルチテナント型 JVM を使用するメリットと代償

マルチテナント型 JVM を使用することによる主なメリットとして、デプロイ済みのアプリケーションが複数の標準的な JVM を使用する場合に付き物のメモリーの消費を回避できることがあります。このオーバーヘッドが生じる原因には、以下に挙げるものがあります。

  • Java ヒープが数百メガバイトものメモリーを消費するため。ヒープ・オブジェクトがまったく同一だとしても、JVM 間でヒープ・オブジェクトを共有することはできません。さらに、JVM に最大量のヒープが必要になるのは短時間だけであっても、JVM は割り当てられたヒープのすべてを使用する傾向があります。
  • JIT (Just-In-Time) コンパイラーが数十メガバイトのメモリーを消費するため。生成されたコードが専用コードとしてメモリーを消費することが原因です。生成されたコードもかなりのプロセッサー・サイクルを費やすため、アプリケーションがプロセッサーを使用する時間も奪われてしまいます。
  • クラスの内部成果物 (その多く (StringHashtable など) は、すべてのアプリケーションで存在します) がメモリーを消費するため。これらの成果物それぞれのインスタンスが、JVM ごとに 1 つ存在します。
  • JVM ごとに、デフォルトでコアあたり 1 つのガーベッジ・コレクション・ヘルパー・スレッドがあるだけでなく、複数のコンパイル用スレッドもあるため。コンパイルまたはガーベッジ・コレクションのアクティビティーは、1 つ以上の JVM で同時に発生することがあります。この状況は、複数の JVM が限られたプロセッサー時間を求めて競い合うことになるため、最適ではない状態になる可能性があります。

マルチテナント型 JVM は、メモリー・コストと処理コストを抑えるだけでなく、複数のアプリケーションを単一の従来型 JVM で実行する場合に比べ、より望ましい形での分離を実現します。

共有 JVM の最初のテナントが起動された後は、JVM がすでに稼働状態にあることから、以降のアプリケーションの起動時間が短くなるというメリットもあります。起動時間の短縮は、スクリプトで使用されることの多い、短時間実行されるアプリケーションには特に有用です。

マルチテナント型 JVM を使用することによる主な代償は、それぞれに独立した JVM で実行されるアプリケーションほどには、各テナントが分離されないことです。例えば、マルチテナント型 JVM 自体での障害は、すべてのテナントに影響を及ぼします。

また、マルチテナンシー拡張機能を実装するために JVM が実行しなければならない処理によって、わずかながらもパフォーマンスが低下します。ただし、このパフォーマンス・ヒットは、テナントの数が増えるにつれ、減少していきます。それは、同じシステム内で複数の JVM を実行した場合のプロセッサーおよびメモリーのコストを回避することになるためです。


マルチテナント型 JVM の使用方法

他のテナントとランタイムを共有するようにするには、アプリケーションを起動する際に、アプリケーション・ユーザーは唯一の引数 -Xmt をコマンド・ラインに追加します。以下はその一例です。

java -Xmt -jar one.jar

これにより、アプリケーションは専用の JVM 上で実行されているかのように動作します (ただし、この記事の後で説明する制限事項が適用されます)。しかし実際には、アプリケーションは他のアプリケーションと並んで実行されています。マルチテナント型 JVM の拡張機能が、このようにアプリケーションを起動することを可能にし、JVM を共有する各テナントを互いに分離します。

テナントが起動されると、JVM ランチャーは既存の共有 JVM デーモン (javad) を探し出し、必要に応じて起動します

(図 1 を参照)。

図 1. JVM ランチャーが共有 JVM デーモンを自動的に見つけ (必要に応じて起動し) ます
共有 JVM デーモン (javad) を見つけて起動する JVM ランチャーのスクリーン・キャプチャーと図

2 番目のテナントが起動されると、そのテナントは既存の共有 JVM デーモンを見つけて、その JVM 内で自らを実行します (図 2 を参照)。

図 2. JVM ランチャーが既存の JVM デーモンを見つけて、そのデーモンに接続します
既存の JVM デーモン (javad) を見つけて、そのデーモンに接続する JVM ランチャーのスクリーン・キャプチャーと図

その結果、javad プロセス内には両方のテナントに共通の 1 つのブートストラップ・コードが存在するようになります。この仕組みにより、これらのテナントはランタイム構造の大部分を共有できるようになります。

このように、マルチテナント型 JVM を使用して既存のアプリケーションを実行するのは、コマンド・ラインに限られた変更を加えるのみでよいため簡単です。


分離の実現

通常、同じ (従来型の) JVM で実行される複数のアプリケーションが互いに分離されることはありません。それぞれのアプリケーションのアクティビティーが、他のアプリケーションが完了可能な処理に影響を及ぼします。しかも、静的フィールドを介して共有可能なデータには、すべてのアプリケーションからアクセスすることができます。これらの問題に、マルチテナント型 JVM は 2 つの方法で対処します。それは、静的フィールドの分離とリソースの制約です。

静的フィールドの分離

マルチテナント型 JVM では、クラスに含まれる不変の部分がテナント間で共有されます。このような不変の部分には、メソッドのコンパイル済みコード、JVM が使用するデータ構造、そしてこれらと同様のその他の成果物があります。不変の部分を共有すれば、複数の JVM を使用する場合に存在することになる別個のコピーが不要になるため、メモリーが節約される結果となります。ただし、マルチテナント型 JVM は、各テナントに対して静的フィールドのコピーを提供し、テナントそれぞれがコピーを持てるようにします。静的フィールドの分離 (および、各テナントは、概してそのテナントが作成したオブジェクトのインスタンスにのみアクセスできるという事実) により、各テナントは自身に関連付けられたデータにしかアクセスすることができません。その結果、テナント間でデータが分離されるというわけです。

リソースの制約: 望ましくない振る舞いへの対処

理想的な世界では、複数のテナントが協力して適切な方法で共有リソースを使用します。しかし、この不完全な世界では、バグと悪意のある振る舞いの両方が発生する恐れがあります。マルチテナント型 JVM で提供される制御可能な値は、「あるテナントが他のテナントに影響が及ぶように不正を行ってリソースを使用する」という能力が制限されるように構成することができます。制御可能な値には以下のものが含まれます。

  • プロセッサー時間
  • ヒープ・サイズ
  • スレッド数
  • ファイル I/O: 読み取り帯域幅、書き込み帯域幅
  • ソケット I/O: 読み取り帯域幅、書き込み帯域幅

これらの制御可能な値は、-Xmt コマンド・ラインで指定することができます。以下に例を示します。

  • -Xlimit:cpu=10-30 (CPU の最小 10 パーセント、最大 30 パーセント)
  • -Xlimit:cpu=30 (CPU の最大 30 パーセント)
  • -Xlimit:netIO=20M (最大帯域幅 20 Mbps)
  • -Xms8m-Xmx64m (初期ヒープ 8 MB、最大ヒープ 64 MB)

使用可能なすべてのオプションについては、Java 7 R1 のドキュメントに記載されています (「参考文献」を参照)。


パフォーマンスとフットプリント

非共有型 JVM とマルチテナント型 JVM 上での、アプリケーションのパフォーマンスおよびメモリー・フットプリントを比較するテストとして、システムがスワップするまで各 JVM 構成にアプリケーションを追加していきます (スワップした時点で、システムが「フル」になったと見なします)。非共有型のケースでは、アプリケーションを独立した JVM で実行し、アプリケーションを追加するごとに新規 JVM を起動します。マルチテナント型のケースでは、単一のマルチテナント型 JVM で別のテナントとしてアプリケーションを実行します。

表 1表 2 に、1 GB のメモリーを搭載したマシンと 64 ビットの JVM を使用してテストを実行した結果を記載します (すべてのケースで、圧縮参照を使用した JVM とバランス・ガーベッジ・コレクション・ポリシーを使用しています)。両方の表の「手動調整」列に示されているのは、最大限の密度 (表 1) または起動時間 (表 2) を実現しようとしてコマンドライン・オプションを手動で調整した後の通常の JVM での結果です。「デフォルト」列には、デフォルト・オプションを使用した通常の JVM での結果を示しています。

表 1 に示されているように、マルチテナント型 JVM では、非共有型 JVM の 1.2 倍から 4.9 倍の密度 (アプリケーションによって異なります) を達成しました。

表 1. 最大並行アプリケーション数
アプリケーション内容マルチテナント型手動調整デフォルトマルチテナント型 JVM による改善
Hello World「HelloWorld」を出力した後にスリープ30973634.2 倍から 4.9 倍
JettyJetty を起動してリクエストを待機34-181.9 倍
TomcatTomcat を起動してリクエストを待機28-132.1 倍
JRubyJRuby を起動してリクエストを待機3226151.2 倍から 2.1 倍

密度が増加した理由は、以下のものをはじめとする主要な成果物が共有されたためです。

  • ブートストラップおよび拡張クラス・ローダーによってロードされるクラスと関連成果物、ローダーがロードするクラスごとのヒープ Class オブジェクト、テナント間で安全に共有できるヒープ・オブジェクト (インターンされた String など)。
  • JIT でコンパイルされたコード、JIT でコンパイルされたクラスのメタデータ。
  • ヒープ: あるテナントがヒープ内で使用可能な領域を使用できるのは、他のテナントがその領域を必要としていない場合です。

表 2 には、マルチテナント型 JVM では平均起動時間を 1.2 倍から 6 倍高速化できたことが示されています。

表 2. 起動時間 (初回/平均)
アプリケーション内容マルチテナント型手動調整デフォルトマルチテナント型 JVM による改善
Hello World「HelloWorld」を出力した後にスリープ5709/138ms514/400ms3361/460ms3.3 倍
JettyJetty を起動してリクエストを待機7478/2116ms-6296/12624ms6 倍
TomcatTomcat を起動してリクエストを待機9333/6005ms-7802/7432ms1.2 倍
JRubyJRuby を起動してリクエストを待機12391/3277ms14847/4101ms7849/6058ms1.25 倍から 1.8 倍

表 2 からは、最初のアプリケーション・インスタンスの起動時間は、標準 JVM よりもマルチテナント型 JVM でのほうが一般に遅いことがわかります。この結果は、予想通りです。というのも、最初のインスタンスでは、マルチテナンシー拡張機能によってパスが長くなるため、起動に遅れが生じるからです。以降のインスタンスの起動時間は、一貫してマルチテナント型 JVM のほうが短くなります。

以上の結果は、開発中の JVM で得られた初期段階の結果であるため、これより改善することが可能です。さらに、これらの例では、アプリケーションがさまざまな時点でリソースが必要になったときに起こり得る共有については考慮されていません。典型的な JVM では、JVM ごとに必要なメモリー・フットプリントは、JVM の存続期間にわたって必要とされるところまで増大していく傾向があります。標準 JVM の場合、このメモリー・フットプリントの大半は共有されません。マルチテナント型 JVM では、リソース要件が重複していなければ、ヒープとネイティブ成果物のメモリーを簡単に共有することができます。


制限事項

マルチテナント型 JVM の最終目標は、すべての Java アプリケーションを変更することなく実行できるようにすることです。現時点では、Java 仕様が課している制限事項、そして現在の実装に伴う制限事項により、この目標を達成することはできません。既知の制限事項の主なものとしては、以下の内容が挙げられます。

  • JNI (Java Native Interface) ネイティブ: マルチテナント型 JVM は、JNI ネイティブの分離には対応していません。そのため、ユーザー指定の JNI ネイティブを使用するアプリケーションをマルチテナント型 JVM で実行するのは安全ではない可能性があります。そのようなアプリケーションは、JVM 全体の処理に影響を与える恐れや、別のテナントのデータにアクセスする恐れがあるためです。ただし、使用する JNI ネイティブに十分な「信頼」が伴っていれば (例えば、よく知られているミドルウェアであるなど)、そのリスクを許容することは可能です。さらに OS は 共有 JVM プロセスに対して、JNI ネイティブが配置されている共有ライブラリーのコピーを 1 つしかロードすることを許していません。そのため、複数のテナントが同じ共有ライブラリー内にある同じ JNI ネイティブをロードすることは不可能です。
  • JVMTI (Java Virtual Machine Tool Interface): デバッグとプロファイリングのアクティビティーは、JVM サーバーを共有するすべてのテナントに影響を及ぼします。そのため、マルチテナント型 JDK では現在、これらの機能はサポートされていません。これは、さらなる取り組みが予定されている領域です。
  • GUI プログラム: SWT などのライブラリーは、ネイティブ層でグローバルな状態を維持するようなので、マルチテナント型 JDK ではサポートされていません。

まとめ

この記事では、マルチテナント型 JVM を紹介し、その利用方法と、マルチテナント型 JVM を使用するメリットと代償について説明しました。読者の皆さんが マルチテナント型 JVM に興味を持ち、ベータ版を試してフィードバックを寄せてくださることを願います。マルチテナント型 JVM は、これを使用するのに適した環境には大きなメリットをもたらすはずです。

参考文献

学ぶために

製品や技術を入手するために

  • Java 7 R1 ダウンロード (Linux): IBM Developer Kit for Linux, Java Edition (および User Guides) をダウンロードしてください。
  • Java 7 R1 ダウンロード (AIX): Java Standard Edition on AIX および IBM WebSphere Real Time on AIX を対象とした Developer Kits、User Guides、サービス情報をダウンロードしてください。
  • Java 7 R1 ダウンロード (z/OS): Java 対応テスト一式をパスした、フル機能の z/OS 向け Java 製品を入手してください。
  • IBM 製品の評価版をダウンロードして、DB2、Lotus、Rational、Tivoli、WebSphere が提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

  • developerWorks コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Cloud computing
ArticleID=948581
ArticleTitle=Java マルチテナンシーの紹介
publish-date=07102014