BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル 信頼できるメッセージングは、不要。

信頼できるメッセージングは、不要。

原文(投稿日:2010/06/18)へのリンク

SOA やWeb サービスで一般的に容認された考え方は、信頼できるメッセージングの必要性である。信頼性のあるメッセージングとは、送信アプリケーションによって送られたメッセージは、もう一方で確かに、受信されそして1回のみ受信される、ことを保証する。RESTに対する最も共通の拒絶理由の1つは、RESTが信頼できるメッセージングを提供していないことである。Stefan Tilkov 氏が次のように書いている:「RESTful HTTPは、WS-ReliableMessaging と同等ではない、としばしば指摘され、このために、信頼性が争点(これは、相当変わってしまう。あらゆるシステムがビジネス シナリオによって、どのような関連性でも持つので)となる分野では、使えない、と多くの人々が結論している」[1]。もちろん、Tilkov氏は、これに賛成しないで、アプリケーション レベルでのソリューションを主張する。 Joe Gregorio氏は、 RESTify DayTrader [2]で同じような指摘をした。本当にそうなら、仮説:ビジネス目的なら、信頼できるメッセージングが必要である,というのは,単に間違っている。逆は,真である:ビジネスの観点から、信頼できるメッセージングは、絶対に不要である。もし、明確なビジネス セマンティクスとビジネス論理があれば、個別の信頼できるメッセージングは、冗長である。

Webサービスと信頼性

Webサービスは、ビジネス論理からメッセージ交換の詳細を分離する方法を提供する。基本的に、その考えは、ビジネスをサービスの言葉で記述する(すなわち、「カタログをブラウズする」「発注する」「発注状況をチェックする」など)。サービスは、ビジネス セマンティクスを具体化するビジネス文書を交換することによって、実装されている。SOAP Envelopeは、またSOAP Headerを運ぶことができ、これは、メッセージングのいくつかの機能を実装している:メッセージ セキュリティ、整合性、アドレス指定、信頼性などの機能である。各メッセージング機能は、他の機能から独立している:すなわち、メッセージの整合性は、信頼性無しで実現される。その逆も同じで、両方共無くても、あってもよい。


上の画は、Webサービスを使って実装されたSOAのいくつかの重要なフィーチャを際出させている:

  • ビジネス層は、メッセージング層から独立している;
  • Webサービスは、メッセージ機能の独立した「プラグ&プレイ」モジュールを追加している;
  • メッセージ・ヘッダは、必要なメッセージング機能についての情報を運ぶ。

Webサービスは、それ自身、いつも信頼できるものではない。基本的な問題:もし私が、メッセージを送る、例えば、本を注文する、そしてネットワークの故障で、メッセージが届かず,本が手に入らなかった。シナリオ1が示すように、単に、メッセージを再送すれば、この問題は解決する。

しかし、もしメッセージが到着しても、レスポンスが失われたら、再送は役に立たない:シナリオ2のように、もし本を注文したら、2冊受け取ることになる。

信頼できるメッセージング ソリューションが通常この問題を解決する。シナリオ3に示すように、 アック(acknowledgement、確認), 重複検知、そして 重複排除によってである。

webサービスは、 信頼できるメッセージングの標準として、 WS-ReliableMessaging[3]を提供している。 WS-ReliableMessagingは、いくつかのことを保証している:送られたメッセージは、少なくとも1回、多くても1回、正確に1回,そして/あるいは正しい順番に到着する。通常望むのは、メッセージは,1回、たった1回届くことなので、私は、「正確に1度」と「順番に」ということについてのみ議論する。では、メッセージが順番に届くことから始める。

正しい順番

WS-Reliable Messagingとビジネス見地からのメッセージの通常処理との間には、馴染まないところがある。順番(通りの)処理が重要になる、よくある場面は、オンライン銀行処理である。もし私が、普通預金口座 から残高がほとんど0の当座預金口座 に振替て、続いて、当座預金口座から第三者 に振り返る場合、私は、振替が順番に処理されて欲しい:さもないと、残高不足で、2つ目の振替は、不渡りになってしまう。これが重要なことは、わかっている:私の銀行が順番処理を提供していないで、私が2つの別々セッションで振替をやっていることを忘れたら、私の振替処理は、いつも不渡りになってしまう...

WS-Reliable Messagingがこのような状況を救う理想的なものだと思える。しかし更に分析を進めると、これは、そんなに明白なことではない。 WS-Reliable Messagingが順番処理を実現するのにやっていることは,何なのか? 驚くことはなく、各メッセージに増加するシーケンス番号を付加しているのである。もしメッセージが順番通りに届かなかった(すなわち 2-1-4)なら、受信側のWS-Reliable Messagingソフトウェアは、足りないメッセージが届くまで待ち、それからビジネス論理を含んだ、次の層に順番に配送する(すなわち1と2を配送し、3を待ち、それから3と4を配送する)。まず、不思議なことは、明らかに、順番は、ビジネス層にとって重要なメッセージの特性である。もしそれが、ビジネス層に重要なら、なぜビジネス メッセージ自身にシーケンス番号がないのか?我々は、ビジネスーレベルのセマンティクスで、メッセージを扱う。そしてその順番が重要になる:では、なぜ、ビジネス レベルでメッセージ中に、順番を示す要素あるいは、特性がないのか?

可能性のある答えが2つある。1つ目:ペイロードにもシーケンス番号があり、ビジネス セマンティクスに付加された順番である。もしシーケンス番号があるなら、なぜ WS-Reliable Messagingが必要なのか?2度やっているのである。たぶん、まれな場合に、2度やることは、そうやるべき事なのかも知れない(ところで、私の非常に早くて,効率的なWS-Reliable Messaging ソフトは、これを本当に,本当に早くやることができ,それからビジネス層が1度だけ順番通りのメッセージを受け取り、そして確認のためにチェックする)、しかし一般的に、私は、2度やることには警戒する。冗長だからである。WS-Reliable Messaging のヘッダーにあるシーケンス番号とペイロードのシーケンス番号が違っていたら、どうすべきなのか?2つのレベルの順番処理で発生したエラーに対して、どうやって同じルールが適用できるかを確認すればいいのか(さて、無くなったメッセージは,決して届かない:残りのメッセージは、全く送らない、あるいは、エラー状況といっしょに全て送る、あるいは、エラー原因を解決するように人間に警告する)?両方のレベル、すなわち WS-Reliable Messaging とビジネス、が同じ論理に従えば、事は上手くいく。

2つ目の答え:ビジネス ペイロードにシーケンス番号がない。結局言うだろう、 WS-Reliable Messagingを受け取った、なら、なぜそれが必要なのか?実のところ、これでは、世界をめちゃくちゃにすることになる。もし順番が、ビジネスレベルで重要であるなら、ビジネスレベルは、順番を示し、それが適切に処理されることを確認し、そしてそれを持続する必要がある。もし、ビジネスレベルで重要な順番を、一方で WS-Reliable Messaging-バスに押し込められたメッセージの順番に依存するようにし、他方でそれらが出てきた順番に依存するようにしたら、ビジネス論理(順番)という 永久的なフィーチャ をメッセージ処理という 一時的なフィーチャ に依存させることになる:メッセージバスから出てくる順番。 WS-ReliableMessaging バスがその仕事を終えた後に、WS-ReliableMessaging のシーケンス番号が失われる。そうなると、まともなロギングや監査はできない。もちろん、メッセージに新しいシーケンス番号をつけることはできる。こうすれば、メッセージがこの順で、 WS-Reliable Messagingボックスから出てきたことは、示せるが、まだ、WS-Reliable Messaging ストリーム全体をロギングなしでは、本格的な監査の目的には、これは、ほとんど意味が無い。そして,確かにWS-Reliable Messaging ストリーム全体をロギングすることは、できる。しかし、それは、全く間違ったところで物事をしているように見える。

更に、順番処理は、単なる、WS-Reliable Messaging バスとビジネス層間でのやりとりのフィーチャではない。もし私の銀行が2つの銀行の合併でできたもので、私の普通預金口座 がたまたま当座預金口座とは違うデータベース、違う場所の違うマシンにあったとする:そうなると単に、WS-Reliable Messaging バスからビジネス層に、正しい順番で、メッセージを送ることは、ちゃんとそのジョブを実行したことには、全くならない。ビジネス層は、普通預金ソフトと当座預金ソフトがそれらのジョブを正しい順番で実行していることも確認する必要がある。この例は、順番処理がいかに深くビジネス論理に組込まれる可能性があるかを示している。

まとめると:もしメッセージの順番(通りの)処理がやっているビジネスの特性であるなら、ビジネスレベルのメッセージ中に順番を示す指標が、適切なビジネス セマンティクスとビジネス論理と一緒に付与されている必要がある。もし我々がこの単純かつ充分な設計ガイドラインに従うなら、 WS-Reliable Messagingは、不要である。多分,ある場合には、 WS-Reliable Messagingを使いほうが効率的かもしれない。しかし、ビジネス見地からすると、機能的には、適切にビジネス層が実装されていれば、WS-Reliable Messaging は、不要である。

1度、1度だけ

同様な論理の道筋が正確に1度の配送についても適用できる。あなたへのメッセージがある:ビジネスレベルでは、1回そしてたった1回だけ配送されるというは,重要である。では、私は本を発注した:同じタイトルの本を2回も受け取りたくない。絶対にそんなのは、ごめんである。ビジネスレベルで私の本を正確に1回受け取ることが、もし我々に重要であるなら、私のメッセージが正確に1度だけ受信される、という保証は、私に一体何をもたらすのか?私は、あなたの本の注文システムがそれを受け取ったことを知りたい。もしWS-Reliable Messaging バスがそれを受け取って、その後に、私が間違ったクライアント番号や存在しないカタログ商品を入力したことで、本の注文システムが注文を拒否したら、メッセージが受信されたことを知るのは、私にとって保証にはなっていない。メッセージが構文的にも意味的にも正しい時でさえ、もしそのタイトルが品切れなら、私には意味が無い:もし私のメッセージに対する処理が1回そして正確に1回が、ビジネスレベルで重要なら、私は、ビジネスレベルで正確に1回処理されていることを確認する必要がある。下図が示すように、トランスポート・アック(Transport Ack)は、ビジネスレベルでは、全く意味が無い:我々にはビジネス アックが必要である

WSRMモジュールは、入ってくるメッセージもシンタックス チェックをすべきだ、と言う人がいるかもしれない。そしてもちろん、WSRMモジュールは、例えばスキーマ検証を含んで、シンタックス チェックのほとんどを実行する。しかし顧客番号やカタログ項目を見る:データベースを見ないで、ある顧客番号やカタログ項目が正しいものかどうかを知るのは,不可能である。そして、あるタイトルの本が在庫しているかどうかを知ることは、構文レベルでは、全く不可能である。メッセージを実際にビジネスレベルで発行せずに、そのメッセージがビジネスレベルで受け入れられることを保証する方法はない。そして、ビジネスレベルで私のメッセージが拒否されるかもしれないのに、 WSRMモジュールが正しくそれを受信したかを知ることは、私には不要なことである。ビジネスレベルで、私のメッセージが1度そして1度のみ受信されたことを確認して、私はビジネスレベルの返答が必要である。もしビジネスレベルで、あらゆるメッセージが正確に1度だけ受信することが重要であるなら、ビジネスレベルが、メッセージが受信され、受け入れられた,というメッセージを返信すべきである。またしても、もしこの簡単な設計ガイドラインが守られるなら、ビジネスの見地からは、機能上、別の信頼できるメッセージングは、不要である。

「正確に1度」という要求をもう少し詳細に調べてみよう。ビジネスレベルで、あらゆるメッセージが正確に1度だけ受信することが重要である、ということは、順番処理のように、各メッセージは、ユニークなビジネス トランザクションを構成する,ことを意味する。 順番処理の場合のように、WSRM は、メッセージ、アック受理証そしておそらく再送、あるいは、重送の排除に付加されたユニークな番号によって、 正確に1度を保証する。またしても、もしあらゆるメッセージがユニークなビジネス トランザクションであるなら、明らかにビジネスレベルでユニークなIDでなければならない:注文ID、予約番号、あるユニークなトークン。そしてもし、そのようなユニークなトークンがビジネスレベルで必要なら、ビジネスレベルがそのユニークさを主張すべきである。ビジネスレベルのユニークさは、メッセージ レベルの一時的なユニークさに依存すべきではなく、ビジネス メッセージの永続的なフィーチャにならなければならない、そしてビジネス セマンティクスがそれを保証しなければならない。

冪等性による解決

ビジネス論理が順番処理や正確に1度の配送が必要なら、私は、明らかにビジネス応答が必要である:ビジネス応答が、ビジネスレベルで,私のメッセージが受信され,正しく処理されたことを唯一保証する。すべてのWSRM のマジックをやめて,単にビジネス応答を返せば,目的が達成でき、しかも WSRMがやるよりも、うまいやり方でできる。もし、ビジネスレベルで、ユニークなトランザクションIDとビジネス アックを実装したら、どうなるだろうか? 基本的には、我々は、メッセージ トランスポート レベルで、あらゆるメッセージを冪等にする。もしユニークなビジネスID、ビジネスレベルでの重送の検知、そしてビジネス応答を持てば、メッセージ レベルで再送することは、いつも安全である。こうすると信頼できるメッセージングを非常に簡単にできる:もし、私が HTTP 200 OK応答(あるいはある他の「成功」応答)を私のメッセージで受け取ったら、すべて順調なのである:私のメッセージは受け取られ、そしてもし、ビジネス応答が、HTTP応答で送られなかったら、私は受け取るまで待ってもよい。もちろん、webサービスを実装する際に、我々は、'200 OK'で返信する前に、入ってくるメッセージが なんらかの永続的なメディアに保存されることを確認する必要がある-さもないと、もしコンピュータがクラッシュしたら、メッセージは失われてしまう。しかし、WSRMでも同様な保証が必要だろうが、WSRM自身はそれを提供していない。そしてもし、私がある通信上の障害で '200 OK' を受け取らなかったら、応答を受け取るまで、今や、冪等メッセージを再送することは,安全である。

オランダのヘルスケアの事例

オランダで、我々は全国的なヘルスケアのインフラを設置している。全ヘルスケア組織は、中央の Healthcare Information Brokerを介して情報を交換する。関連する資格をもった全てのヘルスケアの専門家は、全国的な情報交換網によって、患者の情報にアクセスできるようになる。オランダの標準化団体、Nictiz[4]、 HL7v3をベースに関連する国内の標準、医療のVocabularyとメッセージングのフレームワーク、そしてWebサービスを開発した。

元もと、信頼できるメッセージングの標準は、なかった:2003年と2004年に、WS-Reliability 対 WS-ReliableMessagingの縄張り争いがあった。これはまだ続いている。我々は、騒ぎが収まるまで、暫定的に自前のソリューションを使うことを決めていた。2008年 と 2009 年には、我々は、信頼性の問題に戻った:国内交換網がすぐに立ち上がってきたので、暫定的なソリューションは、もはや使えなくなった。 WS-ReliableMessagingをベースにソリューションを設計したが、それには従わないことを決めた。では、詳細を見てみよう。

順番処理は、我々の場合には、ほとんど関係なかった:正確に1度の配送も同様だ,と考えた。我々は、同期コミュニケーション、 SOAP over HTTPを使っている。これでは、メッセージは、HTTPリクエストとして、送られ、そしてビジネス回答は、HTTP応答で送られる。少し単純化すると、2種類のトランザクションがある:

  1. クエリ、患者の薬歴に関するクエリ、クエリ応答は、HTTP応答で返される;
  2. 注文、薬の処方箋、ビジネス応答(通常、 HL7v3受領書)は、HTTP応答で送られる。

最初のケース、クエリには、信頼できるメッセージングは、単に不要である。もし通信障害かなんかでクエリやその返答がなくなってしまったら、単にクエリをもう1回発行すれば良い。クエリは安全である:サーバーの状態は、とにかく変わらない(おそらくトラフィック カウンタ値とか他の無関係な副作用は別にして)。

発注に対しては、話が違う。もしGP(一般医)が薬剤師に処方箋を送ると、それが1度だけ受け取られたことを知ることは、重要である。もし全てが上手く行けば,何の問題もない:GPが処方箋を送り、薬剤師のサーバーがHTTP '200 OK' 応答を返し、そして、GPのアプリケーションが処方箋が届いたことを報告する。もし事態がうまく行かないと、問題である:GPのアプリケーションが'200 OK' 応答を受け取らなかったら、どうすればいいのか?もし処方箋が薬剤師のサーバーに届かなければ、もう一度送られるべきである。もしそれが着かなかったら、再送されないかもしれない:それは、送りなおしではなく、2つ目の処方箋と解釈されるかもしれない。

しかし、処方箋は、ユニークな処方箋IDをすでに持っている。


    

このXML片がHL7v3 フォーマットでの、処方箋の識別子を示している。 'root' 部分がOIDで、各ヘルスケア プロバイダーのアプリケーションに割り当てられている:いかなる2つのアプリケーションも同じroot特性を持つことはない。'extension'の部分は、処方箋用のローカルなユニークなキーである:同じ番号が処方箋にも印刷される。両方で、グローバルにユニークな識別子となる。

処方箋IDは、ユニークなので、受け取り側にこの処方箋IDを使って、処方箋がダブってないかチェックを依頼する。もし処方箋が2回受け取られたら、エラーメッセージが返信される。(ある場合には、必要であれば、受け取り側に元の返信のコピーを返すよう、要求する、もしそれが必要となる情報を持っているなら)。これはどういうことなのか? 重送は、ビジネスレベルで除かれているので、全てのメッセージは、冪等である:コミュニケーションが疑わしい時には、いつでも再送は許されているのである。

トランスポート レベルの信頼できるメッセージングのユースケースの多くは、なくなってしまう:もし確認応答(アック)が受け取れなかったら、処方箋は再送される。最初の処方箋が受領された時に、どのみち受け取るエラーは、元のアックと同等なくらいに、転送が成功した証拠となる。我々は、返信とこの特別なエラー条件の解釈について、我々のスペックをちょっと厳しくした、その結果、突然、信頼できるメッセージングがもはや不要となった。それには、ほとんど骨の折れることは、なかった: HL7v3は、ユニークでなければならない処方箋IDを持っているので、それぞれのヘルスケア アプリケーションは、とにかく重複した処方箋IDを処理しなければならない。もしアックが、GPが受け取る必要のある情報を持っているなら、我々は、薬剤師に、2重に処方箋を受け取ったら、元のアックを再構成して、返信するように要求することもできる:そのような状況が頻繁に起きることもないので、単純なアックには、それは不要である。ところで、ビジネスルールを少し厳しくして、別のトランスポート層の信頼性の必要性を排除した:それがやろうとしたのは、またしても、ユニークなIDを与え、重複に取り組もうとしたのである。 WS-ReliableMessagingだけではなかった。それが主要な競争相手だった。しかし ebMXL Messaging や WS-Reliabilityに対しても、同様な論理の道筋があてはまるのである。

WS-ReliableMessaging単独では、同期メッセージングにも充分ではない。クライアントがファイアウォールの背後にあったり、信頼できない携帯接続がある場合、クライアントは、サーバーから直接にはアクセスできない。そのため、もしHTTPコネクションが突然クローズしたら、サーバーには、クライアントに確認されていない応答を再送する術がない。この場合別のWS-*仕様が必要である: WS-MakeConnection、これは、クライアントに新しいHTTPコネクションを確立して、潜在的に待っている応答メッセージをポーリングする。オランダのヘルスケアにおける我々の全トラフィックは、同期式なので、この追加が必要である。必要な全クライアントを WS-ReliableMessagingの能力を加えるようにアップグレードするのではなく、ずっと新しい WS-MakeConnectionも必要である(そして今日の大抵のクライアントは、単純に、必要なライブラリを持っていない)。 WS-MakeConnectionは、また失敗の時には、基本的に全ての同期トラフィックを非同期にする。これは必ずしも悪いことではないが、オランダのヘルスケアの仕様をもっとずっと複雑にしただろう。WS-* のマントラが、しばしばある:仕様書の複雑さが、ソフトウェアによって開発者から隠れる:あなたのWS-*ライブラリをインストールする、するとそれらは、あなたに魔法をかける!私は、この「複雑さで隠す哲学」を決して信じない。まともな開発者は、このレベルの背後で何が起きているのかを知りたく思うものである。もしあなたのトラフィックが同期であったり、こっそり分割されているのを分かっていなかったら、生のセッションでデバッグするのは,不可能である。

結論

オランダのヘルスケアでは、信頼できるメッセージングの複雑さを考え、そしてビジネスの観点から大抵の場合それを使うことはない、という事実を考慮して、我々は、トランスポート層で信頼できるメッセージングを使わないことに決めた。ユニークな処方箋をとにかく要求する、という少しばかり厳しいビジネス論理によって、我々はずっと単純なソリューションを得ることができた。

要約すると:もし信頼性がビジネスレベルで重要であるならば、ビジネスレベルでそれをやるべきである。信頼できるメッセージング層は、一般的な論理のみを処理できるが、それは我々が欲しいものではない:我々が欲しいのは、順番処理と1度だけの処理のためのビジネス特有の論理である。WS-Reliable Messaging (あるいはそのライバル達)は、時には、ソリューションを最適化する,特にポイント・ツー・ポイント の場合に、ある程度の価値を持つかもしれない。しかし、ビジネスの観点からは、よく設計されたビジネス ソリューションには、信頼できるメッセージングは、必要ない。

著者について

Marcは、IT経験が20年以上ある独立のコンサルタントである。彼の専門は、クロス-エンタプライズの相互運用性とセマンティクスで、よくスピーチと出筆をしている。Marcは、オランダのアムステルダムに住み、そして働いている。


[1] Stefan Tilkov, Addressing Doubts about REST (http://www.infoq.com/articles/tilkov-rest-doubts)を参照。 point 7: RESTは、信頼できない,という議論

[2] Joe Gregorio, RESTify DayTrader, http://bitworking.org/news/201/RESTify-DayTraderを参照。

[3] Paul Fremantle, An Introduction to Web Services Reliable Messaging, 素晴らしい概要: http://www.infoq.com/articles/fremantle-wsrm-introductionを参照。

[4] http://www.nictiz.nl/

この記事に星をつける

おすすめ度
スタイル

BT