レベル: 中級 Shravan K Kudikala, Senior Staff Software Engineer, IBM India Software Labs, IBM
2008年 09月 20日 この記事では、お客様のさまざまな現場での経験を基に、WebSphere Message Broker を使用して高い信頼性と拡張性を備えた ESB ソリューションを開発およびデプロイするためのベスト・プラクティスの概要を説明します。
はじめに
IBM® WebSphere® Message Broker (以下、「Message Broker」と呼びます) はエンタープライズ・サービス・バス (ESB) として機能し、多様なプロトコルの汎用的な接続だけでなく、構造化と非構造化の両方のデータを使用するアプリケーションのデータの変換や加工を可能にします。
メッセージ処理のパフォーマンスはハードウェアの能力、ソフトウェアの構成、メッセージ・フローとメッセージ形式の設計と実装、メッセージ・フロー・インスタンス数などのさまざまな因子に左右されます。この記事では、多様なお客様の現場でパフォーマンスとメッセージ・フロー・サービスの可用性を向上させるのに役立った、実装とデプロイメントのベスト・プラクティスについて説明します。関連する WebSphere MQ やデータベースの実装のベスト・プラクティスについては、詳細な説明はしませんが、Message Broker のアプリケーションの観点から少し触れます。あらゆる状況に対処できるベスト・プラクティスというものはありません。ここで取り上げるベスト・プラクティスも、場合によっては、アーキテクチャーの柔軟性や個別のお客様の要件や能力に応じて手を加える必要があります。
ベスト・プラクティスの分野
- メッセージ・フロー
- パフォーマンスの問題を引き起こす恐れのある実装を回避する方法といった、メッセージ・フローの開発段階におけるベスト・プラクティスです。
- ESQL
- 純粋にパフォーマンス向上の観点から、再利用可能なコードを開発する、メッセージ・フロー内でメッセージ転送を最小限に抑えるために ESQL コードを最適化するといった、メッセージ・フローの ESQL 開発におけるベスト・プラクティスです。
- パブリッシュ/サブスクライブ
- メッセージのルーティングにパブリッシュ/サブスクライブ・モデルを使用するユーザーのためのベスト・プラクティスです。集合や複製に関するベスト・プラクティスは取り上げません。
- Message Broker から見た WebSphere MQ のベスト・プラクティス
- このセクションでは関連する WebSphere MQ のベスト・プラクティスのすべては説明しませんが、Message Broker が MQ クライアント・アプリケーションとして機能する場合に、WebSphere MQ をチューニングしてパフォーマンスを向上させる方法については説明します。
- Message Broker から見たデータベースのベスト・プラクティス
- このセクションでは関連するデータベースのベスト・プラクティスのすべては説明しませんが、Message Broker がデータベースのクライアント・アプリケーションとして機能する場合に、WebSphere MQ をチューニングしてパフォーマンスを向上させる方法については説明します。
- 構成
- Message Broker のセットアップ、構成、デプロイメントの各フェーズにおけるベスト・プラクティスです。高可用性環境固有のベスト・プラクティスは取り上げません。
メッセージ・フロー
- ビジネス・ロジックから構成情報を分離するために、お客様が構成情報を外部化してファイルやデータベースに格納することがよくあります。この手法を使うとパフォーマンスが低下する可能性があります。これは、構成ファイルやパラメーター・ファイルを読み取るのはノードの最初のインスタンスが作成されたとき、あるいは最初のメッセージが処理されるときの 1 回のみであって、メッセージごとにループでチェックするものではないためです。Message Broker は入出力指向というよりも CPU 指向です。そのため通常、ファイルやデータベースが関係する入出力操作はできるだけ避けるのが望ましいのです。
- ビジネス・ニーズによってメッセージを全体に構文解析しなければならない場合を除き、できるだけ部分構文解析法を使用します。メッセージ・フローの最後に MQOutput などの出力ノードがある場合は、メッセージのシリアル化 (ビット・ストリームへの変換) が発生してメッセージはすべて解析されます。この Message Broker の機能によってパフォーマンスを高めることができるため、可能な限りこれを活用してください。
- 処理コストはメッセージ・ツリーのサイズに直接比例します。そのため、メッセージ・ツリーのサイズと設計は、処理コストの削減に非常に重要な役割を果たします。例えば、メッセージのルーティングの決定に使われる可能性のあるフィールドはすべて、メッセージの先頭に置きます。部分構文解析によって、メッセージ・ツリーは全体に解析されないまま次のノードに送られます。MQRFH2 usr フォルダーなどの、ユーザーが保守できるデータ・フォルダーがメッセージ・ヘッダーに含まれている場合は、決定を下すのに必要なルーティング要素をその中に格納するのが最適です。
- 可能な場合、メッセージ・フロー内のノード数は減らします。また、メッセージ・ツリーのコピーや新しいメッセージ・ツリーの作成もできるだけ行わないようにします。メッセージ・ツリーは、特に要素が多数ある場合、かなりのスペースを占めます。メッセージ・ツリーのコピーを避けるために、ツリーを変更する能力を提供する計算ノードなどのノードは、必要なときのみ使用します。こうすることによって、メモリー使用率の効率化が促進できるだけでなく、処理速度を速めることもできます。
- ResetContentDescriptor (RCD) ノードの使用を避けます。RCD ノードは、メッセージ・ツリーを実際に解析するメッセージ・ドメインを変更するためのもので、メモリーと CPU の両方に処理を集中させるアクティビティーであるからです。
- IF 文の論理的な組み合わせ、「PARSE 付き CREATE」文と ESQL ASBITSTREAM を使用すると、RCD ノードや複数の計算/フィルター・ノードを排除できます。
- 実稼働環境ではトレース・ノードの使用を避けます。${Root} 式を使用するとメッセージ・ツリーの全体解析が行われるため、処理コストが増大します。高処理コストは、宛先がアクティブでなくても発生します。
- できる限りユーザー出口を使用し、監査/ログ情報を適切にリダイレクトします。ユーザー出口機能を使用すると、メッセージ処理中に柔軟かつ動的にユーザー出口をアクティブ化/非アクティブ化できます。
- 後続ノードで再計算をしなくてもよいように、中間結果をメッセージ・ツリー内に保存します。MQRFH2 usr フォルダーなどの、ユーザーが保守できるデータ・フォルダーがメッセージ・ヘッダーに含まれている場合は、後続ノードのために中間結果をそこに格納してください。
- メッセージを複数の宛先に書き込む必要がある場合は、複数のノードを使用するよりも、宛先リストを使用する方法をお勧めします。
- XMLT ノードを使用する場合は、まずメッセージ・ツリーがシリアル化され、次に変換エンジンに送られることを覚えておいてください。スタイル・シートを読み込んで変換した後、ノードはその結果を再び解析して、メッセージ・ツリーに戻します。また、Message Broker V6 まででは、XMLT ノードの出力は常に BLOB 形式であるため、メッセージを引き続いてメッセージ・フローで XML メッセージとして処理する必要がある場合、RCD ノードは必須です。そのため、XMLT ノードを複数回使用すると、メッセージ・ツリー全体が解析されることになります。変換されるメッセージ・ツリーが大きい場合、こうすると非常に高コストになります。このような場合、ESQL をより適切なロジックで使用すれば、メッセージ・ツリーの完全な解析が不要になり、処理コストは大幅に改善するはずです。
- XMLT ノードを使用する場合は、できるだけスタイル・シートのキャッシングを活用します。
- メッセージ・フローは、変換、翻訳、プロトコル変換、メッセージ加工、ルーティングなどのメディエーション・アクティビティーを実行する場合にのみ使用します。メディエーション・アクティビティーにおいては、メッセージ・フローはステートレス・エンジンである必要があります。
- メッセージ処理中、トランザクション・モードが入力ノードに対しては「NO」、出力ノードに対しては「Automatic」に設定されていることを確認します。これらは処理をトランザクション・モードで実行する必要がある場合にのみ変更するものとします。
- デフォルトのブローカー例外ハンドラーに頼るのではなく、必ずメッセージ・フローに対する例外処理のメカニズムを用意します。デフォルトの例外ハンドラーでは、有害メッセージの処理で 1 つ障害が発生すると、メッセージのコンシュームがブロックされる恐れがあります。
- 複数のプロトコルを使用する、または使用することを検討している場合は特に、複数のメッセージ・フロー間でコードを再利用するためにサブフローを使用します。
- フィルター・ノードやデータベース・ノードでは、メッセージ・ツリーを修正することはできません。その場合は、ノード内の環境ツリーを使用してメッセージ・ツリーの内容を修正し、それを後続ノードにコピーします。
- データベースを操作するノードがある場合は、開発、テスト、実稼働といった各種の環境間でデータ・ソース名のプロパティーが異なる可能性があるため、プロパティーをプロモートします。プロパティーをプロモートすると、多様な環境にデプロイする際に、それを個別のノード・レベルではなく、フロー・レベルで変更できます。このことは、XMLT ノードのスタイル・シート名など、他のノード・プロパティーにもあてはまります。
- すべての java ノードを再検討し、特にfinally ブロックで clearMessage() が MbMessage オブジェクトごとに呼び出されていることを確認します。MbMessage オブジェクトは出力メッセージ・ツリー、環境ツリー、ローカル環境ツリー、例外リスト・ツリーなどを作成するのに使われます。 そのため、メッセージ・ツリーを作成した場合は常に、それらを try - finally ブロックでクリアしておいてください。
- ノードを多数作成して処理ロジックを分散させるよりも、複雑なノードを少数作ることを強くお勧めします。
- 各メッセージ・フローはスレッドです。処理保全性を効果的に維持するには、メッセージ・フロー・ノード内でスレッドを新たに作成するのはよくありません。ビジネス・ニーズが生じた場合は、すべてのスレッドをそのノード自体で管理し、ノードを削除する際にはスレッドをリリースして、メッセージ処理中にスレッドによるブロッキングが起こらないようにする必要があります。
ESQL
- スクラッチパッドの作業にはローカル環境ツリーを使用するのはできるだけ避け、環境ツリーを使用します。環境ツリーのコピーはメッセージ・フローのインスタンスのすべてのノードに 1 つしか存在しませんが、ローカル環境の場合、プロパゲートされるノードごとにメッセージ・ツリーがコピーされます。
- メッセージ・ツリーのナビゲーションの効率を高めるために、ESQL コーディング中は動的参照を使用します。
- ESQL で PASSTHRU 文を使用する場合は、パラメーター・マーカー「?」を使用します。そうすることにより、Dynamic SQL 文を再利用できます。
- ループ内で、同じ目的で同じ関数呼び出しを行わないでください。例えば、ESQL WHILE ループで CARDINALITY 関数を呼び出すのは高コストです。
- 同じ入力メッセージの出力メッセージを複数送信する必要がある場合は、ESQL の PROPAGATE 関数を使用します。こうすると、実行されるメッセージ・プロパゲーションごとに、出力メッセージ・ツリーのストレージを再請求するのに役立ちます。その結果、メッセージ・フローによるメモリー使用率を減らすことができます。また、ハード・ワイヤーリングを使用したフローのループも避ける必要があります。
- フィールドのリストを作成するには、ROW および LIST コンストラクターを使用します。また、変数を宣言時に初期化することもお勧めします。このようにして ESQL 文の数をできるだけ減らします。これにより、パフォーマンスを向上させ、作成および解析する内部メモリー・オブジェクトの量を減らすことができます。
- ESQL のストリング操作はプロセッサーに操作が集中する作業であるため、できる限り使用しないようにします。
パブリッシュ/サブスクライブ
- パブリッシュ/サブスクライブを使用すると、トピックあたりのサブスクライバーの数によってトピックのパブリケーションごとに書き出される出力メッセージの数が決まるため、これがメッセージのスループットに影響を与えます。メッセージは 1 つの作業単位で書き込まれます。そのためパーシスタント・メッセージを使用する場合は、ブローカーのキュー・マネージャーのログをチューニングする必要があります。
- ブローカーは保存パブリケーションをデータベースに格納するため、Publication ノードを使用すると、特に保存パブリケーションである場合は、ブローカー・データベースの使用量が増えます。そのため、パブリケーションを保存パブリケーションにする必要があるかどうかをよく考えなければなりません。
- 各サブスクリプション登録と登録解除の詳細はブローカー・データベース表に格納されています。
アプリケーションによる動的なサブスクリプションやサブスクリプション解除のレベルが高すぎると、ブローカー・データベース操作のレベルが上がります。
また、すべての入出力およびデータベース操作には高いコストがかかります。そのため、これらの操作を最小限に抑えるようにソリューションを設計するか、データベースをチューニングしてパフォーマンスを上げるかのどちらかにする必要があります。
- パブリッシュ/サブスクライブ・モデルを設計する場合は、トピック・ベースのルーティングよりも、コンテンツ・ベースのルーティングを検討します。コンテンツ・ベースのルーティングを使用することで、SQL 式をメッセージの内容に照らして評価し、サブスクライバーが本当にそのメッセージを受信する必要があるかどうかを判断しやすくなります。これによって、ブローカーからサブスクライバーに送信するメッセージの数を減らすことができます。トピック・ベースのルーティングでは、サブスクライバーは登録したトピックに関するすべてのメッセージを受け取ります。サブスクライバーはメッセージを全部必要とはせず、その内容に基づいて破棄する可能性があります。そのため、コンテンツ・ベースのルーティングによって、サブスクライバーは本当に必要なメッセージを入手できます。
Message Broker から見た WebSphere MQ のベスト・プラクティス
- Message Broker の処理パフォーマンスは、CPU が不足していない限り、フローが CPU バウンドに設計されている方が高くなります。WebSphere MQ 上のパーシスタント・メッセージに関して言えば、WebSphere MQ がフローをログに記録するため、フローは入出力バウンドになります。そのため、ビジネス・ニーズがなければ、メッセージは永続化しません。また、非パーシスタント・メッセージごとに有効期限を設定します。バッファーがいっぱいになると、WebSphere MQ は非パーシスタント・メッセージについても入出力操作を行います。そのため、メッセージの有効期限を設定して、ブローカーまたはアプリケーションが処理やメッセージ消費を停止しても、キューにメッセージが蓄積しないようにするのです。
- WebSphere MQ でパーシスタント・メッセージを使用する場合は、バッファー・サイズとキュー管理ログのログ拡張サイズを大きく設定します。また、ログを置くディスクとしては、不揮発性の書き込みキャッシュを持つディスクなど、待ち時間の短いものを使用します。これによってパーシスタント・メッセージの処理レートを大幅に向上させることができます。
- WebSphere MQ の入出力が避けられない場合は、可能な限り減らす努力をします。例えば、次を行います。
- メッセージ処理のレートを大容量に保って、メッセージのタイプに関係なく、キュー上のメッセージ数を最小限にします。これは実行グループとメッセージ・フローのインスタンスを複数にすることによって実現できます。
- メッセージの着信速度と処理速度に大きな差が生じないようにします。上記に従ってメッセージ・フローと構成をチューニングしてください。
- キュー・マネージャーのログ作成には、大容量バッファーと高速ディスクを使用します。
- サポートされるすべてのプラットフォーム上で、Message Broker を信頼できるアプリケーションとして実行します。これによって、キュー・マネージャーとアプリケーション (ブローカー) の通信コストを削減できます。
Message Broker から見たデータベースのベスト・プラクティス
- 入出力操作およびデータベース操作は高コストです。そのため、ソリューション内ではそのような操作の数はできる限り最小限に抑えます。可能な場合は常にキャッシュを増やします。キャッシュを増やすかどうかは、ビジネス・ニーズによって判断します。ただし、過剰なキャッシュの増量はお勧めできません。
- ソリューションに実行すべきデータベース操作がある場合は、データベース・アプリケーションに関連したベスト・プラクティスに従います。以下は Message Broker のアプリケーションの観点から見た DB2 に関する推奨事項です。しかし、これらは他のほとんどのデータベースにもあてはまります。
- アプリケーション・ヒープ・サイズ (APPLHEAPSZ) とアプリケーション・コントロール・ヒープ・サイズ (APP_CTL_HEAP_SZ) をチューニングします。実際の値はビジネスの状況やソリューションの実装によって異なるため、具体的な値を推奨することはできません。値を決定するには、データベースにビジネス要件に即した最大のメッセージ・トランザクションを発行し、ヒープ・サイズを監視してください。
- BLOB、CLOB、VarChar などのラージ・オブジェクトにはデータベースのメモリー領域を使用してアクセスするため、アプリケーションにこれらの操作を行う機能がある場合は、バッファー・プールのサイズをチューニングします。
- locklist と maxlocks を十分大きくするか、commit 文をこまめに発行して作業単位を小さくします。
- メッセージ・フローのインスタンスとアプリケーション間の競合を減らすために、できるだけインデックスを使用します。
- メッセージ・フローが表からのデータ読み取りしか行わない場合は、その表の読み取り専用のビューを使用します。これによってデータベース・マネージャー内のロックの量と、読み取りの処理コストを削減できます。
- データベース操作が避けられない場合は、以下を行って操作量を最小限に抑えます。
- データベースを Message Broker が置かれているシステムのローカルに置く
- バッファー・サイズを大きくする
- データとログに高速ディスクを使用する
- SELECT 文を使用する場合は、WHERE 節を効率化して、データベースから取得するデータの量を最小限に抑えます。
- 可能な場合は、既にコンパイルされ、データベースに格納されているストアード・プロシージャーを使用します。これによってデータ取得速度が上がります。
- 結合には処理時間がかかり、高コストであるため、複雑な結合はできるだけ避けます。
構成
- Message Broker のコンポーネントが (他マシン上に) 複数ある場合、規模の大きいデプロイメントではコンポーネントごとに個別のユーザー ID を使用します。これはセキュリティーと保守を容易にするためです。
- コンポーネントのサービス ID への直接ログイン・アクセスを行わせないようにします。サービス ID への sudo を実行して操作を実行できるようにユーザー ID に特権を提供してください。これはコンポーネントの保護に役立ちます。
- コンポーネントのサービス ID はユーザーに開示しません。サービス ID には ACL にあるすべてのトポロジー・レベルの特権がデフォルトで許可されるため、ユーザーは、「runas」コマンドを使ってサービス ID でツールキットを起動して、コンポーネントに対する完全な特権を持ってしまうからです。
- コンポーネント・レベルの操作特権を定義するには、アクセス制御リストを使用します
- セットアップを完全に行った後は、管理作業にツールキットを使用する依存度を減らします。構成マネージャーのプロキシー API エクササイザーなどの代替手段を利用するか、ローカル・マシンでコマンドを使用してください。セキュリティー上の理由から、リモート・マシンから管理アクティビティーを実行できないようにします。そのためには、構成マネージャーのキュー・マネージャー値である、 SYSTEM.BKR.CONFIG チャネルの MCA チャネル・ユーザー ID を無効なユーザー ID 値に設定します。こうすることによって、ツールキットからはそれ以上の管理操作は実行できなくなります。
- 環境構成に関連する情報は「mqsiprofile」ではなく、ユーザー・プロファイルに設定します。フィックスパックの更新などの保守アクティビティー中にこれらのファイルは上書きされるため、以前の設定は失われてしまいます。
- 見込まれる負荷と利用可能なシステム・リソースに基づき、企業ポリシーに従って、 ulimit を適切な値に設定します。これは Windows 以外のマシンに適用すべきベスト・プラクティスです。
- パフォーマンス・テストに基づいてプロセス・サイズを決定します。必要に応じて実行グループ (DataFlowEngine) のデータ・セグメント・サイズ (AIX のみ) を増やします。環境内で複雑な多数のメッセージ・フローに対して 32 ビットの実行グループを使用しているときには、デフォルト値の 1 GB では十分でない場合があります。
- メモリーの観点から言えば、32 ビット・プロセスよりも、64 ビット・プロセス (実行グループ) を使用することをお勧めします。
- Message Broker ソリューション内で Java をかなり使用する場合は、パフォーマンス・テストを何度か行って JVM の最大ヒープ・サイズを決定します。なお、JVM ヒープ・サイズは DataFlowEngine (実行グループ) プロセスから割り振られます。そのため、プロセス・ヒープ・サイズと JVM 最大ヒープ・サイズの値を同じに設定してはいけません。
- スクリプトまたは適切な Message Brokerのコマンドを使用して、すべてのデプロイメント・アクティビティーを実行します。環境変数 MQSI_SHOW_DEPLOY を 1 に設定すると、オペレーティング・システムのユーザー・ログでデプロイメント処理の詳しい進捗を確認できます。mqsilist <brokername> などのクエリー操作もデプロイ・メッセージであるため、userlog にはデプロイメント情報が記録されます。
- 環境は常に実稼働環境に合わせるようにし、構成レベルを同じにします。保守作業が必要な場合は、まずクローン上で実行して、ソリューションに影響がないことを確認します。その後、実稼働環境で実行します。
- 命名規則とコーディング標準を厳格に定めます。開発者と管理者が全員必ずそれに従うようにします。
- Message Broker の全成果物についてソース管理のしくみを定めるとともに、保守の簡素化のためデプロイメント用のスクリプト (またはシェル・スクリプト) を使用します。
- 実稼働環境では特に、1 つのキュー・マネージャーをコンポーネント間 (ブローカー、ユーザー・ネーム・サーバー、構成マネージャー) で共有しないようにします。
- 実行グループごとにメッセージ・フローのコピーを 1 つずつ割り振るのではなく、1 つの実行グループ内で稼働しているメッセージ・フローのコピー数を増やすインスタンス追加法を使用します。
- ドキュメントは必ず保管し、実稼働環境に加えた変更をすべて追跡できるようにします。時々加えられる小さな変更が壊滅的な結果を招くこともあります。アクティビティーを記録しておくと、デバッグして環境を迅速に復元するのに役立ちます。
- 常にドメイン・レベルのバックアップと復元を実行します。ドメイン・レベルのバックアップの際は不完全なデプロイを行わないようにします。また、バックアップが完了するまでデプロイはいっさい実行しないようにします。
- ドメインまたはシステム環境に変更 (フィックスパック更新などの定期保守) を加える前に、必ずバックアップを取ります。これによってアップグレード後に障害が発生した場合に、復元しやすくなります。
- 特に災害時回復シナリオを念頭に置いて、バックアップ/リカバリー戦略をテストおよび管理するためのポリシーを適用します。
結論
この記事では WebSphere Message Broker のベスト・プラクティスをいくつか説明しました。これらのベスト・プラクティスを使うと、メッセージ処理のパフォーマンスを向上させることができます。ただし、パフォーマンスは依存関係のある WebSphere MQ やデータベース・インスタンスの効果的なチューニング、適切なソリューション設計、高性能 CPU と十分なメモリーを搭載したマシンといった、その他の因子にも左右されます。
謝辞
Amar A Shah 氏 (WebSphere Message Broker レベル 3 テクニカル・リード)、Raja Sreenivasan 氏 (Bharti の WebSphere Message Broker 管理者)、および Raghavendran Sreenivasan 氏 (WebSphere Message Broker レベル 3 チーム・リード) にはこの本稿をレビューをお願いし、貴重なフィードバックをいただきました。ここに厚く謝意を表します。
参考文献
著者について  | |  | Shravan K Kudikala はインドのハイデラバードにある IBM India Software Lab で シニア・スタッフ・ソフトウェア・エンジニアとして勤務しています。WebSphere Message Broker レベル 3 サポート・チームのメンバーでもあります。本記事のほかに IA97、IA0X、および IA9W のサポートパックに関する記事も執筆しています。 |
記事の評価
|