非同期な世界
長い間設計やコーディングをしてきて同期的な処理(要求を出すとこたえがすぐに返ってくる処理)に慣れてしまうと、非同期な処理(要求を出したがこたえをすぐには期待しない処理)は非常に不安なものです。しかし、よく世界を観察すると同期処理で動いているものばかりではないことに気づきます。
よく例として挙げられるのがメールです。紙のメールにせよ、電子メールにせよ、すぐにこたえが返ってくるわけでもなく、そのように望んでいるわけでもありません。これに対し電話は同期処理です。相手が忙しいかどうかに係わりなく通じます。「この忙しい時に!」というのは仕事中よくあることです。
最近では、急ぎではなく事実として残しておきたい用件は、電子メールでやり取りすることが普通となってきました。システムもまた然りです。要求先の忙しさに関係なくコミュニケーションするには非同期な処理が向いています。これをシステム的に言うと同期通信と非同期通信と呼びます。
それでも不安は残る
システムでも非同期通信向きのものがあることは理解しやすいと思いますが、一方で信頼性に欠けるのではないかという不安が残ります。これについては、電子メールでも返信を求めることができるように非同期通信でも信頼性を保つための仕組みがあります。これは後ほど説明します。
JMS(Java Message Service)とは何か
JMSというAPIができて非同期通信が実現できたわけではありません。メッセージング指向のミドルウェア(MOM:Message Oriented Middleware)製品が登場し非同期通信が可能になり、それらをJava EE(当時はJ2EEという呼称)に取りこむための仕組みがJMSです。JDBCが特定のデータベース製品を意識しなくて済むように開発されたのと同様、JMSもコーディングするのに特定のMOM製品を意識する必要はありません。
プレイヤー
JMSを使って非同期通信を行うために必要なプレイヤーは表1の通りです。
プレイヤー | 役割 |
コネクションファクトリ | コネクションファクトリは文字通りコネクションを生成するための役割を持っています。デスティネーションとともに管理オブジェクトの一つであり、MOM製品をカプセル化しています。 |
デスティネーション | 直訳すると「宛先」ですが、実質的に後に説明するキューまたはトピックを指します。つまり、宛先であることに間違いないのですが、現実世界で言うと郵便ポストだと考えると分かりやすいと思います。私たちは手紙や葉書を出す場合、ポストが宛先ごとに膨大な数の投入口があったとしたら非常に面倒です。実際はポストに入れた後、集配局が手紙や葉書の宛名をもとに届けてくれるわけです。 |
コネクション | MOM製品とクライアントの間の通信路をカプセル化します。JDBCでいうコネクションに近い概念です。データベースがOracleやMySQLなどJBDCが意識しなくてもいいのと同様です。JMSのコネクションをクローズするとセッション、メッセージプロデューサ、メッセージコンシューマもクローズされます。 |
セッション | セッションはコネクションから生成されるシングルスレッドであり、メッセージを生成します。 |
メッセージプロデューサ | セッションによって生成されます。デスティネーションへメッセージを送信します。 |
メッセージコンシューマ | セッションによって生成されます。ディスティネーションからメッセージを受信します。 |
メッセージ | デスティネーションを介してメッセージプロデューサとメッセージコンシューマの間で授受されるものです。 |
メッセージドメイン
ITの世界にはドメインという言葉が使われますが、その文脈(コンテクスト)によって意味が異なるため混乱します。JMSではメッセージプロデューサとメッセージコンシューマのカーディナリティとメッセージの授受の方法により次の2つのドメインが定義されています。「Java Message Service API Tutorial」を参考に説明します。Oracle Sun Developer NetworkのJMSページの[Get the Specification]リンクをたどり仕様書を入手してください。
Point-to-Pointメッセージドメイン
Point-to-Point(以降、PTP)メッセージングドメインは以下の特徴を持ちます。
- メッセージプロデューサは1つのメッセージコンシューマのみと通信します。PTPではメッセージプロデューサを送信側(Sender)、メッセージコンシューマを受信側(Receiver)と呼びます。
- メッセージの送信側と受信側はタイミングに依存しません。これは送信側がメッセージを送った時、受信側が起動していなくても、後に起動した際に取得できることを指します。メッセージはデスティネーションに保持されているため、受信側がデスティネーションに取りに行くことが可能になります。PTPの場合、デスティネーションをキューと呼びます。
- 受信側はメッセージ取得後に通信処理の成功を通知します。メッセージ同様、通知はキューに対し送られます。
送信側はキューにメッセージを送り(図1の1)、受信側はキューからメッセージを取り出します(図1の1)、受信側はメッセージ取得後、成功した旨をキュー(正確にはセッション)に通知を送ります(図1の2)。1が2つあるのは、順序性がないからです。受信側はキューにメッセージがあるかどうかに係わらず、キューからメッセージを取得しようとします。
Publish/Subscribeメッセージドメイン
Publish/Subscribe(以降、Pub/Sub)メッセージドメインは以下の特徴を持ちます。
- メッセージプロデューサは複数のメッセージコンシューマと通信可能です。Pub/Subではメッセージプロデューサを発信者(Publisher)、メッセージコンシューマを購読者(Subsciber)と呼びます。
- Pub/Subでもメッセージのパブリッシャとサブスクライバはタイミングに依存します。購読者が発信者のメッセージを受け取るにはデスティネーションに対し事前に購読申し込みを行っておく必要があります。Pub/Subの場合、デスティネーションをトピックと呼びます。一旦購読申し込みを行えば、PTPのようにキューにメッセージを取りに行く必要はありません。トピックが購読者にメッセージを送ってくれます。
PTPと違って購読者が発信者からメッセージを受け取るには、購読者が購読申し込み(サブスクライブ)する必要があります(図2の1)。一度購読申し込みを行うと、購読者はトピックからメッセージを取りに行く必要がなくなります。発信者からトピックにメッセージが送られると(図2の2)、トピックは購読申し込みを行っている購読者すべてにメッセージを配信します(図2の3)。
JMSプレイヤーとメッセージドメインの整理
JMSプレイヤーとメッセージドメインで言葉の使い分けをしたり、メッセージドメイン間でその仕組みが異なります。表2で違いを整理しています。
比較項目 | Point-to-Point | Publish/Subscribe |
メッセージプロデューサ | 送信側 | 発信者 |
メッセージコンシューマ | 受信側 | 購読者 |
デスティネーション | キュー | トピック |
タイミング | 依存しない | 依存する |
カーディナリティ | 送信側:受信側=1:1 | 発信者:購読者=1:n |