第33章 クラスター化と EJB 非活性化


Web クラスタ化と EJB 非活性化は Seam では 1 つの共通のソリューションを共有するため一緒に説明していくことにします。 本章ではプログラミングモデルおよびクラスタ化と EJB 非活性化を使うことによってそれが受ける影響について見ていきます。 Seam によるコンポーネントおよびエンティティのインスタンスの非活性化、非活性化とクラスタ化との関連、 非活性化を有効にする方法について記載しています。 また、 Seam アプリケーションをクラスタにデプロイして HTTP セッションの複製が正しく動作していることを確認する方法についても記載しています。
まず、 クラスタ化に関する基本的な情報から見ていくことにします。次に JBoss AS クラスタへの Seam アプリケーションのデプロイ例を示します。

33.1. クラスタ化

Web クラスタリング としても知られるクラスタ化では、 クライアントにはアプリケーションのユニフォームビューを表示しながらこのアプリケーションを 2 台以上の複数の並列サーバー (ノード) で実行させることができます。 1 台または複数のサーバーに障害が発生した場合、 アプリケーションは生き残っているノードからアクセスすることができるよう負荷をサーバーに分散します。 ノードを追加するだけでパフォーマンスや可用性が高まるためスケーラブルなエンタープライズアプリケーションには極めて重要となります。 ただし、 障害を起こしたサーバーに保持された状態はどうなるのかという疑問が起こってきます。
今までのところ、 Seam は追加のスコープを含ませステートフルの (スコープされた) コンポーネントのライフサイクルを統制することで状態管理を行うことは理解されていることと思います。 しかし Seam の状態管理はインスタンスの作成、 保存、 破棄のみではありません。 Seam では JavaBean コンポーネントに対する変更の追跡や要求時に戦略的なポイントでその変更を保存するため、 要求がクラスタ内の 2 次ノードに移行した場合に変更を復元することができます。 ステートフル EJB コンポーネントの監視や複製は EJB サーバーによって処理されます。 Seam 状態管理ではステートフル JavaBean に同様の機能を提供します。
JavaBean コンポーネントの監視に加え、 Seam では管理エンティティインスタンス (つまり、 JPA および Hiernate のエンティティ) が複製時に付随しないようにします。 ロードすべきエンティティの記録を保持し、 2 次ノードで自動的にそれらをロードします。 この機能を利用するには Seam 管理永続コンテキストを使用する必要があります。 詳細は本章の後半で説明します。
次にクラスタ化用にプログラムを行う方法について見ていくことにします。

33.1.1. クラスタ化用のプログラミング

クラスタ環境で使用するセッションまたは対話スコープの可変の JavaBean コンポーネントは、すべて Seam API より org.jboss.seam.core.Mutable インターフェースを実装しなければなりません。 コントラクトの一部としてコンポーネントは dirtyflag イベントを管理する必要があり、 これが保存しなければならないフォームにユーザーが変更を加えたかどうかを示します。 このイベントは clearDirty() メソッドにより報告およびリセットが行われ、 このメソッドはコンポーネントの複製が必要かどうかを確定するため呼び出されます。 これによりオブジェクトに対するあらゆる変更に対しセッション属性の追加や削除に Servlet API を使用する必要がなくなります。
また、 すべてのセッションおよび対話スコープの JavaBean コンポーネントが シリアライズ可能 であることを必ず確認してください。 transient のマークが付けられているか @PrePassivate メソッドで null に設定されていない限り、 ステートフルコンポーネントのフィールドはすべてシリアライズ可能でなければなりません (EJB または JavaBean)。 transient または nullified のフィールドの値は @PostActivate メソッドで復元することができます。
リスト作成に List.subList を使用する場合、 問題が発生する可能性があります。 作成されたリストがシリアライズできないためです。 オブジェクトを自動的に作成するいくつかのメソッドにも同様の状況が発生することがあります。 java.io.NotSerializableException が発生した場合は、 この例外にブレークポイントを配置しデバッグモードでアプリケーションサーバーを稼働して問題となるメソッドを探します。

注記

クラスタ化はホットデプロイしたコンポーネントとは動作しません。 また、 開発環境以外ではホットデプロイが可能なコンポーネントの使用は避けてください。

33.1.2. Seam アプリケーションをセッション複製で JBoss AS クラスタへデプロイ

次の手順は seam-gen アプリケーションおよび Seam Booking サンプルに対して検証が行われました。
本項ではマスターとスレーブのサーバーの IP アドレスはそれぞれ 192.168.1.2192.168.1.3 であると仮定します。 両方のノードが要求に応答しセッションと通信していることを確認しやすいよう意図的に mod_jk ロードバランサーは使用しませんでした。
次のログメッセージは WAR アプリケーション vehicles.war のデプロイメントおよびそれに該当するデータソース vehiclesDatasource から生成されました。 Booking サンプルはこのプロセスに完全に対応しています。クラスタへのデプロイ方法に関する説明は examples/booking/readme.txt ファイルでご覧頂けます。
以降の手順はファームデプロイメントの方法を用いていますが、通常通りにアプリケーションをデプロイしてから起動順序に応じて 2 つのサーバー同士でマスターとスレーブの関係を決めさせることもできます。
チュートリアル内のタイムスタンプは混同を避けるためすべてゼロに置換しています。

注記

使用するノードが Red Hat Enterprise Linux または Fedora を稼働する別々のマシンに存在する場合、互いを自動的に認識し合わないことがあります。 JBoss AS のクラスタ化は jGroups によって提供される UDP (ユーザーデータグラムプロトコル) マルチキャスティングに依存します。Red Hat Enterprise Linux および Fedora に同梱される SELinux はデフォルトでこれらのパケットをブロックします。 パケットを許可するには iptables のルールを変更してください (root 権限)。 IP アドレスが 192.168.1.x とした場合、 コマンドは次のようになります。
  /sbin/iptables -I RH-Firewall-1-INPUT 5 -p udp -d 224.0.0.0/4 -j ACCEPT
  /sbin/iptables -I RH-Firewall-1-INPUT 9 -p udp -s 192.168.1.0/24 -j ACCEPT
  /sbin/iptables -I RH-Firewall-1-INPUT 10 -p tcp -s 192.168.1.0/24 -j ACCEPT
  /etc/init.d/iptables save
Copy to Clipboard Toggle word wrap

注記

ステートフルセッション Bean と HTTP Session 複製でアプリケーションを JBoss AS クラスタにデプロイする場合、 ステートフルセッション Bean のクラスに @Clustered (JBoss EJB 3.0 アノテーション API より) アノテーションを付与するか jboss.xml 記述子で clustered の印を付ける必要があります。 詳細については Booking サンプルを参照してください。

33.1.3. チュートリアル

  1. JBoss AS のインスタンスを 2 つ作成します (zip を 2 度展開するだけです)。
    HSQLDB を使用しない場合は JDBC ドライバを両方のインスタンスの server/all/lib/ にデプロイします。
  2. WEB-INF/web.xml に最初の子エレメントとして <distributable/> を追加します。
  3. org.jboss.seam.core.init にある distributable プロパティを true に設定して ManagedEntityInterceptor を有効にします (つまり、 WEB-INF/components.xml<core:init distributable="true"> と設定します)。
  4. 使用可能な IP アドレスが 2 つあることを確認します (同じインターフェースに 2 台のコンピュータ、 2 枚のネットワークカード、 または 2 つの IP アドレスがバインドされているということです)。2 つの IP アドレスは 192.168.1.2192.168.1.3 と仮定します。
  5. 最初の IP でマスターとなる JBoss AS のインスタンスを起動します。
      ./bin/run.sh -c all -b 192.168.1.2
    Copy to Clipboard Toggle word wrap
    ログはクラスタメンバーが 1 つ、 他のメンバーはゼロであると報告するはずです。
  6. スレーブとなる JBoss AS インスタンスの server/all/farm ディレクトリは空であることを確認します。
  7. スレーブの JBoss AS インスタンスを 2 番目の IP で起動します。
      ./bin/run.sh -c all -b 192.168.1.3
    Copy to Clipboard Toggle word wrap
    ログはクラスタメンバーが 2 つ、 他のメンバーが 1 つであると報告するはずです。 また、 マスターインスタンスから取得されている状態を表示します。
  8. -ds.xml をマスターインスタンスの server/all/farm にデプロイします。
    このデプロイメントの確認がマスターインスタンスのログに表示されるはずです。 スレーブインスタンスに対するデプロイメント確認の該当メッセージが表示されるはずです。
  9. アプリケーションを server/all/farm ディレクトリにデプロイします。 通常のアプリケーション起動メッセージが終了すると、マスターインスタンスのログにデプロイメントの確認が表示されるはずです。 スレーブインスタンスのログはデプロイメントを確認する該当メッセージを表示します (デプロイされたアーカイブが転送されるのに最長 3 分間待つ必要がある場合があります)。
これでアプリケーションは HTTP Session 複製によりクラスタ内で実行しています。次のステップはクラスタ化が正しく動作していることを確認する作業です。

33.1.4. JBoss AS クラスタで稼働しているアプリケーションの配信可能なサービスの検証

これでアプリケーションが 2 つの異なる JBoss AS サーバーで正しく起動するようになりました。 しかし、2 つのインスタンスが正しく HTTP Session を交換していることを確認することが重要です。 これによりマスターインスタンスが停止した場合にもアプリケーションはスレーブインスタンスで動作を続行できます。
まず、 マスターインスタンスでアプリケーションに行き最初の HTTP Session を開始します。 同じインスタンスで JBoss AS JMX Console を開き次の管理 Bean に移動します。
  • Category: jboss.cache
  • Entry: config=standard-session-cache,service=Cache
  • Method: printDetails()
printDetails() メソッドを呼び出します。 これによりアクティブな HTTP Session のツリーが表示されます。 ブラウザで使用しているセッションがツリーにあるセッションのいずれかに該当していることを確認します。
次にスレーブインスタンスに切り替え、JMX Console で同じメソッドを呼び出します。 このアプリケーションのコンテキストパスにまったく同一のツリーが表示されるはずです。
両方のツリーがまったく同一であれば両方のサーバーのセッションは同一であること判断できます。 次に、 データが正しくシリアライズおよびデシリアライズを行うかをテストする必要があります。
マスターインスタンスの URL よりサインインします。 次にサーブレットパスのすぐ後ろに ;jsessionid=XXXX を置き IP アドレスを変更して 2 番目のインスタンスの URL を構成します (セッションが別のインスタンスに引き継がれたのがわかるはずです)。
ここでマスターインスタンスを終了して、スレーブインスタンスからアプリケーションを継続して使用できるか確認してみます。 そのあと、 server/all/farm ディレクトリからデプロイされたアプリケーションを削除してインスタンスを再起動します。
URL の IP をマスターインスタンスの IP に戻し、 新しい URL に移動します。 オリジナルのセッション ID がまだ使用されているのがわかるはずです。
セッションまたは対話スコープの Seam コンポーネントを作成して適切なライフサイクルメソッドを実装することで、オブジェクトの非活性化と活性化を監視することができます。HttpSessionActivationListener インターフェースのメソッドが使用できます (EJB 以外の全コンポーネントで自動的に登録されます)。
public void sessionWillPassivate(HttpSessionEvent e);
public void sessionDidActivate(HttpSessionEvent e);
Copy to Clipboard Toggle word wrap
代わりに、2 つの public void のメソッドに @PrePassivate@PostActivate のマークをそれぞれ付けることもできます。 不活性化は各要求の最後に発生しますが、活性化はノードが呼び出されたときに発生するのを忘れないようにしてください。
複製を透過的にするために、 Seam は変更されたオブジェクトを自動的に追跡します。 このため、必要となるのはセッションまたは対話スコープのコンポーネントにある dirtyflag の管理のみで、 あとは Seam が JPA エンティティのインスタンスを処理してくれます。
トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2025 Red Hat