次の方法で共有


MSMQ (Microsoft Message Queuing Services) を使ったプログラミング原則

Charles Sterling
Microsoft Corporation

June 1999

概要:

MSMQ (Microsoft® Message Queuing Services) を使って、分散アプリケーションを構築、トラブルシューティング、テストする原則を説明します。

目次

  • はじめに
  • 良質な MSMQ アプリケーションを作成するための 11 個のガイドライン
  • MSMQ でよく起きる問題のトラブルシューティング

はじめに

MSMQ (Microsoft Message Queuing Services) を利用することで、異質なネットワークや一時的にオフラインになっているシステムを超えて、同時に動作していないアプリケーションがお互いに通信できます。これを実現するために、何種類ものメッセージの送受信方法があります。ただし、このような柔軟性は非効率さを招きかねません。この文書では、MSMQ アプリケーションの効率的なコーディング方法、MSMQ 利用のテスト方法、およびアプリケーションのコーディング プロセスで遭遇する問題を解決するトラブルシューティングについて概説します。 この文書は、読者が MSMQ の知識を持っていることと、MSMQ でプログラミングを行った経験があることを仮定しています。すべてのサンプル コードは Microsoft Visual BasicR で書いていますが、原理的には他のプログラミング言語にもあてはまります。

良質な MSMQ アプリケーションを作成するための 11 個のガイドライン

以下にプログラミング ガイドラインの簡単な要約を示します。MSMQ アプリケーションを作成する際には、このガイドラインに従うことをお勧めします。

  • ローカルでのみ受信します。
  • MQIS (Message Queue Information Store) にクエリを発行する関数を避けます。
  • タイムアウトを実装します。
  • 非同期通知の制約を理解します。
  • トランザクションを使うべき時間と場所を知っておきます。
  • 継続可能な COM オブジェクトを使うべきタイミングを知っておきます。
  • どのようなセキュリティ コンテキストを使うべきかを理解します。
  • スマート キューの利用を実装します。
  • 肯定応答または否定応答を要求します。
  • 大文字と小文字が区別されることを覚えておきます。
  • オフライン中にコンピュータを再起動してからアプリケーションをテストします。

ローカルでのみ受信します

MSMQ を使うと、プログラマは場所を全く意識しないでコードを書けます。この機能は強力で役立ちますが、キューを搭載しているコンピュータから受信側のコンピュータが切り離されると、この機能は動作しなくなります。これは、ホスト コンピュータまたはサイト コントローラから切り離されている間は、MSMQ がメッセージを受信できないことに起因します。

次の 2 つの要因から、性能の矛盾が生じます。

  • MSMQ はメッセージを送信しますが、キューイングする以外は何もしません。このキューイングしたメッセージは、効率的にネットワークまたはハードディスクにまとめて送り出せます。
  • MSMQ は TCP/IP に基づいてメッセージを送信しますが、MSMQ は RPC に基づいてメッセージを受信します (RPC は TCP/IP にバインドする傾向にあり、アブストラクション層が更に 1 つ増えます)。

MSMQ の性能に関する詳細情報については、https://msdn.microsoft.com/isapi/gomscom.asp?Target=/ntserver/appservice/deployment/planguide/msmqperformance.asp (英語情報) にある「Microsoft MSMQ 環境の性能最適化」を見てください。

ローカルでのみ受信する場合に頭に入れておく必要がある事項 : MSMQ 1.0 では、トランザクション中はリモート キューから受信できません。詳細は、https://msdn.microsoft.com/library/backgrnd/html/msmqtips.htm (英語情報)にある、「MSMQ (Microsoft Message Queuing Services) ヒント集」の中の「MSMQ 1.0 におけるトランザクション型リモート読み出しのセマンティクス」の章を参照してください。

MQIS にクエリを発行する関数を避けます。

公開キューに関する全情報は MQIS という名前のデータ リポジトリに格納されています (MSMQ バージョン 1.0 では、このリポジトリは SQL ServerTM データベースに含まれています)。

キューのオープンに使える関数のほとんどは、キューの存在を確認するため、または要求しているアクセス タイプの権限を検証するためにデータ リポジトリにクエリを発行します。たとえば、既定でキューは全員に「送信」アクセス権を設定していますが、所有者だけに「受信」アクセス権を設定しています。

データ リポジトリへのアクセスが必要な関数は多数ありますが、不要な関数もあります。必要な機能へのトラフィックを最小限にすることが重要です。キューをオープンする戦略の一覧に、コストおよび各戦略の利点と欠点を述べています。

  • キューを参照するのに、キューの GUID を使用します。

  • (syntax queuinfo.FormatName = "public =228B7F89-EB76-11D2-8A55-0080C7E276C0" )

    コスト

    • 存在と権限の確認のためのサイト コントローラへの 1 往復コスト

    利点

    • オフラインで動作。
      注: この戦略が動作しない場合、Windows NT 4.0 SP4 (Service Pack 4) にアップグレードしてください。
    • コンピュータがオンラインなら、MSMQ は、GUID が存在しないかどうかを確認する必要があります。

    欠点

    • GUID がハードコードの場合、エンタープライズまたはキューを再構築できません。
    • アプリケーションを初めて実行したときのパスから取り出して、キャッシュしてあった GUID を使う場合、接続を再度する必要があります。
  • キューを参照するのに、PathName を使います。

  • (syntax queuinfo.PathName = "Machine_Name\Queue_name" )

    コスト

    • サイト コントローラに 2 往復します。1 回目は GUID の決定で、2 回目は存在と権限の確認です。

    利点

    • 動的にキューを再発見できます。

    欠点

    • オフラインでは動作しません。
    • コードを簡単にすることがネットワークの往復を増やすことになります。
  • キューへの送信に直接的なフォーマット名を使います。

  • (Syntax queuinfo.FormatName = "Direct=OS:Machine_Name\Queue_name" )
    コスト

    • サイト コントローラとの往復はなくなります。

    利点

    • 動的にキューを再発見できます。
    • 別の企業にも有効です。

    欠点

    • コスト ベースのルーティング処理がありません。
    • 送信元と送信先のコンピュータが、いずれは同時にオンラインになる必要があります。
    • MSMQ が送信先マシンの存在を確認することはありません。
    • 受信処理ができません。
    • 中間の格納と転送処理がありません。

タイムアウトを実装します。

MSMQ の既定のタイムアウトは無制限に設定されています。この設定は壊滅的な結果につながることがあります。一見すると、特定するのがとても簡単な問題に思えますが、無限時間のタイムアウトは深く潜行して発生し、問題になります。このようなタイムアウトには次のものを含みます。

  • receive 関数への ReceiveTimeout パラメータ
    既定では無制限 です。この関数では、キューから受信するメッセージを待つアプリケーションの待ち時間を指定します。このアプリケーションは受信するメッセージを待っている間は応答を停止します (Visual Basic のメイン スレッドはメッセージ待ちになっているので、Visual Basic で Ctrl + Break を押しても、コントロールを解放しません)。コードを失わずにこの状況を抜け出す最適な方法は、MSMQ サービスを停止することです。これにより、ランタイム エラー状態となり、プロセスから抜け出す機会が得られ、タイムアウト状態を作り出せます。
  • キューに到達するまでの時間
    既定では無制限 (90 日と定義) です。既定ではないタイムアウト値を指定し、しかもできるだけ小さな値とすることを、強くお勧めします。もし、アプリケーションがタイムアウトを指定せず、送信先に到達できない (たとえば、送信先コンピュータがすでに存在しない) 場合、メッセージは生き続け、3 か月もの間、リソースを保持し続けます。
  • 受信されるまでの時間
    既定では無制限です。メッセージは、キューから取り出されるまで、キューの中にとどまり、このタイムアウトは問題になリ易いです。--特に、明白に送信しなかったメッセージの場合 (たとえば、肯定メッセージ、またはジャーナル メッセージ)。

マルチスレッドの VisualBasic アプリケーションで、さらに問題が起きるようなら、これに関する機能強化を含んだ Windows NT 4.0 Service Pack 4 にアップグレードされることをお勧めします。

トランザクションを使うべき時間と場所を知っておきます。

MSMQ には 以下の 2 種類のトランザクションがあります。

  • DTC が提供するもので、他のリソース分配者とのトランザクションに参加する場合に必要です。
  • MSMQ が内部的に提供するもので、性能的に有効ですが、外部トランザクションとして登録できません。

MSMQ のトランザクションはとても役に立ち、メッセージのインスタンスが 1 つだけ送信されることを保証します。。単独のトランザクション内で複数のメッセージを送信しても、メッセージは順序付けて処理され、送信失敗が起きると、必ず XactDeadletter キューにログ出力されます。

MSMQ のトランザクションで不利な点は性能、およびトランザクション内部からリモート受信できないことです。

詳細情報は、「 MSMQ (Microsoft Message Queuing Service) ヒント集」 (https://msdn2.microsoft.com/en-us/library/ms811055.aspx) (英語情報) 文書の「 MSMQ 1.0 におけるトランザクション型リモート読み出しのセマンティクス 」の章と、https://msdn.microsoft.com/isapi/gomscom.asp?Target=/ntserver/appservice/deployment/planguide/msmqperformance.asp (英語情報) にある「MSMQ 環境における性能の最適化」を参照してください。

継続可能な COM オブジェクトを使うべきタイミングを知っておきます。

COM オブジェクトの送信プロセスは便利に使えますが、(ADO または Microsoft Word ) 汎用的な COM オブジェクトの配信オーバヘッドが見えないので、利便性には費用もかかります。したがって、開発者はあらゆる状況に対処する不測事態用コードを書く必要があります。次の例では、1 行 1 列だけの ADO レコードセットの送信を示しています。送信されるメッセージは 394 バイトです。同じ情報をテキストで送信すると、22 バイトしかかかりません。

  
Private Sub Form_Load()
Dim con As Connection
Dim strQuery As String
Dim rs As Recordset
Dim msg As New MSMQMessage
Dim q As MSMQQueue
Dim qi As New MSMQQueueInfo
'***********ADO Code****************
Set con = New ADODB.Connection
con.CursorLocation = adUseClient ' Required to implement IPersist
con.Open ("Driver={SQL Server};Server=eastway;Database=pubs;Uid=sa;Pwd=")
strQuery = "select max(au_id) from authors"
Set rs = con.Execute(strQuery)
qi.FormatName = "direct=os:eastway\test"
Set q = qi.Open(MQ_SEND_ACCESS, 0)
'msg.Body = rs
msg.Body = "" & rs.Fields(0)
msg.Send q
End Sub

どのようなセキュリティ コンテキストを使うべきかを理解します。

MSMQ は作業が行われているセキュリティ コンテキストに基づいて、権限を検証します。これは次の事柄に影響を与えます。 サービス、MTS (Microsoft Transaction Server) オブジェクト、ASP スクリプト、および認証済みのユーザー アカウントではなく、不注意にローカル ユーザーでコンピュータにログオンしたユーザー。

既定で、全サービスはローカル システムのコンテキストで動作します。ローカル システムはサービスをホスティングしているコンピュータ上でのみ有効なアカウントです。既定では、MSMQ 権限では、リモート コンピュータへのすべての受信操作は失敗します。しかし、送信アクセスの既定は「Everyone」であるため、送信はうまくいきます。ドメイン上で不正なユーザーを確認する試みで必要なオーバヘッドは、送信先のキューに到達する送信に多大の遅延を招きます。この問題が発生している場合には、送信がうまくいってから、送信元コンピュータを出ていくまでに 30 秒の間隔があく兆候がみられます (パフォーマンス モニタで見ることができます)。

既定で、ASP (Active Server Pages) は、ローカル システムに基づいている IIS (Internet Information Server) のコンテキストで動作します (この設定は IIS 4.0 では構成できず、IIS 3.0 では無視されます)。ASP はローカル システムで動作するため、上記と同じ問題を抱えています。この問題にはいくつかのソリューションがあります。

MTS オブジェクト パッケージの既定のセキュリティは 「対話ユーザー」 です。この既定はMTS パッケージが、MTS コンポーネントを呼び出すクライアント アプリケーションと同じコンピュータにある場合はうまくいきます。ただし、従来の Windows DNA アーキテクチャでは、ビジネス オブジェクトは専用コンピュータに置かれます。これは次のような設計になっています。つまり、クライアント コンピュータがビジネス オブジェクト コンピュータを呼び出し、ビジネス オブジェクト コンピュータがサーバー コンピュータを呼び出し、サーバー コンピュータがキューをホストします。

Windows NT 4.0 では委任をサポートしていないので、このモデルはローカル システムのコンテキストで動作している場合と同じ問題を抱えています。受け渡されるセキュリティ識別子 (SID) はローカル システム アカウントのものと同じです。

ワークステーションにローカル管理者としてログオンするのは、「標準セキュリティ」 の考え方でサービスを利用している開発者にとって、頻繁に問題となります。ドメインにインストールした MSMQ には、この概念はありません。サイト コントローラにアクセスを試みると、「このサイト コントローラに接続していません。 C00E0013L」というエラーになります。ミラー アカウント (同じ名前とパスワードを持つローカル マシン アカウント) を使えば、この問題をある程度回避できますが、次の理由から勧められません。

  • パスワードを静的に保持していることで、セキュリティ リスクを引き起すことがあります。
  • 同期して変更の保守を行うのはスケーラブルではなく、障害を起こしやすくなります。
  • MSMQ では、ユーザー ドメインの SID (Security IDentifier) をユーザーが作成するすべてのオブジェクトと関連付けます。ミラー アカウントからの SID は MSMQ エンタープライズには分からないので、オブジェクトの所有者は「Unknown」とみなされるので、MSMQ の既定の権限では問題を引き起します。

スマート キューの利用

キューの作成には他の MQIS 呼び出しのオーバヘッド ( MQIS にクエリを発行する関数を避けます を参照) がすべてかかるだけでなく、場合によっては、InterSite レプリケーションの時間 (既定では 10 秒) も加わります。

MSMQ は再起動後に、最も近くにあるサイト コントローラを調べます。このサイト コントローラはキューの存在およびキューへのアクセス情報を求めるクライアントに対するサーバーとなります。ただし、オリジナルのサイト コントローラが、オブジェクト作成をサービスする唯一のサイト コントローラです。

ロジック フローの例 :

  1. キューを作成してアプリケーションを開始
  2. キューを 「 送信 」 または 「 受信 」 のどちらかを行うものとしてオープン

情報検索に使用したサイト コントローラがオリジナルの親サイト コントローラの場合、このプロセスは常に成功します。クライアントが移動して、現在は別のサイト コントローラを使っている場合は、キューの作成情報が、インストールを行ったオリジナルのサイト コントローラから、このサイト コントローラに情報をレプリケーションしてきていたとしても、このコードはうまく動作しません。したがって、すべてのオープン処理に「リトライ ロジック」を組み込むことをお勧めします。

肯定応答または否定応答を要求します

MSMQ の既定動作では、メッセージが配信されたときに、成功か失敗かを通知しません。使い捨て程度のメッセージにはこれで問題ありませんが、確認が必要なメッセージの場合には、通知を要求する必要があります。

トランザクション型メッセージでは、失敗するメッセージに、この通知プロパティを設定します。したがって、トランザクション型メッセージで失敗したものはすべて XactDeadletter キューに報告があります (成功した場合は報告しません)。プログラマにはあまり知られていませんが、XactDeadletter キューは多数のメッセージを蓄積できます。

大文字と小文字が区別されることを覚えておきます

これはプログラミング ガイドラインというよりは、注意を喚起する警告の意味合いがあります。MSMQ のキュー名は大文字と小文字を区別します。MSMQ のエクスプローラはすべてのキューを小文字で示しますので、大文字と小文字の区別を間違えたために起きたエラーは、二重に発見しにくくなります。

オフライン中にコンピュータを再起動してからアプリケーションをテストします

これもまた、プログラミング ガイドラインというよりは、注意を喚起する警告になります。MSMQ と Microsoft Windows NT 4.0 には、キャッシュ機能がありますので、製品にするプログラムが期待通りの動作をするかどうかを確認するには、ネットワークから切り離して、完全に再起動してからアプリケーションをテストするのが最適です。ネットワークから切り離した状態では、MSMQ サービスがオンラインになるまでの時間は、通常よりも長くなるのが普通であることにも注意してください。 (ある種の送信構文とすべてのリモート受信ではオフライン状態は利用できません)。

MSMQ でよく起きる問題のトラブルシューティング。

MSMQ 問題は簡単なテストをして、切り分けて解決できるものが多数を占めます。以下に Microsoft のサポートで作成した、発生頻度順の問題一覧を示します。接続性の問題が最大の割合を示しています。

  • 接続性
  • セキュリティ
  • MQIS の接続性
  • 遅さ / リソースの消耗
  • その他の問題

接続性

接続性の兆候や問題がどの程度であるに関わらず、まず、ping ユーティリティを使って、問題のあるコンピュータをテストすることをお勧めします。ping テストで応答が返ってくるのに時間がかかると、このようなテストがうまく行ったり、行かなかったりするのと同じで、問題があることを示しています (後者のケースでは、名前解決が失敗しているか、または名前解決やネットワークの飽和を知らせるブロードキャストを行うためにコンピュータがフォールバック運転をしていることを示しています)。

MSMQ のテストでコンピュータをテストするために、ping ユーティリティを動作させるときに、使う名前は NetBIOS (Network Basic Input/Output System) のマシン名で、完全修飾の DNS 名でも、IP アドレスでもありません。これは、MSMQ 1.0 が NetBIOS 名しか使用しないためです。

ping ユーティリティは TCP/IP の ICMP プロトコルに基づいています。ICMP は、ファイアウォール問題の検証には、以下の 2 つの理由から、不適切な選択です。

  • これはセッション ベースではなく、TCP セッションの確立能力を確認できません。
  • ICMP はネットワーク装置を制御するのが主な利用方法なので、ICMP がファイアウォールを超えることはめったに許されません。

ファイアウォールとポート問題には、Telnet がツールとして適しています。Telnet を使うと、135、1801、2101、3527 のポートでホスト コンピュータとセッションを確立できます。ファイアウォールに必要なポートに関する情報については、「 How To Configure a Firewall for MSMQ Access」 ( https://msdn.microsoft.com/isapi/gosupport.asp?Target=/support/default.asp (英語情報)にある文書: Q183293 を参照 ) と、https://msdn.microsoft.com/isapi/gomscom.asp?Target=/com/wpaper/dcomfw.asp (英語情報)にある「 Using Distributed COM with Firewalls 」を参照。

さらに接続性に問題があれば、NetMonitor のトレースを使って切り分けられます。NetMon トレースは、セッションの確立を試みている MSMQ のオブジェクトを見つけだし、接続性プロセスのどの部分に障害があるのかを確かめるのに有効です。NetMon は、2 台のコンピュータ間の接続が成功している場合、ドメイン コントローラからの認証に失敗している状況を見つけだすのにも有効です。

セキュリティ

ユーザーがローカルにログオンし、信頼関係のないドメインを超えて、MSMQ を使おうとすると、セキュリティ問題が多数発生します (詳細情報は、どのセキュリティ コンテキストを使うべきかを理解します を参照)。

適切なセキュリティを確認する最も簡単なテストは、他のコンピュータ上の、次の既定の管理者共有フォルダに接続することです。

   
\\Machine_Name\C$

この接続に認証が要求される場合は、MSMQ は接続しません。SQL Server とは違って、MSMQ は接続確立のために既存の資格情報を使用しません。ファイル共有は TCP/IP 以外のプロトコルでアクセスされるため、この接続を達成すること自体は、正しい接続性テストではありません。

MQIS の接続性

MQIS へのデータ格納機能があるのは、MSMQ サーバーだけなので、MQIS の接続性問題は、MSMQ サーバーだけに影響があります。MQIS の接続性問題のトラブルシューティングのキー ポイントを以下に示します。

  • MSMQ は、ODBC と DB-Library の両方を使用しているので、MQIS のセットアップ時には、ODBC トレースと SQL トレース (SQL Server 7.0 では SQL Server Profiler として知られています) の両方を使います。
  • セットアップ後は、ODBC トレースは SQL トレースよりも適したツールです。
  • SQL Server 7.0 と MSMQ は完全に互換がありますが、次の 2 つの条件があります。
  • SQL Server 6.5 と 7.0 の両方をインストールしている場合、6.5 を動作させて、セットアップを実行し、MQIS を 7.0 にアップグレードします (この順序でセットアップを行えば、MSMQ は両方で動作します)。
  • SQL Server 7.0 と MSMQ サーバーをクラスタにすることはできません。

遅さとリソースの消耗

遅さとリソースの消耗問題については、次の問題を明確にできるので、PerfMon パフォーマンス モニタ ユーティリティの MSMQ 用カウンタは有効です。

  • 送信がペンディングになっているメッセージ。特にペンディングになっているメッセージは他の手段では検出できません。
  • ジャーナル キューまたは確認キューに蓄積されているメッセージ。多くの場合、ジャーナリング機能をオンにしたままであることを知りません。
  • メモリ利用または消耗。これは COM オブジェクトを送信する際に共通の問題です。

その他の問題

その他の問題や未知の問題に対しては、MSMQ のデバッグ バージョンが貴重なトラブルシューティング ツールです。MSMQ のエラー状態はすべて、MQ.h に定義されているエラーの中の 1 つですが、エラー情報が汎用的すぎて、役立たない状況に陥ることがあります (たとえば、「GenericError」というメッセージ文を持つエラーが実際にあります)。ただし、MSMQ のデバッグ バージョンを使うと、MSMQ の実際の開発者からのコメントも含めて、MQ.h の定義済みエラー分類ではなく、実際のエラー原因を知ることができます。