以下、本開示の通信方法及び通信システムについてその実施の形態を示す図面に基づいて具体的に説明する。
図1は、本実施の形態における通信システム100の概要図である。通信システム100は、複数のサーバ装置1と、複数のクライアント装置2とを含む。サーバ装置1及びクライアント装置2は夫々、ネットワークNを介して通信することが可能である。特に複数のサーバ装置1は相互に通信接続することが可能である。このときネットワークNに参加するサーバ装置1の数は例えば数十台である。クライアント装置2は複数のサーバ装置1の内のいずれかと通信接続(セッションを確立)することが可能である。複数のサーバ装置1はいずれも、共通するデータベース3にアクセスが可能である。データベース3はサーバ装置1内部又はサーバ装置1外部に通信媒体を介して接続可能に設けられている。複数のデータベース3は内容が同期するようにしてあり、サーバ装置1は、いずれのデータベース3から情報を取得してもよい。
複数のサーバ装置1は夫々サーバコンピュータであり、Pub/Sub 型メッセージ送受信システムにおけるブローカとして機能する。複数のクライアント装置2は所謂IoT機器であって、無線による通信部と、センサ又はスイッチとを含む機器である。クライアント装置2はスマートフォン等の通信端末機器であってもよい。クライアント装置2は夫々、パブリッシャ又はサブスクライバのいずれか一方若しくは両方として機能する。例えばスマートフォンであるクライアント装置2によって遠隔からスイッチ機器のクライアント装置2へ制御内容を送信して制御したり、センサ機器であるクライアント装置2からスマートフォンであるクライアント装置2へ測定結果を送信したりする。前者のパターンではスマートフォンであるクライアント装置2がパブリッシャとして、スイッチ機器であるクライアント装置2がサブスクライバとして機能し、後者のパターンではセンサ機器であるクライアント装置2がパブリッシャとして機能し、スマートフォンであるクライアント装置2がサブスクライバとして機能する。
通信システム100では、複数のサーバ装置1群の利用をクライアント装置2に許可することにより、クライアント装置2から他のクライアント装置2をネットワークN経由で制御したり、多数のクライアント装置2から情報を収集することを可能としたりするサービスを実現することが可能である。ここで、スマートフォンであるクライアント装置2からスイッチ機器であるクライアント装置2を制御するに際し、これらの間を2つのサーバ装置1がブローカとして仲介する場合を考える。クライアント装置2とサーバ装置1との間、又は2つのサーバ装置1間のセッションが切断されるか、サーバ装置1が動作を停止(ダウン)したことで、制御情報を含むメッセージが損失すると、スイッチ制御が意図されたものとは異なる内容となる可能性がある。本実施の形態における通信システム100では、セッションを確立するサーバ装置1とクライアント装置2との間におけるメッセージの到達保証のみならず、複数のサーバ装置1を経由するメッセージのやり取りにおいてもサーバ装置1のダウンさえも考慮した到達保証を実現する。
図2は、通信システム100を構成する各装置のハードウェア構成を示すブロック図である。サーバ装置1はサーバコンピュータを用いる。サーバ装置1は、ハードウェア的に1台のサーバコンピュータに対して、論理的に1つの装置として実現されるとは限らない。大抵の場合、1台のサーバコンピュータにて論理的に複数が動作する仮想マシンにより実現される。後述のクライアント装置2及びデータベース3についても同様である。ただし説明を簡易とするため、以下の説明では、サーバ装置1及びクライアント装置2は物理的に1つのコンピュータを用い、データベース3は1つの記憶装置を用いることとして説明する。
サーバ装置1は夫々、制御部10、第1記憶部11、第2記憶部12、一時記憶部13及び通信部14を備える。制御部10はCPU(Central Processing Unit )、GPU(Graphics Processing Unit)等のプロセッサを用い、第1記憶部11に記憶されているサーバプログラム1Pに基づいた各処理を実行し、汎用サーバコンピュータをPub/Sub 型メッセージ送受信システムにおけるブローカとして機能させる。なお本実施の形態のサーバ装置1は基本的には、MQTTモデルのブローカに準拠した動作を行なう。一時記憶部13はDRAM(Dynamic Random Access Memory)等の揮発性メモリを用いて制御部10の処理により生成される情報を一時的に記憶する。
第1記憶部11は、ハードディスク又はフラッシュメモリ等の不揮発性メモリを用いる。第1記憶部11は、サーバプログラム1Pのほか、制御部10が処理の際に参照する情報を記憶する。
第2記憶部12は、第1記憶部11同様にサーバ装置1が内蔵する不揮発性メモリの一部を用いるか、又は、外部の記憶装置を用いる。第2記憶部12は、後述する通信処理においてサーバ装置1間で共有されるべきデータベース3として利用される。データベース3の内容については後述にて詳細を説明する。
通信部14は、ネットワークカード又は無線通信デバイスを用い、ネットワークNへの通信接続を実現する。通信部14はTCP/IPに準じた通信を行なうが、これに代替するプロトコルであっても構わない。サーバ装置1は通信部14によりネットワークNを介した通信接続を実現し、他のサーバ装置1との間で、1対1でセッションを確立し、図1に示したようなメッシュ状のネットワークを構築する。
ネットワークNは、所謂インターネットである公衆網、通信キャリアネットワーク、及びIoTサービスを実現する事業者の事業者ネットワーク、それらへの接続拠点である基地局、アクセスポイント等を含む総称である。なおサーバ装置1はネットワークNの事業者ネットワークからネットワークNへ接続し、クライアント装置2は公衆網、通信キャリアネットワークからネットワークNに接続している。
データベース3は上述したようにサーバ装置1の第2記憶部12を用いて実現されるか、又はサーバ装置1からは独立した外部記憶装置(ハードディスク及び記憶処理部)を用いてネットワークNに接続されている構成としてもよい。
クライアント装置2は種々のコンピュータによって実現されるが、少なくとも制御部20、記憶部21、及び通信部23を備える。制御部20は、CPU、マイクロプロセッサ等及びクロックを用い、記憶部21に記憶してある端末用プログラム2Pに基づいた各処理により、汎用コンピュータをPub/Sub 型メッセージ送受信システムにおけるパブリッシャ又はブローカとして機能させる
記憶部21はフラッシュメモリ等不揮発性メモリを用いる。記憶部21にはPub/Sub 型メッセージ送受信を実現するための端末用プログラム2Pが記憶されているほか、制御部20が処理の際に参照する情報を記憶する。
通信部22は、ネットワークカード又は無線通信デバイスを用い、ネットワークNへの通信接続を実現する。
通信システム100におけるメッセージの到達保証を実現する具体的方法について、以下フローチャート及び説明図を参照しながら、下記のように段階的に説明する。
1.装置間の通信における前提
(0)装置間のセッション
(1)QoS (到達保証)の基本
(2)keep接続
(3)ブローカ間のセッション
2.複数の保証レベル
(1)QoS =0(ゼロ)
(2)QoS =1、ただしブローカがダウンした場合は保証しない
(3)QoS =1、ブローカがダウンした場合も保証する
(4)QoS =2、ただしブローカがダウンした場合は保証しない
(5)QoS =2、ブローカがダウンした場合も保証する
[1.装置間の通信における前提]
(0)セッション
クライアント装置2とサーバ装置1、サーバ装置1とサーバ装置1の間は基本的に、互いにセッションを確立し、そのセッション内でメッセージをやり取りする。サーバ装置1は、複数のクライアント装置2及びサーバ装置1とセッションを確立することができ、そのセッション毎に通信相手を識別している(誰とのセッションかを識別する)。
(1)QoS (到達保証)の基本
複数のサーバ装置1は、上述したように基本的にMQTTモデルにおけるブローカに準拠している。したがってサーバ装置1は、クライアント装置2及び他のサーバ装置1との間のメッセージのやり取りについて、MQTTモデルの到達保証をベースに処理を実行する。図3は、MQTTモデルにおける到達保証を示すシーケンス図である。MQTTモデルでは、送信者からpublish メッセージとしてデータが送信され、このpublish メッセージは、トピック([topic] )、送信対象のデータ(ペイロード)([data/payload])、及び到達保証レベル([qos])を含む。到達保証レベルによっては、パケットを識別するパケットID([packet_id])を含む。なお、ここ及び以下の説明にて[]内はフィールド名の例を表わし、各々には適切な数値又は論理値が入り使用される。図3のシーケンス図では、メッセージの送信者と受信者との間のメッセージについての取決めが、QoS レベルが0(ゼロ),1,2である場合について夫々示されている。送信者は、メッセージを送信する(publish )に際し、QoS レベル(qos )を0,1,2のいずれかから指定することができる。
図3Aで示すように、パブリッシャである送信者があるトピック(topic )についてデータ(data)をpublish メッセージとして送信する際に、QoS レベルとして「0(ゼロ)」を指定した場合、そのメッセージに対して受信者は、受信処理以外の処理は行なわない。これにより送信者側からは、メッセージが到達したか否かを確認することはできず、到達していない場合にもその状況を知り得ない。ただ、最新のデータをその都度送信する場合には、QoS =0で十分に足りる。
図3Bで示すように、パブリッシャである送信者があるトピックについてデータを送信する際にQoS として「1」を指定した場合(qos =1)、送信するパケットのパケットID(packet_id)を送信者と受信者との間のセッション内で採番して指定して送信する(図3Bではpacket_id=0x10)。この場合受信者は、パケットIDを指定してpubackというメッセージを返し、送信者側はこのpubackメッセージを受信するまで、送信したデータをパケットIDと共に保持(一時記憶)する。送信者があるトピックについてデータを送信し、その送信に対してpubackメッセージを受信する前に受信者との間でセッションが切断された場合、送信者は受信者とのセッションを再確立した後に、一時記憶しているpublish メッセージを、記憶しているパケットIDを指定して再送する。これにより、送信者は、受信者側でデータを受信した事実を知ることができ、受信者は、セッションの切断があったとしても必ずデータを受信することができる。ただしこの場合、データが受信者に到達してからセッションが切断されたか、到達する前に切断されたかを区別することができず、データを受信してからセッションが切断された場合には、同一のデータを複数回受信することになる。
図3Cで示すように、パブリッシャである送信者があるトピックについてpublish メッセージを送信する際に、QoS として「2」を指定した場合、「1」を指定した際と同様に、送信するパケットのパケットIDを採番して使用して送信する(図3Cではpacket_id=0x11)。この場合受信者は、パケットIDを指定してpubrecメッセージを返し、同一のパケットIDを指定して送信されたデータについては以後、破棄する。したがってデータの再送を受けたとしてもこれを破棄してデータの受信を1回のみとすることができる。送信者はこのpubrecメッセージを受信するまで、送信したデータをパケットIDと共に保持し、pubrecメッセージを受信した場合には一時記憶していたデータを破棄する。破棄したデータと共に記憶していたパケットIDは新たなデータの送信に使用できるので、送信者はこれを宣言するpubrelメッセージをパケットIDと共に送信する。受信者はこのpubrelメッセージを受信したことを示すpubcomp メッセージを送信し、これによりQoS レベルが「2」のメッセージの送受信は完了する。QoS =2の場合もセッションが切断された場合、送信者は受信者とのセッションを再確立した後に、pubrecメッセージを未受信であればpublish メッセージを再送し、pubcomp メッセージを未受信であればpubrelメッセージを再送する。
なお図3B及び図3Cで示したメッセージのやり取りの中で、セッションが切断されるケースでは、受信者側では、送信者側からpublish メッセージ又はpubrelメッセージが送信された場合にこれらのメッセージが再送か否かに拘わらず、これに応答してpubrecメッセージ又はpubcomp メッセージを応答として送信する。受信者側では、publish メッセージ又はpubrelメッセージを受信していないのにpubrecメッセージ又はpubcomp メッセージを再送することはない。
なお図3Aから図3Cに示したMQTTにおける到達保証は、送信者と受信者という2つの装置間でのメッセージの到達保証の規定である。したがって、同一のトピックの同一のデータについてパブリッシャから接続対象のブローカまでのメッセージがQoS レベルとして「2」を指定して送信されたとしても、サブスクライバまでの到達がQoS レベル「2」で保証されるわけではない。これに対し本実施の形態における通信システム100では、MQTTにおける到達保証を利用しつつ、その到達保証の対象を、直接的にセッションを確立する2つの装置間のみならず、サブスクライバへ到達するまでの経路で最適化する。更には、セッションの切断のみならずブローカがダウンして一時記憶が破棄される状態となった場合も含めてメッセージの到達を保証する。これらの到達保証の実現については[2.]以降で説明する。
(2)keep接続
通信システム100では、サブスクライバであるクライアント装置2からサーバ装置1へのセッション確立の際には、「keep」というオプションを選択できるようにしてある。keep接続は、MQTTモデルにおける「CleanSesson 」というオプションで「false 」を選択してセッションを確立することに対応する。クライアント装置2はサーバ装置1へ通信接続をリクエストする際に「keep」オプションをtrueに指定しておけば、サーバ装置1との間のセッションが切断されたとしても、切断されている間にサーバ装置1へ到達したメッセージを後に受信することができる。
keep接続を実現するための処理について説明しておく。図4は、keep接続が選択された場合のサーバ装置1の処理手順の一例を示すフローチャートである。サーバ装置1の制御部10は、サーバプログラム1Pに基づき、クライアント装置2からの通信接続のリクエストを検知すると以下の処理を実行する。
制御部10は、通信接続してきたクライアント装置2のクライアントID(user_id)及び通信接続してきたクライアント装置2からの接続のオプション(「keep」オプション(keep=true又はfalse ))を一時記憶する(ステップS1)。
制御部10はまず、クライアントIDを基に第2記憶部12のデータベースに記憶してあるセッション情報(後述のステップS8)を参照し(ステップS2)、接続してきたクライアント装置2に対応するセッション情報が新規であるか否かを判断する(ステップS3)。セッション情報がデータベースに存在せず、新規であると判断された場合(S3:YES)、制御部10はクライアントIDに対応付けて接続中であることを示す状態情報を新規に一時記憶部13に記憶し(ステップS4)、これにより新規セッションが開始される。
次に制御部10は、セッションを確立しているクライアント装置2からサブスクライブ対象とするトピックの指定を到達保証レベル(QoS )の指定と共に受信すると(ステップS5)、指定されたトピック及び指定されたQoS をクライアントIDに対応付けて一時記憶部13に記憶する(ステップS6)。
制御部10は、対象のクライアント装置2からの通信接続の「keep」オプションがtrueであるか否かを判断し(ステップS7)、trueであると判断された場合(S7:YES)、クライアントIDとに対応付けてステップS5にて対象とされた指定トピック(文字列)及びQoS をセッション情報として第2記憶部12のデータベース3(「keep_sub」テーブル)に記憶する(ステップS8)。ステップS8において制御部10は、記憶するセッション情報が既に記憶されている情報と同一である場合、そのままとしておけばよい。
その後制御部10は、指定トピックに対してパブリッシャからデータが送信される都度、このデータをサブスクライバであるクライアント装置2へ配信する処理を実行し(ステップS9)、該クライアント装置2とのセッションが切断されたか否かを判断する(ステップS10)。切断されていないと判断された場合(S10:NO)、制御部10は処理をステップS9へ戻し、指定トピックについての配信処理を続行する。
切断されたと判断された場合(S10:YES)、対応するクライアントIDの状態情報を消去して(ステップS11)、指定トピックの配信先をデータベースへと変更し(ステップS12)、処理を終了する。以後制御部10は、指定トピックについてのメッセージに含まれるデータ(ペイロード)については、トピックの識別情報に対応付けてデータベース3(「store 」テーブル及び「store_target」テーブル)に記憶する。
通信接続の「keep」オプションがtrueでない(即ちfalse である)と判断された場合(S7:NO)、制御部10は、指定トピックに対してパブリッシャからデータが送信される都度に、これをサブスクライバであるクライアント装置2へ配信する処理を実行する(ステップS13)。そして制御部10は、クライアント装置2とのセッションが切断されたか否かを判断する(ステップS14)。切断されていないと判断された場合(S14:NO)、制御部10は処理をステップS13へ戻し、トピックに対する配信処理を続行する。切断されたと判断された場合(S14:YES)、対応するクライアントIDの状態情報を消去して(ステップS15)、処理を終了する。この場合、第2記憶部12のデータベースには情報の記憶がされない。
ステップS3にてセッション情報が存在し、既存であると判断された場合(S3:NO)、対象のクライアント装置2は再接続であるから、制御部10はデータベースに同一のクライアントIDに対応付けて記憶されている指定トピックを読み出して状態情報を復元する(ステップS16)。
そして制御部10は、再接続時の「keep」オプションがtrueであるか否かを判断する(ステップS17)。trueであると判断された場合(S17:YES)、制御部10は、指定トピックについて第2記憶部12のデータベースに記憶されているデータ(ペイロード)を取り出して再接続してきたクライアント装置2へ配信する(ステップS18)。制御部10は、処理をステップS9へ進める。
ステップS17にてtrueでない(false )と判断された場合(S17:NO)、第2記憶部12のデータベースに記憶されているクライアントIDと指定トピックの対応であるセッション情報を消去し(ステップS19)、処理をステップS13へ進める。
図5は、keep接続によるサブスクライブ状態の維持を示す説明図である。図5は、サブスクライバであるクライアント装置2からブローカのサーバ装置1への接続、切断等のイベントを図の上部から下部へ時系列に示し、各イベントによるサブスクライブ状態の変化を示している。「keep」オプションをtrueに指定して接続した場合には、その後に切断されたとしてもその期間に指定トピックに対してパブリッシャから送信されたメッセージについて、再接続後に配信を受けることができ、サブスクライバであるクライアント装置2は漏れなくメッセージを受信することができる。
図6から図14を参照して、keep接続によるメッセージの配信処理実現の具体的方法をについて説明する。図6は、装置間の接続例を示す図である。識別情報「p1」のクライアント装置2(以下、サーバ装置1又はクライアント装置2(識別情報)と記載する)がパブリッシャとしてサーバ装置1(b1)(ブローカ)に通信接続し(セッションA)、クライアント装置2(s2)が、サブスクライバとしてサーバ装置1(b1)に通信接続(セッションB)する例を示している。サブスクライバであるクライアント装置2(s1)は、サーバ装置1へkeep接続(「keep」オプションをtrueに指定して通信接続)している。クライアント装置2(s1)からトピック「t1」が指定されると、サーバ装置1(b1)は、サブスクライバ毎に、その識別情報([user_id] )と対応付けて、指定トピック([topic] )及び指定されたQoS を含むセッション情報をデータベース3(「keep_sub」テーブル)に記憶する。図6の例では、サブスクライバであるクライアント装置2(s1)について(user_id=s1)、指定トピック(topic=t1)及び指定されたQoS ([qos] )を記憶している。
また図6では、クライアント装置2(s2)もサブスクライバとしてサーバ装置1(b1)に通信接続している(セッションC)。クライアント装置2(s2)は、サーバ装置1(b1)に通信接続する際に「keep」オプションをfalse (非keep)として通信接続しているので、データベース3(「keep_sub」テーブル)には対応するセッション情報が記憶されない。クライアント装置2(s2)がクライアント装置2(s1)と同様にトピック「t1」を指定した場合、以後、トピック「t1」についてパブリッシャであるクライアント装置2(p1)からpublish メッセージが送信される都度、ブローカであるサーバ装置1(b1)からはクライアント装置2(s1, s2)へ指定されたQoS でpublish メッセージが送信される。
図7は、図6の接続状態にて装置間で送信されるメッセージの具体例を示す。パブリッシャであるクライアント装置2(p1)は例えば、「t1」というトピックについて「a 」というペイロード(data/payload)を含むpublish メッセージを、その送信の都度、QoS (1又は2)を指定して送信する。図7中[qos] にてQoS の指定値が含まれることを示している。このpublish メッセージには、セッション毎に起点側で採番されるパケットID(packet_id=0x100 )が付与されている。図7の図に示す状態ではクライアント装置2(s1)の状態情報はonlineであってトピック「t1」をサブクライブしている。サーバ装置1(b1)は、到達したメッセージのトピック「t1」を参照し、該トピックを指定しているサブスクライバであるクライアント装置2(s1)へ向けてペイロード(data/payload=a)を含むpublish メッセージを送信する。サーバ装置1(b1)からクライアント装置(s1)へのpublish メッセージのQoS は、クライアント装置2(s1)がサーバ装置1(b1)へサブスクライブ対象のトピックを指定する際に指定してセッション情報として記憶しているQoS と、パブリッシャから送信される際に指定されたQoS との内の小さい方に調停される。またサーバ装置1(b1)から送信されるメッセージのパケットに付与されているパケットID(packet_id=0x101 )は、送信者であるサーバ装置1(b1)によって採番されている。同様にしてクライアント装置2(s2)へもペイロード(data/payload=a)を含むpublish メッセージが送信されている(パケットID(packet_id=0x103)は別途採番されている)。
図8は、図6に対する切断状態を示す図である。図8は、図6に示した接続状態から、クライアント装置2(s1, s2)とサーバ装置1との間のセッションB,Cが切断された状態となったことを示している。サーバ装置1では、クライアント装置2(s1)とのセッション切断を検知し、対応するセッション情報(s1)に対応するトピックについて配信先をデータベース3とすることを一時記憶している。一方でサーバ装置1は、クライアント装置2(s2)とのセッション切断を検知しても、このセッションは非keepであったので対応する状態情報(s2)を一時記憶していない。
図9及び図10は、図8に示した切断状態でパブリッシャからメッセージが送信された場合の処理の一例を示す。クライアント装置2(p1)が図7同様に、「t1」というトピックについて「a 」というペイロードを含むpublish メッセージを、QoS (1又は2)を指定して送信する。図中[qos] にてQoS の指定値がメッセージに含まれることを示している。この場合、ブローカであるサーバ装置1(b1)は、識別情報「s1」のセッション情報に対応するトピック「t1」のメッセージについては配信先をデータベース3とすることを記憶しているから、データベース3(「store 」テーブル)に、トピック毎にメッセージを記憶する。このメッセージは保存メッセージとして記憶される。保存メッセージは例えば、メッセージ各々を識別する識別子([store_id])、トピック([topic] )、メッセージの内容([data/payload])を含む。保存メッセージは、ブローカでの受信時刻([TS])を含んでもよい。図9の例では、「123 」の識別子(store_id=123)が付されたトピック(topic=t1)について「a 」(data/payload=a)という内容の保存メッセージが記憶されている。
図10に示すようにサーバ装置1(b1)は続けて、データベース3に記憶した保存メッセージ(「store 」)の配信先の情報(配信先情報)を、配信先の装置の識別情報毎に更にデータベース3(「store_target」テーブル)に記憶する。一回のpublish の実行に対し記憶される保存メッセージ(「store 」テーブル)は1つであるが、配信先情報(「store_target」テーブル)は、保存メッセージの配信先の数分だけ存在することとなる。配信先情報は、配信先の識別情報([user_id] )、送信した際のパケットID([packet_id] )、メッセージの識別子([store_id])、送信されたか否かを示すフラグ([already_sent])、及び送信する際のQoS ([qos] )を含む。図10の例であれば、保存メッセージ(id=123)が、クライアント装置2(user_id=s1)向けに未送信である(already_sent=false)ことを示す配信先情報が記憶されている。またメッセージのパケットIDが対応付けて記憶される。図10の例では、publish メッセージの受信時に配信先とのセッションBは切断していることが分かっており、この場合パケットIDはNULL(MQTTで利用できる範囲(0x0001-0xffff)外を設定)に設定されている。そして配信先に対応付けて、QoS が記憶されている。このQoS は配信先のサブスクライバからサブスクライブ対象のトピックを指定する際に指定したQoS と、パブリッシャからメッセージが送信される際に指定されたQoS とで数値が小さい方のQoS とする。
そしてサーバ装置1は、パブリッシャのクライアント装置2へ向けて、publish メッセージに対するpubackメッセージ(QoS =1)又はpubrecメッセージ(QoS =2)を返す。
図11は、再接続後の処理を示す。クライアント装置2(s1)がサーバ装置1(他のサーバ装置1でもよい)と再び通信接続すると(セッションB)、データベース3に記憶してあるセッション情報(「keep_sub」テーブル)から、サーバ装置1側で指定トピック等のセッション情報を読み出して状態情報を復元する。そしてサーバ装置1は、データベース3に記憶されている配信先情報(「store_target」テーブル)からクライアント装置2(user_id=s1)向けの未送信メッセージ(already_sent=false)を検索する。クライアント装置2(s1)への「123 」という識別子が付された保存メッセージが未送信であることが参照される。サーバ装置1はデータベース3(「store 」テーブル)から識別子「123 」である保存メッセージのペイロード(data/payload=a)を読み出し、サブクライバであるクライアント装置2(s1)へpublish メッセージとして送信する。このとき、クライアント装置(s1)向けの配信先情報では、予め切断していた状態であってパケットIDが採番されていなかった(NULLである)ので、改めてパケットID(packet_id=0x102 )が採番されている。配信先情報のパケットIDも採番されたパケットIDで更新される。クライアント装置2(s2)からの再接続については、前回の接続が非keepであったので状態情報は復元されることなしに、新たなセッション(セッションC)を確立する。また、クライアント装置2(s2)からサブスクライブするトピックを指定する処理が行なわれない限り、サーバ装置1は、クライアント装置2(s2)の指定トピックを認識しない。
サーバ装置1(b1)は、データベース3に記憶されていた配信先情報(「store_target」)を、配信先へ送信できたことによって削除する。具体的には例えば、配信先からpubackメッセージを受信し、配信先での受信が確実に確認できた場合に配信先情報を削除する。記憶の削除タイミングはこれに限らず、適切に設計されるとよい。識別子「123 」の保存メッセージは、識別情報「s1」の配信先情報のみの配信先が対応していたので、送信済みとなる。サーバ装置1(b1)はデータベース3(「store 」テーブル)から保存メッセージを消去する。ただし指定されているQoS によって処理が異なる。図12は、QoS =1の場合の処理例を示す。データベース3の配信先情報(「store_target」テーブル)におけるクライアント装置2(s1)向けのメッセージについてQoS が「1(At least Once )」である場合、サーバ装置1(b1)は、図11に示したメッセージ(publish )の送信後、クライアント装置2(s1)からpubackメッセージが返信されたことを確認すると、データベース3(「store_target」テーブル及び「store 」テーブル)から「s1」向けの「123 」に係るレコードを消去する。
図13及び図14は、QoS =2の場合の処理例を示す。データベース3に記憶されている配信先情報(「store_target」テーブル)に記憶してある情報が、「s1」向けのメッセージについてQoS が「2(Exactly once)」である場合の例である。サーバ装置1は、図11に示したpublish メッセージの送信後、クライアント装置2からpubrecメッセージが返信されたことを確認すると、図13に示すようにデータベース3の配信先情報(「store_target」テーブル)の未送信を示すフラグ(already_sent)の「false 」を「true」へ書き換え、pubrelメッセージをクライアント装置2へ送信する。配信先情報は、パケットIDは、pulish メッセージ送信時に採番された「0x102 」によって更新されている。そして図14に示すようにサーバ装置1は、pubrelメッセージに対してクライアント装置2からのpubcomp メッセージの受信を確認するとここで初めて、データベース3(「store_target」テーブル及び「store 」テーブル)からクライアント装置2(s1)向けの識別子「123 」を含む保存メッセージを消去する。サーバ装置(b1)がpubcomp メッセージを受信する前に、切断された場合、配信先情報は送信したか否かを示すフラグが送信済み(already_sent=true )を示したままデータベース3に保存されている。再確立後、サーバ装置(b1)は、再度pubrelメッセージの送信から処理を再開する。このとき配信先情報のパケットIDを参照してpubrelメッセージを送信している。後述の中途メッセージ情報による送信と重複する場合でも、パケットIDを保存しておき、再送時に利用することで、受信側で同一メッセージを棄却することができ、「Exactry once」を実現することができる。
図6から図14に示したように、サーバ装置1はデータベース3(「store 」テーブル及び「store_target」テーブル)に記憶する情報を利用したkeep接続を実現する動作を行なう。これにより、仲介するブローカの実体が1つである場合のセッションの切断に対するサブスクライバまでのメッセージの到達の保証は実現される。
keep接続が選択されている場合サーバ装置1は更に、QoS =1又は=2で接続しているクライアント装置2との間で、図3に示したMQTTモデルにおける到達保証用のメッセージのやり取り中にセッションが切断されたケースを考慮した処理を行なう。
図15Aは、サーバ装置1がセッション切断を検知した際に実行する処理手順の一例を示すフローチャートである。なお図15A及び図15Bの処理手順は、図3Aから図3Cに示した送信者側であるサーバ装置1における手順である。図15Aのフローチャートに示す処理手順は、図4のフローチャートに示した処理手順の内、ステップS10の後に実行される。
サーバ装置1の制御部10は、publish/pubrelメッセージを送信する際に詳細には、送信するメッセージをMQTT準拠のネットワークコントローラ(通信ライブラリ)の送信用ボックス(以下送信バッファ)にそのパケットを書き込む。ネットワークコントローラの動作により、送信用ボックスに書き込まれたパケットが対応するセッションの相手へのソケットに書き込まれ、送信が行なわれる。そしてネットワークコントローラの動作により、メッセージに対して応答されるべきメッセージ(puback/pubrec, pubcomp)を受信するとこの送信バッファからpublish/pubrelメッセージを消去する処理が行なわれる。
制御部10は、サブスクライバであるクライアント装置2との切断を検知すると(ステップS101)、送信バッファにメッセージが残存しているか否かを判断する(ステップS102)。残存していると判断された場合(S102:YES)、制御部10はその残存しているメッセージのパケットイメージをそのまま読み出し、データベース3(「keep_mqtt 」テーブル)に中途メッセージ情報として記憶する(ステップS103)。中途メッセージ情報は、送信先のクライアント装置2の識別情報(user_id )と、送信時刻(タイムスタンプ= [TS])と、メッセージのパケットイメージそのままとを含む。パケットイメージには、クライアント装置2へのメッセージ送信時に付与したパケットID、QoS 等が含まれている。送信バッファに残存しているメッセージは、セッションが切断(破棄)されると、対応するメッセージを受信していないにも拘わらず削除(破棄)され(ステップS104)、処理を終了する。
ステップS102にて残存していないと判断された場合(S102:NO)、制御部10は、そのまま処理を終了する。
図15Bは、サーバ装置1がセッション再開を検知した際に実行する処理手順の一例を示すフローチャートである。図15Bのフローチャートに示す処理手順は、図4のフローチャートに示した処理手順の内、ステップS18の前に実行される。
制御部10は、クライアント装置2からの通信接続を検知する(ステップS105)。制御部10は、通信接続の相手を特定して状態情報を復元しているので、中途メッセージ情報として、再接続してきたクライアント装置2(接続相手)を対象とする送信途中のメッセージがデータベース3(「keep_mqtt 」テーブル)に記憶されているか否かを判断する(ステップS106)。ステップS105にて記憶されていないと判断された場合(S106:NO)、制御部10は処理をそのまま次のステップS18へ進める。
ステップS105で記憶されていると判断された場合(S106:YES)、制御部10は、データベース3に中途メッセージとして記憶してあった送信時のパケットイメージをそのまま、再接続してきたクライアント装置2へ送信する(ステップS107)。制御部10は、データベース3から読み出した中途メッセージを送信すると、データベース3(「keep_mqtt 」テーブル)から該当する中途メッセージの記憶を削除し(ステップS108)、再開時の再送の処理を終了する。中途メッセージの記憶の削除タイミングはこれに限らず、対応するメッセージ(puback/pubrec )を受信した場合など、適切に設計される。
図16から図19を参照して図15A及び図15Bのフローチャートにおける処理を説明する。図16は、クライアント装置2がサーバ装置1と切断された状態を示す図である。なお図16はQoS =1に調停されている例を示す。図16に示すように、ブローカであるサーバ装置1(b1)がクライアント装置2(s1)へpublish メッセージを送信した後、pubackメッセージが返される前にセッションが切断されると(S101)、サーバ装置1(b1)の制御部10は、送信バッファにpublish メッセージが残存していると判断する(S102:YES)。したがって、サーバ装置1(b1)はデータベース3(「keep_mqtt 」テーブル)に、publish メッセージを中途メッセージとして記憶する(S103)。図16では具体的には、タイムスタンプ([TS])、クライアント装置(s1)の識別情報(s1)、publish メッセージ(topic=t1, packet_id=0x101, data/payload=a, qos=1)がそのまま記憶されている。これによりサーバ装置1(b1)では、pubackメッセージを受信していないために残存していたpublish メッセージが送信バッファから削除される(S104)。
図17は、図16の切断状態から復帰した場合の処理手順を示す図である。クライアント装置2(s1)が、サーバ装置1(b1)又は他のサーバ装置1に通信接続すると、サーバ装置1(b1又は他)ではこれを検知し(S105)、クライアント装置2(s1)向けのメッセージが、データベース3(「keep_mqtt 」テーブル)に中途メッセージ情報として記憶されているか否かを判断する(S106)。図16のケースでは、クライアント装置2(s1)向けのpublish メッセージが記憶されているので、通信接続先のサーバ装置1(b1)の制御部10はこれをデータベース3(「keep_mqtt 」テーブル)から読み出し、パケットID等をそのまま含むパケットとして再送する(S107)。データベース3(「keep_mqtt 」テーブル)からは一旦、中途メッセージとして記憶されていたpublish メッセージが削除される(S108)。クライアント装置2(s1)は、publish メッセージの再送を受け、pubackメッセージを送信する。pubackメッセージが送信完了された状態では、サーバ装置1側の送信バッファからも、データベース3(「keep_mqtt 」テーブル)における中途メッセージ情報からも、未送信であったメッセージが削除されて初期状態に戻る。これにより、メッセージのやり取りの途中で切断がされた場合に、サブスクライバであるクライアント装置2がいずれのサーバ装置1に再接続したとしても、その中断されていたMQTTにおける到達保証に係るメッセージのやり取りが完了する。
図18は、クライアント装置2がサーバ装置1と切断された他の状態の例を示す図である。なお図18はQoS =2に調停されている例を示す。調停後のQoS が「2」である場合(パブリッシャからのメッセージ送信時の指定及びサブスクライバからの指定がいずれも「2」)、ブローカであるサーバ装置1とサブスクライバであるクライアント装置2との間のセッションで考慮すべきメッセージのやり取りが未完了状態における切断のパターンは、符号Xで示すpubrecメッセージの受信前、及び符号Yで示すpubcompメッセージの受信前である。符号Xで示すpubrecメッセージの受信前においては、図16で示した処理同様に、サーバ装置1にて送信バッファにpublish メッセージが残存していると判断されるので(S102:YES)、データベース3(「keep_mqtt 」テーブル)に、中途メッセージ情報として、クライアント装置2(s1)向けのpublish メッセージのパケットイメージが記憶される(S103)。送信バッファからもpublish メッセージが削除される(S104)。そして符号Yで示すpubcomp メッセージの受信前においては、サーバ装置1にて送信バッファにpubrelメッセージが残存していると判断されるので(S102:YES)、データベース3(「keep_mqtt 」テーブル)に、中途メッセージ情報としてクライアント装置2(s1)向けのpubrelメッセージのパケットイメージが記憶される(S103)。
図19は、図18の切断状態から復帰した場合の処理手順を示す図である。この場合も、クライアント装置2(s1)がサーバ装置1(b1)又は他のサーバ装置1に通信接続すると、サーバ装置1(b1又は他)ではこれを検知し(S105)、クライアント装置2(s1)向けのメッセージがデータベース3(「keep_mqtt 」テーブル)における中途メッセージ情報に記憶されているか否かを判断する(S106)。図18の符号Xのタイミングで切断されていたところから復帰した場合には、クライアント装置2(s1)向けのpublish メッセージが中途メッセージ情報として記憶されているので、接続先のサーバ装置1(b1)の制御部10はこれをデータベース3(「keep_mqtt 」テーブル)から読み出し、パケットID等をそのまま含むパケットとして再送する(S107)。符号Yのpubrecメッセージの受信前のタイミングで切断されていたところから復帰した場合には、クライアント装置2(s1)向けのpubrelメッセージが記憶されている。サーバ装置1(b1)の制御部10はこれをデータベース3(「keep_mqtt 」テーブル)から読み出し、パケットID等をそのまま含むパケットとして再送する(S107)。これに対しクライアント装置2(s1)では、再接続した後にpublish メッセージの再送を受信した場合、これを既に受信処理している場合には破棄してpubrecメッセージを返信する。pubrelメッセージの再送を受信した場合には、pubcomp メッセージをサーバ装置1へ返信する。
同様にして、サーバ装置1(b1)は、パブリッシャであるクライアント装置2との間のセッションがpuback/pubrecメッセージ又はpubcomp メッセージの送信を完了する前に切断された場合には、クライアント装置2(s1)向けの、データベース3(「keep_mqtt 」テーブル)における中途メッセージ情報としてこれを記憶する。パブリッシャであるクライアント装置2(s1)が再接続してきた場合、サーバ装置1(b1)の制御部10は、このデータベース3(「keep_mqtt 」テーブル)を参照して通信相手先へのメッセージが記憶されている場合にはパケットイメージをそのまま送信する。
このようにMQTTモデルの処理手続きを実行中に切断が検知された場合、データベース3(「keep_mqtt 」テーブル)にメッセージが中途メッセージ情報として記憶される。これにより、再度セッションが確立されたときにその直前の状態に復元される。仮に、サブスクライバであるクライアント装置2(s1)が異なるサーバ装置1へ通信接続を行なったとしても、データベース3(「keep_mqtt 」テーブル)に記憶されている中途メッセージ情報は各サーバ装置1で共有し同期し合うので同一の状況を復元させることが可能である。
(3)ブローカ間の通信接続
通信システム100では、図1に示したようにブローカである複数のサーバ装置1が例えば数十台、相互にメッシュ状に通信接続する。サーバ装置1はブローカとして起動すると最初に、接続可能な他のサーバ装置1と通信接続を確立し、自身に通信接続しているクライアント装置2の情報(「connections」テーブル)を交換し、共有のデータベース3から参照して情報の同期処理を行なう。また、サーバ装置1間の接続は、いずれも上述のkeep接続で実現する。なおサーバ装置1は、自身に通信接続しているクライアント装置2が指定するトピックについて、サブクライブを実行する。実行先は、指定トピックのパブリッシャが通信接続している他のサーバ装置1である。サーバ装置1はいずれの場合もQoS を「2(Exactly once)」で指定する。サーバ装置1間のセッションが切断された場合、その間に自身に接続しているクライアント装置2が必要とするメッセージが送信されたとしても、他のサーバ装置1が保持していたものを取得して配信することが可能である。
[2.複数の保証レベル]
本実施の形態における通信システム100でサブスクライバまでのメッセージの到達保証は、全てのセッションが切断されずに安定的に維持している場合には、サーバ装置1間のkeep接続及びサーバ間におけるQoS =2の設定によって実現される。到達保証を妨げる要因は、セッションの切断、及びブローカであるサーバ装置1のダウンである。keep接続のみならず到達保証のために、後述するようにデータベース3を用いるが、データベース3のダウンについては冗長化によってこれを保証する。本実施の形態における通信システム100では、複数のブローカを経由するネットワークN上で、publish メッセージの送信時、又はサブスクライブ時に指定されたQoS レベルと、ブローカにおけるダウン時の動作選択に応じてメッセージ(データ)の到達を保証する。
ブローカであるサーバ装置1は、自身がダウンした場合、即ちサーバ装置1の実体がエラーにより消失、又は処理が停止することでプロセスが終了させられた場合に、それまでのメッセージ処理を保証するか否かを、起動時に選択する。サーバ装置1は、ダウンした場合にも保証する場合には、全ての処理をデータベース3に記憶することを前提とする。
QoS はクライアント装置2が通信接続しているブローカであるサーバ装置1へpublish メッセージを送信する都度、又はサブスクライブするトピックを指定する際に選択するオプションの1つであり、サーバ装置1はこれを認識して以後の処理を実行する。なお、サブスクライバであるクライアント装置2の指定トピックについてのQoS は、サブスクライブが解除されない限り維持される。
選択に応じた処理内容を順に説明する。保証レベルは以下のようになる。
(1)QoS =0(ゼロ)
(2)QoS =1、ただしブローカがダウンした場合は保証しない
(3)QoS =1、ブローカがダウンした場合も保証する
(4)QoS =2、ただしブローカがダウンした場合は保証しない
(5)QoS =2、ブローカがダウンした場合も保証する
(1)QoS =0(ゼロ)
パブリッシャであるクライアント装置2から、QoS =0(ゼロ)でメッセージが送信される場合の該メッセージについての各装置における送信に係る処理について説明する。パブリッシャであるクライアント装置2から、QoS =0を指定してpublish メッセージが送信された場合、サーバ間のサブスクライブのQoS =2の設定、及びサブスクライバであるクライアント装置2からの指定トピックについてのQoS の指定に拘わらず、このメッセージの経路である全てのセッションにてQoS が「0(ゼロ)」に調停される。この場合、送信されたpublish メッセージに基づき、ブローカであるサーバ装置1はこのメッセージを指定トピックとしてサブクライブしているクライアント装置2又は他のサーバ装置1へ各1回送信するのみである。ブローカ間でも図3Aに示したpublish メッセージの送信のみが行なわれ、pubackメッセージ、pubrec/pubrel/pubcompメッセージのやり取りは行なわれない。
サブスクライバであるクライアント装置2が、指定トピックについてQoS として「0(ゼロ)」を指定した場合、ブローカであるサーバ装置1から当該クライアント装置2へのメッセージのQoS は「0(ゼロ)」である。当該クライアント装置2へメッセージを送信するサーバ装置1は、該クライアント装置2が指定したトピックのpublish メッセージをパブリッシャ又は他のサーバ装置1から受信する都度、publish メッセージを該クライアント装置2へ向けて1回のみ送信して送受信処理を終了する。なおこの場合、パブリッシャであるクライアント装置2と該クライアント装置2が通信接続しているブローカとの間のメッセージの送受信、及び、ブローカ間のメッセージの送受信は、パブリッシャから指定されているQoS (1 or 2)に基づき行なわれる。
(2)QoS =1、ブローカダウン保証外の動作
ブローカがダウンした場合にメッセージの到達を保証しないという前提において、パブリッシャであるクライアント装置2から、QoS =1を指定してpublish メッセージが送信される場合の処理について説明する。なお以下の説明では、当該メッセージのトピックを指定しているサブスクライバであるクライアント装置2が、トピック指定時にQoS として「1」以上を指定している場合の当該サブスクライバまでのメッセージの到達について説明する。サーバ間のサブスクライブのQoS =2の設定、及びサブスクライバであるクライアント装置2からの指定トピックについてのQoS が「1」以上であるケースでは、それらのQoS の指定に拘わらず、このQoS =1のメッセージの経路である全てのセッションにてQoS が「1」に調停される。トピック指定時に「0(ゼロ)」を指定しているサブスクライバへのメッセージ送信は(1)で述べたようにpublish メッセージを1回送信するのみで処理が終了するので説明を省略する。
(2.1)正常運用時
まず、QoS =1のメッセージに対する各サーバ装置1における処理の順序性について述べる。サーバ装置1は、第1記憶部11に記憶しているサーバプログラム1Pに基づき、パブリッシャであるクライアント装置2からメッセージの送信を受けた場合、指定されたQoS に応じてパブリッシャへ応答(pubackメッセージ)を返す。この応答のタイミングはMQTTモデルであれば、セッション毎に順序が守られればよい(図3参照)。これに対し通信システム100におけるサーバ装置1は、パブリッシャから送信されたpublish メッセージに基づきサブスクライバであるクライアント装置2又は他のブローカであるサーバ装置1との間のメッセージ送受信タイミングに対する順序性を持たせてパブリッシャへの応答を返す。
図20は、ブローカであるサーバ装置1によるメッセージ配信の処理手順の一例を示すフローチャートである。なお図20のフローチャートに示す処理手順は、図4のフローチャートに示した手順の内のステップS9の詳細に対応する。
サーバ装置1の制御部10は、パブリッシャとして通信接続を確立している1又は複数のクライアント装置2から、又は他のサーバ装置1からpublish メッセージを受信したか否かを判断する(ステップS201)。受信していないと判断された場合(S201:NО)、制御部10は処理をステップS201へ戻す。
制御部10は、受信したと判断した場合(S201:YES)、受信したpublish メッセージのトピックを抽出し(ステップS202)、抽出されたトピックを指定してサブスクライブしている他の装置に、他のサーバ装置1が含まれているか否かを判断する(ステップS203)。
ステップS203にて他のサーバ装置1は含まれていないと判断された場合(S203:NO)、制御部10は、自身に通信接続しており、抽出されたトピックを指定しているサブスクライバであるクライアント装置2へ向けてステップS201で受信したpublish メッセージを送信する(ステップS204)。なおステップS204において制御部10は、送信先に、keep接続を選択しており且つセッションが切断中であるクライアント装置2が存在する場合には、送信先をデータベース3とする。続いて制御部10は、受信したpublish メッセージの送信元(パブリッシャ又は他のサーバ装置1)へpubackメッセージを返し(ステップS205)、publish メッセージの配信処理を終了する。ステップS204において、抽出されたトピックを指定していたサブスクライバが通信接続を切断しているなどして、データベース3に書き込む場合には、データベース3への書き込みが行なわれる。
他のサーバ装置1が含まれていると判断された場合(S203:YES)、制御部10は、抽出されたトピックを指定しているサブスクライバであるクライアント装置2及び他のサーバ装置1へステップS201で受信したpublish メッセージを送信する(ステップS206)。ステップS206においてもデータベース3が配信先となる場合には送信に代替してデータベース3への書き込みが行なわれる。
制御部10は、ステップS206のpublish メッセージの送信先の内、他のサーバ装置1全てからpubackメッセージを受信したか否かを判断する(ステップS207)。実行先のサーバ装置1全てからpubackメッセージを受信しないと判断された場合(S207:NO)、制御部10は受信するまでpubackメッセージの送信は待機する。
ステップS207にて実行先のサーバ装置1全てからpubackメッセージを受信したと判断された場合(S207:YES)、制御部10はステップS201で受信したメッセージの送信元のパブリッシャ又は他のサーバ装置1へpubackメッセージを返し(ステップS208)、publish メッセージの配信処理を終了する。
図20のフローチャートに示した手順にて注目すべきは、抽出されたトピックについてpublish メッセージを送信する際に、送信先に当該トピックをサブスクライブしている他のサーバ装置1が1又は複数存在する場合には(S203:YES)、その他のサーバ装置1全てからpubackメッセージを受信するまでは(S207:YES)、メッセージの送信元のパブリッシャ又は他のサーバ装置1へpubackメッセージを返さない点である。送信先に他のサーバ装置1が含まれない場合、ステップS205に示したように直ちにpubackメッセージを送信することと異なり、この点によって順序性が持たれる。これにより、クライアント装置2へは送信処理が完了したことが保証され、他のサーバ装置1を経由する場合でもその先のクライアント装置2への送信処理が完了したことが保証される。
なお、他のサーバ装置1全てからpubackメッセージを受信するまでは(S207:YES)、メッセージの送信元のパブリッシャ又は他のサーバ装置1へpubackメッセージを返さないという制御については、各サーバ装置1に複数のクライアント装置2が通信接続しており、そして多数のトピックについて多数のメッセージが前後して送受信されることを鑑みると具体的には以下のように行なうことが好ましい。制御部10は、publish メッセージを受信すると、この1つのメッセージに対応するカウント数を初期化し、この1つのメッセージのトピックを指定トピックとするクライアント装置2及びサーバ装置1への送信処理を通信部14により実行し、送信処理の都度、カウント数を増大させる。そして、クライアント装置2へ送信する場合にはpublish メッセージの送信処理(ソケットへの書き込み)の完了が検知された時点で対象のカウント数を減少させ、データベース3に書き込む場合には書き込みの完了が検知された時点で対象のカウント数を減少させる。複数のクライアント装置2へのpublish メッセージを送信する場合、各々へのソケット書き込みの都度増大したカウント数は、全てのクライアント装置2への送信完了が検知されると、増大した分だけ減少している。送信先に他のサーバ装置1が含まれない場合、全てのクライアント装置2への送信完了が検知されて、カウント数が初期値となった時点で該1つのメッセージの送信元へpubackメッセージが送信される。他のサーバ装置1が含まれる場合、他のサーバ装置1への送信処理について完了した場合には、カウント数は増大したままである。他のサーバ装置1からのpubackメッセージの受信が検知できたタイミングで制御部10は、該1つのメッセージに対応するカウント数を減少させ、他のサーバ装置1全てからpubackメッセージを受信したことでカウント数が初期値になった時点で該1つのメッセージの送信元へpubackメッセージを送信する。
図20のフローチャートに示した手順について具体的に説明する。図21は送信順序を示す説明図である。図21の説明図では、パブリッシャであるクライアント装置2と該パブリッシャから送信されるメッセージのトピックを指定トピックとしているサブスクライバであるクライアント装置2との間に、1つのブローカのみが介在する例を挙げて説明している。図21の説明図では各メッセージの表記に対し、その順序を示す数値を付している。数値が小さいほど時間的に先に実行されるものであり、同一のものは同時でもよいし前後を問わないことを意味している。図21に示す例では具体的には、最初((10)のタイミング)に、クライアント装置2(p1)からpublish メッセージが送信される。これに応じてサーバ装置1は、このメッセージのトピック「t1」を指定トピックとしたサブスクライバであるクライアント装置2(s1)へメッセージの送信タイミング(20)よりも後の(30)のタイミングに、クライアント装置2(p1)へpubackメッセージを返す。クライアント装置2(s1)から、pubackメッセージが返されるか否かはクライアント装置2の設計次第であって不明であるから、サーバ装置1(b1)はこれを待つことなくpubackメッセージをパブリッシャであるクライアント装置2(p1)へ返している。
また、パブリッシャであるクライアント装置2と通信接続しているサーバ装置1は、自身に他のブローカであるサーバ装置1が接続している場合、前記パブリッシャが送信するpublish メッセージのトピックを指定する他のサーバ装置1へメッセージを送信する。そして通信システム100におけるサーバ装置1は、他のサーバ装置1がpubackメッセージを返してくるのを待ってから、パブリッシャへpubackメッセージを返す。他のサーバ装置1(1又は複数)は、夫々に接続しているサブスクライバであるクライアント装置2へ向けて、対応するpublish メッセージを送信した後にpubackメッセージを返してくる。なお通信システム100においてサーバ装置1間の接続は全て、上述したようにkeep接続である。
図22は送信順序の他の例を示す説明図である。図22の説明図では、パブリッシャであるクライアント装置2(p1)と該パブリッシャから送信されるメッセージのトピックを指定トピックとしているサブスクライバであるクライアント装置2(s1)との間に、2つのブローカが介在する例を挙げて説明している。図22の説明図では各メッセージに、順序を示す数値を付している。数値が小さいほど時間的に先に実行されるものであり、同一のものは同時でもよいし前後を問わないことを意味している。
図22に示す例では具体的には、最初のタイミング(10)に、クライアント装置2(p1)からQoS =1を指定してpublish メッセージが送信される場合について説明する。サーバ装置1(b1)は、クライアント装置2(p1)から送信されたpublish メッセージを、自身に接続している他のサーバ装置1(b2及びb3)へ、(20)のタイミングで送信する。他のサーバ装置1、例えばサーバ装置1(b2)は、サーバ装置1(b1)から送信されたpublish メッセージを受信すると、そのトピック「t1」を指定トピックとしたサブスクライバであるクライアント装置2(s1)へpublish メッセージをタイミング(30)に送信してから、サーバ装置1(b1)へタイミング(40)でpubackメッセージを返す。クライアント装置2(s1)から、(40)のタイミングでpubackメッセージが返されるか否かはクライアント装置2の設計次第であって不明であるから、サーバ装置1(b2)はこれを待つことなくpubackメッセージを返している。サーバ装置1(b1)は、トピック「t1」のメッセージを送信したサーバ装置1(b2及びb3)のいずれからも(40)のタイミング前後でpubackメッセージが返されてきたか否かを判断する。サーバ装置1(b1)は、トピック「t1」についてのメッセージの送信先である全てのサーバ装置1(b2及びb3)からpubackメッセージが返されたことを確認した場合に、パブリッシャであるクライアント装置2(p1)へ、(50)のタイミングでpubackメッセージを返す。これにより、パブリッシャであるクライアント装置2(p1)は、(50)のタイミングでpubackメッセージをサーバ装置1(b1)から受信できたことで、これを指定トピックとするサブスクライバであるクライアント装置2へのpublish メッセージが到達したこと(受信確認ではない)を認識することができる。この意味で、通信システム100では、セッション毎の到達保証のみならず、サブスクライバまでのメッセージの到達をQoS =1で保証することが可能になる。
(2.2)切断発生時
ブローカがダウンした場合は保証しないという前提で、QoS =1が指定されたpublish メッセージが送信され、全てのセッションにてQoS が「1」に調停されるケースにおける切断時の処理について切断箇所毎に説明する。図23は、サーバ装置1及びクライアント装置2の接続構成を示す図である。図23は、パブリッシャであるクライアント装置2(p1)と該パブリッシャから送信されるメッセージのトピックをQoS =1で指定トピックとしているサブスクライバであるクライアント装置2(s1)との間に、2つのブローカが介在する場合の接続構成を示している。図23の接続構成では、パブリッシャであるクライアント装置2(p1)は、ブローカであるサーバ装置1(b1)に通信接続している(セッションE)。サブスクライバであるクライアント装置2(s1)はもう1つのブローカであるサーバ装置1(b2)に通信接続している(セッションF)。2つのブローカ間も通信接続されている(セッションG)。
(2.2.1)パブリッシャ・ブローカ間
図23中のセッションEが切断された場合の到達保証について説明する。パブリッシャであるクライアント装置2から、QoS =1が指定されたpublish メッセージが送信された場合におけるパブリッシャとブローカとの間(セッションE)の通信の切断については、パブリッシャであるクライアント装置2(p1)からpublish メッセージが送信された後に切断されるケースを考える。
このケースでは、パブリッシャであるクライアント装置2(p1)は、送信したpublish メッセージに対するpubackメッセージが返されるまで、そのpublish メッセージを送信バッファに一時記憶したままとする(図3)。なおサーバ装置1(b1)は、切断される前に受信したpublish メッセージについて、他のサーバ装置1(b2)へのpublish メッセージの送信を完了し、(40)のタイミングにて他のサーバ装置1(b2)からpubackメッセージを受信し、pubackメッセージを送信しようとしていた可能性がある。しかしながらサーバ装置1(b1)は、セッションEが切断されているのでこのpubackメッセージを送信できない。
クライアント装置2(p1)は、ブローカであるサーバ装置1(ここではb1、他のブローカでもよい)へ通信接続のリクエストを実行する。リクエストに応じてセッションEが確立するとクライアント装置2(p1)は、送信バッファに一時記憶しているpublish メッセージを新たなセッションにおいて接続先のサーバ装置1(b1)へ送信する。接続先のサーバ装置1(b1)は、再接続してきたクライアント装置2から再送されたpublish メッセージについて、新たなpublish メッセージであるとして処理を行なう。この場合でもQoS =1の処理では問題なく到達保証が達成され、パブリッシャであるクライアント装置2(p1)ではサブスクライバであるクライアント装置2(s1)へメッセージが送信されたことを認識することができる。
(2.2.2)ブローカ・サブスクライバ間
図23中のセッションFが切断された場合の到達保証について説明する。セッションFが、サーバ装置1(b2)がクライアント装置2(s1)へ(30)のタイミングにてpublish メッセージを送信する前に切断された場合、keep接続の処理(図10から図12)により、再接続後にデータベース3から配信される。
図23中のセッションFが、クライアント装置2(s1)からサーバ装置1(b2)へ(40)のタイミングにてpubackメッセージを送信する前に切断された場合、データベース3(「keep_mqtt 」テーブル)の中途メッセージ情報を参照した処理(図15から図17)により、中断されたやり取りが再開され、メッセージのやり取りが完了する。
(2.2.3)ブローカ・ブローカ間
ブローカ間のセッションは上述したようにkeep接続が選択されている。図24は、ブローカ間が切断された場合のサーバ装置1における処理手順の一例を示すフローチャートである。なお図24のフローチャートに示す処理は基本的に、パブリッシャ側のサーバ装置1(即ち図3における送信者側)によって実行されるものである。サブスクライバ側のサーバ装置1の処理は、一部省略して実行される。
サーバ装置1の制御部10は、他のサーバ装置1とのセッション切断を検知すると(ステップS301)、他のサーバ装置1にサブスクライバとしてkeep接続しているクライアント装置2をデータベース3(「keep_sub」テーブル)のセッション情報から抽出する(ステップS302)。
制御部10は、抽出したクライアント装置2の状態情報を、自身に接続しているクライアント装置2として扱って一時記憶する(ステップS303)。ただしこのクライアント装置2についてはメッセージの配信先をデータベース3に設定する(keep接続後の切断状態と同様、図8参照)。そして制御部10は、図15Aのフローチャートに示した処理手順にしたがって、他のサーバ装置1(サブスクライバ側)向けのpublish メッセージが送信バッファに残存しているか否かを判断する(ステップS304)。残存していると判断された場合(S304:YES)、制御部10はこのpublish メッセージを、中途メッセージ情報としてでなく、本来であれば他のサーバ装置1とセッションを確立しているクライアント装置2へ送信されていたはずのメッセージとしてデータベース3に保存する(ステップS305)。送信バッファに残存していたpublish メッセージは消去される。制御部10は、メッセージをデータベース3に保存したことからpubackメッセージを元のpublish メッセージの送信元(パブリッシャ側)へ送信する(ステップS306)。このときデータベース3(「store 」テーブル)には、publish メッセージに含まれるペイロードが識別子と共に保存メッセージとして記憶される。そしてこの保存メッセージの配信先情報として、切断されている他のサーバ装置1を経由したサブスクライバへ送信すべきことを示す情報がデータベース3(「store_target_broker_user」テーブル)に記憶される。このブローカ経由の配信先情報には、情報の識別子(ID)、切断を検知したサーバ装置1の識別情報(broker_id )、切断されている他のサーバ装置1向けに送信した際に使用したパケットID(broker_pid)、送信先のクライアント装置2の識別情報(user_id )及び送信するはずだった保存メッセージの識別子(store_id)を含む。またブローカ経由の配信先情報には、後述のQoS =2の処理で用いられる再送時のパケットID(pid 、再送しているか否か)、及び再送先への送信が完了したか(already_sent他のサーバ装置1からpubrecメッセージを受信しているか)の情報が含まれる。なおテーブル名は例示であることは勿論である。
ステップS304で残存していないと判断された場合(S304:NO)、publish メッセージに対するpubackメッセージを受信済み、そして元のpublish メッセージの送信元(パブリッシャ側)へpubackを送信済みであるので、そのまま処理を次のステップS307へ進める。
サーバ装置1の制御部10は、該他のサーバ装置1とのセッションを再び確立すると(ステップS307)、「(1.3.)ブローカ間の通信接続」で述べたようにブローカ間の同期処理を実行する(ステップS308)。なお、切断が検知されてから再度セッションが確立するまでの期間は大抵10秒以内、例えば3から5秒である。なお制御部10は、再確立されたブローカ間のセッションはすべて新規のものとして確立され、切断前のセッションにおいて採番していたパケットID等は全てリフレッシュされる。
サーバ装置1の制御部10は、自身に接続しているとして一時記憶しているサブスクライバであるクライアント装置2の識別情報と、データベース3に記憶されている各クライアント装置2の接続先の情報(「connections 」)とを照合する(ステップS309)。なお接続先の情報(「connections 」)はサーバ装置1がクライアント装置2とセッションを確立する毎に記憶する情報であって、クライアント装置2(サブスクライバ及びパブリッシャ両方)がいずれのサーバ装置1に通信接続しているかを記憶した情報である。keep接続しているクライアント装置2についての接続先の情報は切断されても、非keep接続がされるまでデータベース3に保持される。なお通信接続先が変更となった場合は、接続先のサーバ装置1の識別情報で上書きされる。
サーバ装置1の制御部10は、ステップS308の照合の結果、自身に通信接続しており状態情報がonlineであるクライアント装置2(複数存在する場合は夫々)について、データベース3に記憶されている接続先の情報に基づき、接続先が自身であるか否かを判断する(ステップS310)。
自身でないと判断された場合(S310:NO)、制御部10は、自身に接続しているクライアント装置2の情報の内、対象のサブスクライバであるクライアント装置2の情報を削除し(ステップS311)、再開時の処理を終了する。
ステップS310で自身であると判断された場合(S310:YES)、制御部10はステップS304で残存していると判断されていたか否かを判断する(ステップS312)。残存していると判断されていた場合(S312:YES)、制御部10はステップS305にて送信されていたはずの保存メッセージを読み出し(ステップS313)、サブスクライバであるクライアント装置2へ送信する(ステップS314)。制御部10は、その後送信先のクライアント装置2からpubackメッセージを受信し(ステップS315)、配信先情報及び保存メッセージを削除する(ステップS316)。ステップS312で残存していると判断されていなかった場合(S312:NO)、制御部10はそのまま、セッションの再確立時のメッセージの処理を終了する。
サブスクライブ側のサーバ装置1では、ステップS302、S303は省略して実行される。
図24のフローチャートに示した処理について、具体的に説明する。図25から図27は、図23に示した接続構成におけるブローカ間のセッションGが切断された場合の処理の例を示す説明図である。図25には、セッションGが切断された場合にデータベース3に記憶される情報の内容例を示している。サーバ装置1(b1)は、タイミング(10)におけるパブリッシャからのメッセージに基づき(20)のタイミングで、サーバ装置1(b2)へ向けてpublish メッセージを送信する。サーバ装置1(b1)は、送信先のサーバ装置1(b2)とのセッションの切断を検知する(S301)。サーバ装置1(b1)は、切断されたセッションの接続先のサーバ装置1(b2)にサブスクライバとして通信接続されているはずのクライアント装置2(s1)の識別情報をデータベース3(「keep_sub」テーブル)から抽出する(S302)。サーバ装置1(b1)は、クライアント装置2の識別情報「s1」の状態情報を、配信先をデータベース3に指定して一時記憶する(S303)。(20)のタイミングで送信したpublish メッセージは、pubackメッセージを受信できていないために送信バッファに残存しており(S304:YES)、サーバ装置1(b1)は残存しているpublish メッセージを読み出し、サーバ装置1(b2)から送信されていたはずのメッセージ(保存メッセージ及びブローカ経由の配信先情報)としてデータベース3(「store 」テーブル及び「store_target_broker_user」テーブル)に記憶する(S305)。図25の例では、識別子「345 」の保存メッセージと、この保存メッセージの識別子「345 」を含むブローカ経由の配信先情報(broker_id=b1, broker_pid=0x123, user_id=s1, pid=NULL, store_id=345, already_sent=false)が記憶されている。そしてサーバ装置(b1)は、publish メッセージをデータベース3に保存したので、(30)のタイミングでパブリッシャであるクライアント装置(p1)へpubackメッセージを送信している。これによりサーバ装置1(b1)では、全てのサーバ装置1経由でメッセージを送信できたことを保証した上でパブリッシャであるクライアント装置2へpubackメッセージを返すことができる。
なおこのとき、クライアント装置2(s1)が接続しているブローカであるサーバ装置1(b2)で、サーバ装置1(b1)からのpublish メッセージをセッションGの切断前に受信していれば、その後程なく、サーバ装置1(b2)はクライアント装置2(s1)へpublish メッセージを送信し、pubackメッセージを受信するなど処理を実行する。publish メッセージに対してpubackメッセージを送信できていないことについてはセッションの切断によってリフレッシュされるなどすればよい。
図26は、図25に示した状態から、セッションGが再確立された場合の例を示す。なお、図26の例では、サーバ装置1(b2)がセッションGの切断前にpublish メッセージを受信できていない場合、又はそのタイミングでセッションFについても切断しており、パブリッシャからのpublish メッセージが到達していない場合について説明する。サーバ装置1(b1, b2)間で同期処理が終了すると(S308)、サーバ装置1(b1)は、状態情報を記憶しているクライアント装置2(s1)の識別情報「s1」と、データベース3に記憶されている各クライアント装置2の接続先の情報(「connections 」)における識別情報「s1」とを照合する(S309)。サーバ装置1(b1)は、クライアント装置2(s1)について、接続先情報では自身が接続先ではないので(S310:NO)、クライアント装置2(s1)についての状態情報を削除する(S311)。
サーバ装置1(b2)側でも、サーバ装置1(b1)とのセッションを再確立すると(S307)、同期処理を行なう(S308)。サーバ装置1(b2)は、状態情報を記憶しているクライアント装置2(s1)の識別情報「s1」と、データベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)における識別情報「s1」とを照合する(S309)。サーバ装置1(b2)は、クライアント装置2(s1)について自身が接続先であると判断する(S310:YES)。サーバ装置1(b2)は、データベース3(「store 」及び「store_target_broker_user」テーブル)に記憶されている保存メッセージ及びブローカ経由の配信先情報に基づきpublish メッセージを読み出し(S313)パケットIDを採番して例えば(50)のタイミングでクライアント装置2(s1)へ送信する(S314)。その後(60)のタイミングでクライアント装置2(s1)から返されるpubackメッセージをサーバ装置(b2)が受信することで(S315)、保存メッセージ及び配信先情報は削除される(S316)。これにより、ブローカ・ブローカ間が切断されたとしてもサブスクライバ側へのQoS =1(「At least One」)でのメッセージの到達を達成できる。仮に、セッションGが切断されたときにサーバ装置1(b2)側でpublish メッセージを受信できていて、これをサブスクライバであるクライアント装置2(s1)に送信済みであった場合、ブローカ・ブローカ間の切断によって保存された保存メッセージ及び配信先情報に基づいて別途新たなパケットIDで同一の内容のpublish メッセージが送信されることになる。しかしながら、QoS =1は最低1回受信であるから問題はない。
図27は、ブローカ間のセッションGが再確立された後の処理の他の例を示す説明図である。図27は、図25に示した状態から、セッションGが再確立されるがその前に、サーバ装置1(b2)とセッションを確立させていたサブスクライバであるクライアント装置2(s1)が、セッションGの切断中にサーバ装置1(b1)へ接続先を変更する事態が発生した場合の例を示す。図27において、クライアント装置2(s1)がサーバ装置1(b1)へセッション確立をリクエストし、これが承諾されるとサーバ装置1(b1)がデータベース3における接続先情報を識別情報「b1」に書き換える。この後同期処理が実行され、サーバ装置1(b1及びb2)間で接続情報が共有される。この場合、サーバ装置1(b1)は、状態情報を記憶しているクライアント装置2の識別情報「s1」と、データベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)における識別情報「s1」とを照合し(S309)、接続先情報でも自身が接続先であると判断する(S310:YES)。サーバ装置1(b1)は、例えば(50)のタイミングでデータベース3(「store 」及び「store_target_broker_user」テーブル)に記憶されているサーバ装置1(b2)から送信されるはずであったpublish メッセージを読み出し(S313)、新たなパケットIDでクライアント装置2(s1)へpublish メッセージを送信する(S314)。データベース3に記憶されていた保存メッセージ及び配信先情報は、(60)のタイミングでクライアント装置2(s1)から送信されたpubackメッセージをサーバ装置1(b1)が受信することで(S315)、削除される(S316)。
図27で示す例においてサーバ装置1(b2)側では、サーバ装置1(b1)とのセッションを再確立すると(S307)、同期処理を行なう(S308)。サーバ装置1(b2)は、状態情報とデータベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)における識別情報「s1」を照合し(S309)、自身が接続先でないと判断する(S310:NO)。サーバ装置1(b2)は、クライアント装置2(s1)についての状態情報を削除する(S311)。クライアント装置2(s1)向けの処理は上述のようにサーバ装置1(b1)側に任される。
このように、MQTTモデルにおける到達保証のメッセージのやり取りの途中でブローカ間のセッションが切断された場合であっても、パブリッシャであるクライアント装置2からサブスクライバであるクライアント装置2までの経路におけるメッセージの到達保証をQoS =1とすることができる。
次に図24のフローチャートにおけるステップS305及びステップS306の間、セッションを再確立する間に新たにパブリッシャ又はパブリッシャ側の他のサーバ装置1からpublish メッセージを受信した場合の処理について説明する。図28は、ブローカ間切断中のメッセージ処理手順の一例を示すフローチャートである。なお図28のフローチャートに示す処理手順の内、図20のフローチャートと共通する手順については同一のステップ番号を付して詳細な説明を省略する。
ブローカであるサーバ装置1の制御部10は、publish メッセージを受信して(S201)、このメッセージを他のサーバ装置1へ送信すると判断した場合(S203:YES)、送信先のサーバ装置1のいずれかとの間のセッションが切断しているか否かを判断する(ステップS211)。セッションが切断していないと判断された場合(S211)、制御部10は他のサーバ装置1へpublish メッセージを送信し(S206)、他のサーバ装置1全てからpubackメッセージを受信したと判断してから(S207:YES)、送信元へpubackメッセージを返す(S208)。
ステップS211にてセッションが切断していると判断した場合(S211:YES)、制御部10は相手のサーバ装置1を通信接続先とするサブスクライバであるクライアント装置2についてのセッション情報をデータベース3(「keep_sub」テーブル)から参照する(ステップS212)。制御部10は参照したセッション情報に基づき、抽出して記憶しているサブスクライバの状態情報を更新する(ステップS213)。例えば、図24のフローチャートにおけるステップS303で記憶していたサブスクライバが、切断中にサブスクライブを停止していた場合には、これを反映し、以後のpublish メッセージの配信先から除外してもよくなる。制御部10は、更新した状態情報に基づき、配信先をデータベース3としているサブスクライバであるクライアント装置2に関し、ステップS201で受信したpublish メッセージについてデータベース3(「store 」及び「store_target」テーブル)に保存メッセージ及び配信先情報を記憶する(ステップ214)。そして制御部10は、切断中のメッセージの処理を終了する。
切断から復帰した場合には、図24のフローチャートのステップS310以降で、サブスクライバの接続先に応じて、いずれかのサーバ装置1が、データベース3からpublish メッセージを配信すればよい。
図28のフローチャートに示したように、サーバ装置1の制御部10は、切断中(大抵の場合3秒から5秒の間)、publish メッセージを受信する都度、その間における各クライアント装置2の接続先の情報を自身が一時的に記憶している状態情報を適応させる。切断されたセッションの相手であるサーバ装置1を通信接続先とするサブスクライバのクライアント装置2がその切断中に、トピックのサブスクライブを止めたり(unsubscribe )、新たにサブスクライブしたり、他のトピックをサブスクライブしたりした場合にも、状態情報を適応させて間違いなくメッセージを送信することが可能になる。
ブローカのダウンを保証外とする場合、データベース3への情報の記憶は最低限としてあるから、QoS =1を保証しつつも送受信の速度が低減することが回避される。その代わり、ブローカであるサーバ装置1はいずれもダウンした場合には、自身に接続しているクライアント装置2の状態情報(online又はdatabase等)の一時記憶を全て失う。ブローカ間のセッションは起動時に新規に確立されるので、セッションに対応して記憶されている情報もダウン時に全て失われることになる。ステップS309等の照合ができないから、QoS =1のメッセージは失われることになる。
(3)QoS =1、ブローカダウン保証
ブローカがダウンした場合もメッセージの到達を保証するという前提において、(2)同様に、経路である全てのセッションにてQoS が「1」に調停されるQoS =1が指定されたpublish メッセージのサブスクライバまでの到達について説明する。つまり(2)同様に、サブスクライバであるクライアント装置2が当該トピックを、QoS =1又は=2で指定している状態で、当該トピックについてパブリッシャがQoS =1を指定してpublish メッセージを送信するケースである。このメッセージについてトピック指定時に「0」を指定しているサブスクライバへの送信する場合の処理は(1)で述べたので説明を省略する。
(3.1)正常運用時
ブローカがダウンした場合にメッセージの到達を保証する場合、ダウンしたことを自身で検知できないので、ダウンした場合の処理に切り替えるといったことができない。したがってダウン時に到達を保証するか否かは、ブローカ(サーバ装置1)のインスタンスが生成された時点で選択される。そしてダウンした場合にも到達保証を行なうことを選択して起動したブローカであるサーバ装置1は基本的に、自身にkeep接続しているクライアント装置2が1つでも存在する限り、パブリッシャであるクライアント装置又は他のサーバ装置1からpublish メッセージを受信する都度、データベース3(「store」及び「store_target」テーブル)に保存メッセージ及び配信先情報を保存する。そしてサーバ装置1は、publish メッセージに対するpubackメッセージを受信する都度、それらの保存メッセージ及び配信先情報を更新又は削除する処理を実行する(図7から図12参照)。サーバ装置1は、自身にサブスクライバであるクライアント装置2が通信接続している場合には、publish メッセージを送信してからパブリッシャであるクライアント装置2側へpubackメッセージを送信する順序性を守る。同様にしてサーバ装置1は、他のサーバ装置1へ向けてpublish メッセージを送信する場合には、他のサーバ装置1全てからpubackメッセージを受信してからパブリッシャであるクライアント装置2側へpubackメッセージを送信する順序性を守る(図20から図22参照)。
図29は、ブローカダウンを保証するサーバ装置1における送信手順の一例を示すフローチャートである。なお図29のフローチャートに示す処理手順は、図4のフローチャートに示した手順の内のステップS9の詳細に対応する。また図29のフローチャートに示す処理手順の内、ブローカダウンを保証外とする際の図20のフローチャートに示した処理手順と共通する手順については同一のステップ番号を付して詳細な説明を省略する。
サーバ装置1の制御部10は、ステップS201でpublish メッセージを受信した場合(S201:YES)、且つ、送信先に他のサーバ装置1が含まれないと判断された場合(SS203:NO)、ステップS202で抽出したトピックについての送信先に、keep接続を選択して通信接続しているサブスクライバであるクライアント装置2が存在するか否かを判断する(ステップS221)。keep接続を選択しているクライアント装置2が存在しないと判断された場合(S221:NO)、サーバ装置1の制御部10は、自身に通信接続しているクライアント装置2へpublish メッセージを送信し(S204)、送信元へpubackメッセージを返す(S205)。ステップS221にて、keep接続を選択しているクライアント装置2が存在すると判断された場合(S221:YES)、セッションの切断が発生しているか否かに拘わらず、制御部10は、publish メッセージ及びkeep接続である配信先の情報を保存メッセージ及び配信先情報としてデータベース3(「store 」及び「store_target」テーブル)に記憶してから(ステップS222)、対象となるクライアント装置2へpublish メッセージを送信する(S204)。
そしてサーバ装置1の制御部10は、pubackメッセージをpublish メッセージの送信元側へ送信した後(S205)、制御部10は再度、ステップS221にて存在すると判断したか否かを判断する(ステップS223)。存在すると判断していないと判断された場合(S223:NO)、制御部10は、そのまま1回のpublish メッセージの受信処理を終了する。
ステップS223にて存在すると判断されていた場合(S223:YES)、制御部10は、その存在するクライアント装置2、即ち抽出されたトピックを指定して自身にkeep接続しているクライアント装置2からpubackメッセージを受信したか否かを判断する(ステップS224)。受信していないと判断された場合(S224:NO)、制御部10は受信したと判断するまでは、次のステップS225の処理は行なわない。pubackメッセージを受信したと判断された場合(S224:YES)、制御部10は、ステップS222で記憶したpublish メッセージ及びkeep接続の送信先の情報をデータベース3から削除し(ステップS225)、publish メッセージの受信処理を終了する。
ステップS203にて他のサーバ装置1が含まれると判断された場合(S203:YES)、制御部10は、データベース3で共有しているセッション情報(「keep_sub」)から、ステップS202で抽出したトピックについて送信先の他のサーバ装置1からの送信先にkeep接続を選択して通信接続しているサブスクライバが存在するか否かを判断する(ステップS226)。ステップS226にて存在しないと判断された場合(S226:NO)、制御部10はそのままpublish メッセージを他のサーバ装置1へ送信する(S206)。この場合制御部10は、当該トピックをサブスクライブしている他のサーバ装置1全てからpubackメッセージを受信してから(S207:YES)、送信元へ向けてpubackメッセージを送信し(S208)、publish メッセージの受信処理を終了する。
ステップS226にて存在すると判断された場合(S226:YES)、セッションの切断が発生しているか否かに拘わらず、制御部10は、publish メッセージ(保存メッセージ)及びkeep接続の配信先情報をデータベース3(「store 」及び「store_target_broker 」テーブル)に記憶してから(ステップS227)、他のサーバ装置1へpublish メッセージを送信する(S206)。
サーバ装置1の制御部10は、当該トピックをサブスクライブしている他のサーバ装置1全てからpubackメッセージを受信してから(S207:YES)、送信元へ向けてpubackメッセージを送信した後(S208)、制御部10は再度、ステップS226にて、keep接続を選択して通信接続しているサブスクライバであるクライアント装置2が存在すると判断したか否かを判断する(ステップS228)。存在しないと判断された場合(S228:NO)、制御部10は、そのまま1回のpublish メッセージの受信処理を終了する。
ステップS228にて存在すると判断された場合(S228:YES)、ステップS227で記憶したpublish メッセージ及びkeep接続の送信先の情報(保存メッセージ及び配信先情報)をデータベース3から削除し(ステップS229)、publish メッセージの受信処理を終了する。
図29のフローチャートに示した処理について、図面を参照して具体的に説明する。図30から図33は、QoS =1でブローカダウンを保証する際の処理を示す図である。図30は、パブリッシャであるクライアント装置2(p1)、及び、サブスクライバであるクライアント装置2(s1, s2)と夫々セッションA,B,Cを確立しているサーバ装置1(b1)における処理を示している。サーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からトピック「t1」について(10)のタイミングでpublish メッセージを受信すると(S201:YES)、トピック「t1」を指定してkeep接続を選択して通信接続しているクライアント装置2(s1)へ受信したpublish メッセージを(20)のタイミングで送信する(S204)。サーバ装置1(b1)はその前に、データベース3(「store 」及び「store_target」テーブル)に、メッセージの内容「a 」を含む保存メッセージと、識別情報「s1」を配信先とする配信先情報とを、publish メッセージを送信する際に採番したパケットIDと共に記憶する(S222)。サーバ装置1は、トピック「t1」のpublish メッセージについて、クライアント装置2(s2)もトピック「t1」を指定しているので(20)のタイミングで送信するが(S204)、クライアント装置2(s2)はkeep接続を選択していないので、識別情報「s2」の配信先情報はデータベース3に記憶されない。
図31は、図30の状態よりも時間が経過した後の処理を示している。まずサーバ装置1は、クライアント装置2(s1, s2)へpublish メッセージを送信したことで次のタイミング(30)でパブリッシャであるクライアント装置2(p1)へpubackメッセージを送信する。これに前後して(例えばタイミング(35)にて)クライアント装置2(s1)からpubackメッセージが送信された場合、サーバ装置1は、パケットID及びpubackメッセージの送信元をキーとしてデータベース3(「store_target」テーブル)から配信先情報を検索する。keep接続を選択していないクライアント装置2(s2)についての検索結果はゼロ(空)であるが、keep接続を選択しているクライアント装置2(s1)については図31に示すように検索される。サーバ装置1(b1)は、このpubackメッセージの受信を機に、レコードを削除する(S225)。サーバ装置1(b1)は、同一の保存メッセージ(「store 」テーブルにおける識別子:123 の情報)について配信先情報が空になったと判断された場合、参照されなくなった保存メッセージとしてこれをデータベース3(「store 」テーブル)から削除する(S225)。
図32は、トピック「t1」についてのパブリッシャであるクライアント装置2(p1)とセッションEを確立しているブローカであるサーバ装置1(b1)における処理を示している。サーバ装置1(b1)は、トピック「t1」を指定トピックとするサブスクライバであるクライアント装置2(s1)が接続している他のサーバ装置1(b2)とメッセージを仲介する。サーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からトピック「t1」について(10)のタイミングでpublish メッセージを受信する(S201:YES)。この場合、サーバ装置1(b1)は、サーバ装置1(b2)に対し、トピック「t1」を指定してkeep接続を選択して通信接続しているクライアント装置2(s1)が存在していると判断する(S226:YES)。サーバ装置1(b1)は、パブリッシャから受信したpublish メッセージを(20)のタイミングで送信するが(S206)、その前に、データベース3(「store 」及び「store_target_broker 」テーブル)へ、保存メッセージ及び配信先情報を記憶する(S227)。図32例では、識別子「567 」の保存メッセージと、この保存メッセージの識別子「567 」と、送信時に使用されたパケットID「0x123 」を含むブローカ間の配信先情報(source_id=b1, target_id=b2, packet_id=0x123, store_id=567, already_sent=false )が記憶されている。
図33は、図32の状態よりも時間が経過した後の処理を示している。サーバ装置1(b2)は、サーバ装置1(b1)から送信されたpublish メッセージを、サブスクライバであるクライアント装置2(s1)へ送信したことで次のタイミング(40)にpubackメッセージを送信する。クライアント装置2(s1)から(45)のタイミングでpubackメッセージが送信されたとしてもこれを待つことなくサーバ装置1(b2)からpubackメッセージが送信される。サーバ装置1(b1)は、他のサーバ装置1全て(b2)からのpubackメッセージを受信すると(S207:YES)、パブリッシャであるクライアント装置2(p1)へ、例えば(50)のタイミングでpubackメッセージを送信する(S208)。サーバ装置1(b1)は、サーバ装置1(b2)からpubackメッセージを受信した場合、パケットID及びpubackメッセージの送信元(target_id=b2)をキーとしてデータベース3(「store_target_broker 」テーブル)から配信先情報を検索する。ステップS226にてkeep接続を選択して通信接続しているクライアント装置2(s1)が存在していると判断され(S228:YES)、配信先情報が検索されるはずであるから、サーバ装置1(b1)は、検索結果の配信先情報をデータベース3(「store_target_broker 」テーブル)から削除する(S229)。サーバ装置1(b1)は、同一の保存メッセージ(「store 」テーブルにおける識別子:567 )について配信先情報が空になったと判断された場合、参照されなくなった保存メッセージをデータベース3(「store 」テーブル)から削除する(S229)。
ブローカダウン時もメッセージの到達を保証することを選択して起動したブローカであるサーバ装置1(b1)は起動後、切断又はブローカダウンが発生していない間も図29から図33に示した処理を実行する。publish メッセージを受信する都度、データベース3への書き込みが実行され、pubackメッセージを受信する都度、削除が実行されるため、keep接続しているクライアント装置2が存在する場合にはメッセージの送受信にある程度の時間を要する。この点で、データベース3をKVS(Key-Value Store )で構成し、作成、更新及び削除を全てイベントとして記憶する処理とすることで、データベース3への処理に要する時間を可及的に削減することが可能になる。
(3.2)切断又はダウン発生時
セッションの切断が発生した場合は、サーバ装置1は夫々、その切断を検知することができ、図24のフローチャートに示した処理と同一の処理を実行する。なおQoS =1でブローカダウン時にもメッセージの到達を保証する場合、上述したようにkeep接続しているクライアント装置2について、各サーバ装置1は正常運用時もデータベース3への記憶及び削除を繰り返し実行している。切断の原因が他のサーバ装置1のブローカダウンである場合、ブローカダウン時もメッセージを保証するケースでは、ネットワークコントローラの送信バッファにメッセージが残存しているか否かではなく、データベース3(「store_target_broker 」テーブル)に削除されていない保存メッセージ及び配信先情報が残存しているか否かを判断する。つまりサーバ装置1は、図24のフローチャートにおけるステップS304において、送信バッファではなく、データベース3にメッセージが残存しているか否かを判断する。そして残存していると判断された場合(S304:YES)、制御部10は、データベース3に残存していたメッセージを、本来であれば他のサーバ装置1とセッションを確立しているクライアント装置2へ送信されていたはずのメッセージ(保存メッセージ及びブローカ経由の配信先情報)としてデータベース3(「store_target_broker_user」テーブル)に保存(移動)する(S305)。
ダウンしたブローカであるサーバ装置1は自身のダウンを検知することはできず、ネットワークコントローラの送信バッファにおける一時記憶情報も失われる。したがってダウンしたサーバ装置1は、図24のフローチャートにおけるステップS304及びステップS305で示したような残存メッセージの退避保存処理はできない。またダウンしたサーバ装置1は、ダウン中に図28のフローチャートにおけるステップS211からS214に示した切断中のメッセージの退避保存を行なうことはできない。したがって再起動したサーバ装置1は、他のサーバ装置1がデータベース3に記憶したメッセージを参照して、ダウン中に送信されたメッセージをクライアント装置2へ向けて送信する。
図34は、サーバ装置1の起動時の処理手順の一例を示すフローチャートである。サーバ装置1の制御部10は、起動するとクライアント装置2及び他のサーバ装置1夫々とセッションを確立し(ステップS401)、確立したセッションにて他のサーバ装置1と同期処理を実行する(ステップS402)。
サーバ装置1の制御部10は、自身に接続しているとして一時記憶しているサブスクライバであるクライアント装置2の識別情報と、データベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)とを照合する(ステップS403)。ステップS403の処理は、図24のフローチャートに示したステップS308の処理と同様である。
サーバ装置1の制御部10は、ステップS403の照合の結果、自身に通信接続しており、状態情報がonlineであるクライアント装置2(複数存在する場合は夫々)について、データベース3に記憶されている接続先の情報中に基づき、接続先が自身であるか否かを判断する(ステップS404)。
サーバ装置1の制御部10は、自身でない(S404:NO)、制御部10は、自身に接続しているクライアント装置2の状態情報の内、対象のサブスクライバであるクライアント装置2の情報を削除し(ステップS405)、起動時の処理を終了し、正常運用時の処理へ移行する(図4又は図20等参照)。
サーバ装置1の制御部10は、ステップS404で自身であると判断した場合(S404:YES)、通信接続しているクライアント装置2に対し、他のサーバ装置1により、自身を経由して送信されるメッセージであったことを示す情報(ブローカ経由の配信先情報)を、データベース3(「store_target_broker_user」テーブル)から抽出する(ステップS406)。更に制御部10は、通信接続しているサブスクライバであるクライアント装置2向けにデータベース3(「store 」及び「store_target」テーブル)に記憶しているメッセージを抽出する(ステップS407)。制御部10は、ステップS406及びS407で抽出した情報に基づくpublish メッセージを、記憶した時刻の順にクライアント装置2へ送信する(ステップS408)。その後制御部10は、送信先のクライアント装置2からpubackメッセージを受信し(ステップS409)、これを受信できた場合に、配信先情報、並びに保存してあったメッセージを削除する(ステップS410)。publish メッセージの送信により起動時の処理は終了する。なおステップS406及びS407で情報が抽出されない場合は勿論、ステップS408−S410の処理は実行されない。
図34のフローチャートに示した処理を、切断箇所別に説明する。
(3.2.1)パブリッシャ・ブローカ間
図23の説明図に示したパブリッシャからサブスクライバまでの間のメッセージを、2つのブローカが仲介する場合に、パブリッシャ寄りに存在するブローカであるサーバ装置1(b1)がダウンする場合におけるパブリッシャ・ブローカ間のセッションについて説明する。この場合は、パブリッシャであるクライアント装置2(p1)は、改めて通信接続したブローカであるサーバ装置1(b1)へ新たなパケットIDにてpublish メッセージを再送することでQoS =1が実現可能である。
なお、ブローカであるサーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からpublish メッセージが送信され、これをサーバ装置1(b2)へ送信する前に、データベース3(「store_target_broker 」テーブル)にそのメッセージを記憶している。このときサーバ装置1(b1)は、クライアント装置2(p1)からpublish メッセージを受信したときに使用されていたパケットIDをデータベース3にイベントログとして記憶しておき、図24及び図34のフローチャートに示した処理手順で再起動後にやり取りを継続してもよい。サーバ装置1(b1)が、他のサーバ装置1全て(b2)からpubackメッセージを受信する前にダウンした場合、ダウンしている間にサーバ装置1(b2)が切断を検知し、データベース3(「store_target_broker 」テーブル)に記憶してあった配信先情報を、自身(b1)を経由して送信されるメッセージであったことを示す情報としてデータベース3(「store_target_broker_user」テーブル)へ移動できる。このときサーバ装置1(b1)は、データベース3への移動を契機にパブリッシャであるクライアント装置2(p1)へ向けてpubackメッセージを送信する。再確立後、サーバ装置1(b2)は、データベース3(「store_target_broker_user」テーブル)に記憶してある自身(b2)から送信されるメッセージであることを示す情報に基づき、クライアント装置2(s1)向けのpublish メッセージの送信を実行する。
(3.2.2)ブローカ・サブスクライバ間
次に、サブスクライバ寄りに存在するブローカであるサーバ装置1(b2)がダウンするケースにおけるブローカ・サブスクライバ間のセッションについて説明する。図23の説明図に示したセッションFに対応する。図35は、ブローカであるサーバ装置1(b2)がダウンした場合の処理を示す図である。詳細には、サーバ装置1(b2)が、クライアント装置2(s1)へpublish メッセージを送信し、pubackメッセージを受信する前にダウンした場合の例を示す。なお図35の例では、サーバ装置1(b1)へのpubackメッセージが送信された後とする。
図35の例では、ブローカであるサーバ装置1(b1)へのpubackメッセージが送信された後にダウンによってセッションが切断される。サーバ装置1(b1、保証ありで起動)が、サーバ装置1(b2)に向けて(20)のタイミングでpublish メッセージ送信する前にデータベース3に記憶したメッセージ及び送信先(「store 」及び「store_target_broker 」テーブル)の情報は削除されている。サーバ装置1(b2)がダウン保証ありで再起動した場合に、(30)のタイミングでpublish メッセージを送信する前にデータベース3(「store 」及び「store_target」テーブル)に記憶していたメッセージ及び配信先情報に基づき、クライアント装置2(s1)へpublish メッセージが再送される(図11同様)。このときパケットIDがデータベース3に記憶していた情報から参照されて送信される。クライアント装置2(s1)からそのパケットIDにてpubackメッセージが送信されることでデータベース3(「store 」及び「store_target」テーブル)からは情報が削除される。
(3.2.3)ブローカ・ブローカ間
次に、サブスクライバ寄りに存在するブローカであるサーバ装置1(b2)がダウンするケースにおけるブローカ間のセッションについて説明する。図36は、ブローカであるサーバ装置1(b2)がダウンした場合の処理を示す図である。詳細には、サーバ装置1(b2)が、ブローカであるサーバ装置1(b1)からのpublish メッセージを受信する前後、クライアント装置2(s1)へpublish メッセージへの送信を行なう前にダウンした場合の例を示す。
図36の例では、サーバ装置1(b1、保証ありで起動)がサーバ装置1(b2)に向けて(20)のタイミングでpublish メッセージを送信する前に、データベース3に記憶したメッセージ及び送信先(「store 」及び「store_target_broker 」テーブル)の情報は残っている。サーバ装置1(b1)は、サーバ装置1(b2)のダウンによるセッションGが切断されたことを検知すると(図24のステップS301)、サーバ装置1(b2)とセッションを確立しているクライアント装置2(s1)へ送信されていたはずのメッセージとしてデータベース3(「store_target_broker_user」テーブル)にブローカ経由の配信先情報を保存(移動)する(S305)。そしてサーバ装置1(b1)は、データベース3に保存したことによってパブリッシャであるクライアント装置2(p1)へpuback メッセージを送信する(S306)。
図37は、図36に示した状態の後、サーバ装置1(b2)が起動した後に行なわれる処理の例を示す図である。サーバ装置1(b1, b2)は夫々相互にセッションの確立、同期処理及び照合等の処理を行なう(図24のS307からS309、図34のS401からS403)。再起動したサーバ装置1(b2)は、クライアント装置2(s1)について、接続先は自身であると判断する(S404:YES)。サーバ装置1(b2)は、接続先を自身とするクライアント装置2(s1)へ送信されていたはずのメッセージ(ブローカ経由の配信先情報)をデータベース3(「store_target_broker_user」テーブル)から抽出し(S406)、新たなパケットID(「0x133 」)を用いてタイミング(50)で送信する(S408)。このときサーバ装置1(b2)によって再度、データベース3(「store 」及び「store_target」テーブル)に保存メッセージ及び配信先情報(user_id=s1, packet_id=0x133, store_id=789, already_sent=false, qos=1)が記憶される。その後(60)のタイミングにてクライアント装置2(s1)からpubackメッセージが送信され、サーバ装置1(b2)がこれを受信する(S409)ことで、この保存メッセージ及び配信先情報が削除されている(S410)。
このようにして、ブローカであるサーバ装置1がセッションの切断のみならずダウンした場合であっても、パブリッシャからQoS =1を指定して送信されたメッセージについて、サブスクライバまでの到達を、QoS =1(「At least Once 」(最低1回、1回以上届く))で保証することが可能である。
(4)QoS =2、ブローカダウン保証外の動作
次に、ブローカがダウンした場合にメッセージの到達を保証しないという前提において、パブリッシャであるクライアント装置2からQoS =2を指定してpublish メッセージが送信される場合の処理について説明する。なお以下の説明では、当該メッセージのトピックを指定しているサブスクライバであるクライアント装置2が、トピック指定時にQoS として「2」を指定している場合の当該サブスクライバまでのメッセージの到達について説明する。なお、同一のメッセージのサブスクライバであって、トピック指定時に「0」を指定しているサブスクライバへのメッセージ送信は(1)で述べたようにpublish メッセージを1回送信するのみで処理が終了するので説明を省略する。また、トピック指定時に「1」を指定しているサブスクライバへのメッセージの送信は(2)で述べたpubackメッセージの順序性をpubrecメッセージに読み替えた内容に基づき行なわれる。つまり原則的に、他のサーバ装置1全てからpubackメッセージを受信するまで、送信元へpubrecメッセージを返さないという制御が行なわれる。
(4.1)正常運用時
QoS =2で送信されるメッセージを保証する場合、ブローカであるサーバ装置1は、パケットID対応情報(pidmap)を記憶して利用する。図1に示したように通信システム100では、複数のブローカ(大抵は1又は2台)がメッセージの配信を仲介する。パブリッシャであるクライアント装置2が接続しているブローカと、サブスクライバであるクライアント装置2が接続しているブローカとが異なる場合、即ちメッセージの送受信に2台以上のブローカが存在する場合には、メッセージはこのブローカ間のセッションを経由する。図3に示したようにサーバ装置1はMQTTモデルに準拠し、セッション毎に、パケットIDをキーとしてメッセージをやり取りする。本開示のサーバ装置1は、自身が確立するセッションに関し、同一のメッセージの送信のために異なるセッション間で使用されたパケットIDの対応関係をパケットID対応情報(pidmap)として記憶する。正常時からパケットID対応情報を記憶しておくことにより、後述するように、メッセージのやり取りの中途でセッションが切断した場合、又はサーバがダウンした場合であっても直前の状態に復帰させることが可能になる。
図38は、QoS =2におけるパケットID対応情報の説明図である。なお図38の説明図では、パブリッシャであるクライアント装置2と該パブリッシャから送信されるメッセージのトピックを指定トピックとしているサブスクライバであるクライアント装置2との間に、2つのブローカが介在する場合の接続構成にて各サーバ装置1で記憶される情報の例を示している。図38では、クライアント装置2(p1)がパブリッシャとしてサーバ装置1(b1)に通信接続し(セッションJ)、同じサーバ装置1(b1)にクライアント装置2(s2)がサブスクライバとして通信接続している(セッションM)。クライアント装置2(s1)は、サブスクライバとしてサーバ装置1(b2)に通信接続している(セッションK)。2つのブローカであるサーバ装置1(b1, b2)間も、通信接続されている(セッションL)。図38の例においてクライアント装置2(p1)から送信されるメッセージは、セッションJ及びセッションMを経由してクライアント装置2(s2)へ到達し、セッションJ、セッションL及びセッションKを経由してクライアント装置2(s1)へ到達する。
サーバ装置1は夫々、3種類のパケットID対応情報を一時記憶部13に記憶している。3種類のパケットID対応情報は第1に、クライアント装置2から自身であるサーバ装置1へのメッセージにおけるパケットIDと(userからの受信の意味で「u 」)、自身であるサーバ装置1からクライアント装置2へのメッセージにおけるパケットIDと(userへの送信の意味で「u 」)の対応関係(pid_map_u2u )を含む。第2に、クライアント装置2から自身であるサーバ装置1へのメッセージにおけるパケットIDと(userからの受信の意味で「u 」)、自身であるサーバ装置1から他のサーバ装置1へのメッセージにおけるパケットIDと(brokerへの送信の意味で「b 」)の対応関係(pid_map_u2b )を含む。第3に、他のサーバ装置1から自身であるサーバ装置1へのメッセージにおけるパケットIDと(brokerからの受信の意味で「b 」)、自身であるサーバ装置1からクライアント装置2へのメッセージにおけるパケットIDと(userへの送信の意味で「u 」)の対応関係(pid_map_b2u )を含む。夫々のパケットID対応情報は、自身へのメッセージの送信者の識別情報([source_user(broker)_id])、自身からのメッセージの受信者の識別情報([target_user(broker)_id])、前記送信者からのパケットID([source_pid]、図中では[s_pid]で示す)、前記受信者向けのパケットID([target_pid]、図中では[t_pid]で示す)、メッセージの送信の完了を示す論理値([sent])を含む。
図38に示す接続構成の場合、ブローカであるサーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)から送信されるpublish メッセージについて3種類のパケットID対応情報の内、次の2つのパケットID対応情報を用いる。1つは、クライアント装置2(p1)からのメッセージのパケットIDと、自身に通信接続しているサブスクライバであるクライアント装置2(s2)へのメッセージのパケットIDとの対応関係のためのパケットID対応情報(pid_map_u2u )である。1つは、クライアント装置2(p1)からのメッセージのパケットIDと、自身と通信接続している他のブローカであるサーバ装置1(b2)へのメッセージのパケットIDとの対応関係のためのパケットID対応情報(pid_map_u2b )である。図38に示す例では、サーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からのパケットIDと、サブスクライバであるクライアント装置2(s2)へのメッセージのパケットIDとの対応関係のための第1のパケットID対応情報(pid_map_u2u )(source_user_id=p1, target_user_id=s2)を用いる。同様にして、サーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からのパケットIDと、他のブローカであるサーバ装置1(b2)へのメッセージのパケットIDとの対応関係のための第2のパケットID対応情報(pid_map_u2b )(source_user_id=p1, target_broker_id=b2)を用いる。
同様にして図38に示す接続構成では、サーバ装置1(b2)は、他のサーバ装置1(b1)からのメッセージのパケットIDと、自身に通信接続しているサブスクライバであるクライアント装置2(s1)へのメッセージのパケットIDとの対応関係のためのパケットID対応情報(pid_map_b2u )(source_broker_id=b1, target_user_id=s1)を用いる。
図39は、パケットID対応情報を用いたメッセージの処理手順の一例を示すフローチャートである。なお図39のフローチャートに示す処理手順は、図4のフローチャートに示した手順の内のステップS9の詳細に対応する。
サーバ装置1の制御部10は、パブリッシャとして通信接続を確立している1又は複数のクライアント装置2から、又は他のサーバ装置1からpublish メッセージを受信したか否かを判断する(ステップS501)。受信していないと判断された場合(S501:YES)、制御部10は処理をステップS501へ戻す。
制御部10は、受信したと判断した場合(S501:YES)、受信したpublish メッセージのパケットIDを特定する(ステップS502)。制御部10は、受信したpublish メッセージのトピックを抽出し(ステップS503)、抽出されたトピックについての送信先に他のサーバ装置1が含まれるか否かを判断する(ステップS504)。
ステップS503にて他のサーバ装置1が含まれないと判断された場合(S504:NO)、制御部10は、ステップS501で受信したpublish メッセージについて、抽出されたトピックを指定して自身に通信接続しているサブスクライバであるクライアント装置2を受信者とするレコードを、記憶しているパケットID対応情報(pid_map_u2u )から検索できたか否か判断する(ステップS505)。ステップS505にて制御部10は、送信者([source_user(broker)_id])、受信者([target_user(broker)_id])及びステップS502で特定したパケットID([source_pid])でレコードを検索する。
ステップS505で検索できなかったと判断された場合(S505:NO)、新規のメッセージであるから制御部10は、受信者とのセッションにおけるパケットIDを採番し(ステップS506)、レコードを作成して記憶する(ステップS507)。制御部10は、ステップS506で採番したパケットIDを使用して、サブスクライバであるクライアント装置2へ向けてステップS501で受信したpublish メッセージを送信する(ステップS508)。
検索できたと判断された場合(S505:YES)、制御部10は、レコードにおけるメッセージの送信完了が完了を示しているか否かを判断する(ステップS509)。完了していないと判断された場合(S509:NO)、publish メッセージを再送する(ステップS508)。なおステップS508において、検索されたレコードに受信者向けのパケットIDが存在する場合は、そのパケットIDを使用して送信し、存在しない場合はここでパケットIDを採番して送信するとよい。
送信が完了していると判断された場合(S509:YES)、制御部10は送信処理を省略して次のステップS510)へ処理を進める。
なおステップS508において制御部10は、送信先に、keep接続を選択しており且つセッションが切断中であるクライアント装置2が存在する場合には、送信先をデータベース3とする。送信先をデータベース3とする場合は、ステップS505のパケットIDは採番できないので、パケットIDなしでパケットID対応情報を記憶するとよい(S507)。
続いて制御部10は、受信したpublish メッセージの送信元(パブリッシャ又は他のサーバ装置1)へpubrecメッセージを返す(ステップS510)。制御部10は、publish メッセージの受信者からpubrecメッセージを受信したか否かを判断する(ステップS511)。受信していないと判断された場合(S511:NO)、制御部10は処理をステップS511へ戻し、受信したと判断されるまで待機する。受信したと判断された場合(S511:YES)、制御部10は、パケットID対応情報のレコードをpubrecメッセージの送信元を受信者の識別情報([target_user(broker)_id])及びpubrecメッセージのパケットID([target_pid])で検索し、検索されたレコードについて、メッセージが送信完了であるとして更新する(ステップS512)。
次に制御部10は、pubrelメッセージをpublish メッセージの送信者から受信したか否かを判断する(ステップS513)。受信していないと判断された場合(S513:NO)、制御部10は処理をステップS513へ戻し、受信したと判断されるまで待機する。受信したと判断された場合(S513:YES)、制御部10は、パケットID対応情報のレコードを送信者のpubrelメッセージの送信者の識別情報([source_user(broker)_id])及びpubrelメッセージのパケットID([source_pid])で検索し、検索されたレコードを削除し(ステップS514)、1つのpublish メッセージの配信処理を終了する。
ステップS504にて他のサーバ装置1が含まれると判断された場合(S504:YES)、制御部10は、他のサーバ装置1に向けて、上述のステップS505からS509に示した処理と同様の処理S515からS519を、記憶しているパケットID対応情報(pid_map_u2b )に対して行なう。なお、ステップS518において制御部10は、他のサーバ装置1以外に、抽出されたトピックを指定して自身に通信接続しているサブスクライバであるクライアント装置2へ送信する場合には、同様にしてpublish メッセージを送信する(S518)。
他のサーバ装置が送信先に含まれる場合、制御部10はステップS518の後に、他のサーバ装置1全てからpubrecメッセージを受信するまで、pubrecメッセージを受信したか否か判断する(ステップS520)。受信していないと判断された場合(S520:NO)、制御部10は処理をステップS520へ戻し、次のステップS521には進まない。受信したと判断された場合(S520:YES)、制御部10は、パケットID対応情報のレコードをpubrecメッセージの送信元を受信者の識別情報([target_user(broker)_id])及びpubrecメッセージのパケットID([target_pid])で検索し、検索されたレコードについて、メッセージが送信完了であるとして更新する(ステップS521)。そして他のサーバ装置1全てからpubrecメッセージを受信したか否かを判断する(ステップS522)。全てから受信していないと判断された場合(S522:NO)、制御部10は処理をステップS520へ戻し、他のpubrecメッセージを受信するまで次のステップS523の処理は行なわない。ステップS522にて、他のサーバ装置1全てからpubrecメッセージを受信したと判断された場合(S522:YES)、制御部10は、自身に通信接続しているクライアント装置2からpubrecメッセージを受信していなくとも、この場合はステップS523へ処理を進め、クライアント装置2からのpubrecメッセージについては個別に処理する。
ステップS522にて他のサーバ装置1全てからpubrecメッセージを受信したと判断された場合(S522:YES)、制御部10は、受信したpublish メッセージの送信元(パブリッシャ又は他のサーバ装置1)へpubrecメッセージを返す(ステップS523)。続けて制御部10は、pubrelメッセージをpublish メッセージの送信者から受信したか否かを判断する(ステップS524)。受信していないと判断された場合(S524:NO)、制御部10は処理をステップS524へ戻し、受信したと判断されるまで待機する。受信したと判断された場合(S524:YES)、制御部10は、パケットID対応情報のレコードを送信者のpubrelメッセージの送信者の識別情報([source_user(broker)_id])及びpubrelメッセージのパケットID([source_pid])で検索し、検索されたレコードを削除し(ステップS525)、1つのpublish メッセージの配信処理を終了する。
図40から図42を参照して、図39のフローチャートに示した処理手順を具体的に説明する。図40から図42は、パケットID対応情報の内容例を示す図である。まず図40は、パブリッシャであるクライアント装置2(p1)がpublish メッセージを送信してから、2つのブローカであるサーバ装置1(b1, b2)を経由してサブスクライバであるクライアント装置2(s1)へpublish メッセージが送信される時点までのパケットID対応情報(「pidmap」)を示す。図40に示すように、サーバ装置1(b1)は、パブリッシャであるクライアント装置2(p1)からタイミング(10)でpublish メッセージを受信すると(S501:YES)、クライアント装置2(s2)とのセッションにおいてパケットID「0x126 」を採番する(S516)。サーバ装置1(b1)は、パケットID対応情報(pid_map_u2u )に識別情報「p1」の送信者からのパケットID「0x112 」と識別情報「s2」の受信者へのパケットID「0x126 」の対応関係を示すレコード(source_user_id=p1, target_user_id=s2, s_pid=0x112, t_pid=0x126, sent=false)を作成して記憶する(S517)。制御部10は、採番したパケットID「0x126 」を用いて(20)のタイミングで識別情報「s2」の受信者へpublish メッセージを送信する(S518)。(30)のタイミングで識別情報「s2」の受信者からは、pubrecメッセージが送信されるので、サーバ装置1(b1)はこれを受信し(S520)、送信完了の論理値(sentの初期値は「false 」)を「true」で更新する(S522)。
サーバ装置1(b1)は、他のサーバ装置1(b2)へもpublish メッセージを送信すべくサーバ装置1(b2)とのセッションにおいてパケットID「0x125 」を採番する(S516、S506)。サーバ装置1(b1)は、パケットID対応情報(pid_map_u2b )に識別情報「p1」の送信者からのパケットID「0x112 」と識別情報「b2」の受信者へのパケットID「0x125 」の対応関係のレコード(source_user_id=p1, target_broker_id=b2, s_pid=0x112, t_pid=0x125, sent=false)を記憶する(S517)。制御部10は、採番したパケットID「0x125 」を用いて(20)のタイミングでサーバ装置1(b2)へpublish メッセージを送信する(S518)。図40に示すタイミングでは、識別情報「b2」の受信者からのpubrecメッセージは未受信であるから、対応するレコードにおける送信完了の論理値(sent)は初期値「false 」のままである。
図40に示す例では、サーバ装置1(b2)においてもサブスクライバであるクライアント装置2(s1)へpublish メッセージを送信するに際し、パケットID「0x134 」を採番する(S506)。制御部10は、パケットID対応情報(pid_map_b2u )に識別情報「b1」の送信者からのパケットID「0x125 」と、識別情報「s1」の受信者へのパケットID「0x134 」との対応関係を示すレコード(source_broker_id=b1, target_user_id=s1, x_pid=0x125, t_pid=0x134, sent=false)を作成して記憶する(S507)。サーバ装置1(b2)の制御部10は、採番したパケットID「Z 」を用いて(30)のタイミングでクライアント装置2(s1)へpublish メッセージを送信する(S508)。
図41は、図40の後、サーバ装置1(b2)からpubrecメッセージが送信される時点(タイミング(40))までのパケットID対応情報(「pidmap」)を示す。図41では、サーバ装置1(b2)は、(30)のタイミングでクライアント装置2(s1)へpublish メッセージを送信すると、順序性を守ってサーバ装置1(b1)へpubrecメッセージを送信する(S510)。これにより、サーバ装置1(b1)は、自身が送信したpublish メッセージについて、受信者であるサーバ装置1(b2)からpubrecメッセージを受信するので(S520)、対応するパケットID対応情報(pid_map_u2b )のレコードの送信完了の論理値(sent)を「true」に更新している(S521)。サーバ装置1(b1)は、他のサーバ装置1全てからpubrecメッセージを受信するので(S522:YES)、この後、パブリッシャであるクライアント装置2(p1)へ向けて、pubrecメッセージを送信する。
図41の例では、サーバ装置1(b2)においても、受信者であるクライアント装置2(s1)からpubrecメッセージを受信したので、対応するパケットID対応情報(pid_map_b2u )のレコードの送信完了の論理値(sent)を「true」に更新している(S512)。
図42は、パブリッシャであるクライアント装置2(p1)からのpublish メッセージの配信処理が完了した後のパケットID対応情報(「pidmap」)を示す。サーバ装置1(b1)は、(40)のタイミングで受信したpubrecメッセージにより、他のサーバ装置1全てからpubrecメッセージを受信したと判断するので(S522:YES)、(50)のタイミングで、パブリッシャであるクライアント装置2(p1)へ向けて、pubrecメッセージを送信する(S523)。
パブリッシャであるクライアント装置2(p1)は、パケットID「0x112 」について受信者であるサーバ装置1(b1)からpubrecメッセージを受信するので、pubrelメッセージを送信する。サーバ装置1(b1)は、pubrelメッセージを受信したので(S524:YES)、送信者の識別情報「p1」及びpubrelメッセージのパケットID「0x112 」でパケットID対応情報を検索し、「pid_map_u2u 」及び「pid_map_u2b 」にて合致する2つレコードをいずれも削除し(S525)、配信処理を終了する。
サーバ装置1(b1)はネットワークコントローラの動作により、サーバ装置1(b2)を受信者とするパケットID「0x125 」のメッセージについて、pubrecメッセージを受信すると、pubrelメッセージを送信する。これによりサーバ装置1(b2)でも、pubrelメッセージを受信したので(S513:YES)、送信者の識別情報「b1」及びpubrelメッセージのパケットID「0x125 」でパケットID対応情報を検索し、「pid_map_b2u 」にて合致する2つレコードをいずれも削除し(S514)、配信処理を終了する。
上述の処理に示したように、QoS =2に調停された場合もQoS =1に調停された場合と同様に、各サーバ装置1における処理の順序性は保たれ、それに加えてパケットID対応情報を各自記憶される。QoS =2の場合、セッションが切断されたことで再接続時に同一のパケットIDを使用してpublish メッセージが再送されるが、各サーバ装置1は、同一の送信者から同一のパケットIDを使用したpublish メッセージについて、受信者からpubrecメッセージを受信しているケースでは再送を行なわない。これにより、パブリッシャからサブスクライバまでのメッセージが、異なるセッションを跨ぐケースでも、メッセージの到達をQoS =2で保証することが可能である。
(4.2)切断発生時
ブローカがダウンした場合は保証しないという前提で、パブリッシャであるクライアント装置2とサーバ装置1との間、2つのサーバ装置1の間、サーバ装置1とサブスクライバであるクライアント装置2との間のセッションがメッセージのやり取り途中で切断した場合について説明する。なお以下の説明は、図38に示した構成におけるセッションJからセッションMの内のいずれか1つ又は複数が切断された例を挙げて説明する。
(4.2.1)パブリッシャ・ブローカ間
パブリッシャであるクライアント装置2から、QoS =2で調停されたサブスクライバへのデータの送信に関し、パブリッシャとブローカとの間のセッションが切断されるケースについて考える。このケースは、図40に示したパブリッシャであるクライアント装置2(p1)からpublish メッセージが送信された後、サーバ装置1(b1)からpubrecメッセージが送信される前に、クライアント装置2(p1)とサーバ装置1(b1)の間のセッションJが切断されるケースである。
このケースでは、パブリッシャであるクライアント装置2(p1)は、送信したpublish メッセージに対するpubrecメッセージが返されるまで、そのpublish メッセージを送信バッファに一時記憶したままとする(図3)。セッションJが再度確立された場合、クライアント装置2(p1)は、送信バッファに一時記憶しているpublish メッセージを再度セッションJにおいて、同一パケットIDを用いて接続先のサーバ装置1(b1)へ送信する。サブスクライバへのメッセージの到達保証がQoS =2に調停されている場合、この2回目以降の同一のpublish メッセージを起源とするpublish メッセージが、サブスクライバであるクライアント装置2で重複して受信処理されることを回避しなければならない。
本実施の形態におけるサーバ装置1の処理により、図40の状態でセッションJが切断されるケースでも、まず、サブスクライバであるクライアント装置2へ(s1)のメッセージ到達を「Exactly once」(正確に1回、ちょうど1回だけ届く)(QoS =2)とすることができる。サーバ装置1(b1)は、切断される前にパブリッシャであるクライアント装置2(p1)から受信したpublish メッセージについて、クライアント装置2(s1)が通信接続している他のサーバ装置1(b2)へのpublish メッセージの送信を完了している場合、パケットID対応情報のレコード(pid_map_u2b)を一時記憶している。したがって、再送されたpublish メッセージをパブリッシャから受信した場合、サーバ装置1(b1)は、同一の送信者からの同一のパケットIDを含み、他のサーバ装置1(b2)を受信者とするレコードを検索できる(source_user_id=p1, source_pid=0x112, target_broker_id=b2)。
レコードが検索できた場合、送信先のサーバ装置1(b2)から、サーバ装置1(b1)へpubrecメッセージが送信される前、即ち、その先に通信接続しているクライアント装置2(s1)へのpublish メッセージの送信前であれば、検索されたレコードにおける送信完了の論理値(sent)は「false 」である。この場合、サーバ装置1(b1)は、検索されたレコードに含まれる受信者(target_broker_id=b2 )へのパケットID(target_pid=0x125)を用いてpublish メッセージを再送する。サーバ装置1(b1)からのpublish メッセージの再送を受けたサーバ装置1(b2)は、通信接続しているクライアント装置2(s1)からのpubrecメッセージを受信していない場合、publish メッセージを同様にして再送する。セッションKにおけるMQTTモデルによって、クライアント装置2(s1)は、pubrelメッセージを受信するまでは、再送されたpublish メッセージを受信しても受信処理せずに破棄するから、重複して受信処理を行なうことはない。
サーバ装置1(b2)は、通信接続しているクライアント装置2(s1)へ、セッションJの切断前にパブリッシャから送信されたメッセージに基づくpublish メッセージを送信済みである場合、pubrecメッセージをサーバ装置1(b1)へ返しているか、返そうとしている。サーバ装置1(b1)はほどなく、このpubrecメッセージを受信し、検索されたレコードにおける送信完了の論理値(sent)は「true」に更新されている。パブリッシャからpublish メッセージの再送を受けた時点で、検索されたレコードの送信完了の論理値(sent)が「true」である場合、サーバ装置1(b1)はサーバ装置1(b2)へ向けてpublish メッセージを再送しない。このように、クライアント装置2(s1)へ、セッションJの切断前にパブリッシャから送信されたpublish メッセージに基づくpublish メッセージが送信済みである場合、サーバ装置1(b2)へも同一のpublish メッセージに基づくpublish メッセージの再送はなされない。クライアント装置2(s1)へ重複してメッセージが到達することはない。
パブリッシャからpublish メッセージの再送を受けた時点で、検索されたレコードの送信完了の論理値(sent)が「false 」である場合、サーバ装置1(b1)はサーバ装置1(b2)へ向けてpublish メッセージを再送するが、サーバ装置1(b2)では、同一パケットIDによるpublish メッセージを受信済みで処理しているので、この再送されたpublish メッセージはMQTTモデルに基づくセッション毎の到達保証により、破棄される。クライアント装置2(s1)へ重複してメッセージが到達することはない。
サーバ装置1(b1)は、切断される前にパブリッシャであるクライアント装置2(p1)から受信したpublish メッセージについて、識別情報「s1」のクライアント装置2が通信接続している他のサーバ装置1(b2)へのpublish メッセージの送信を行なう際に、他のサーバ装置1(b2)とのセッションLが切断されている場合、メッセージ及びその配信先をデータベース3(「store 」及び「store_target_broker」テーブル)として記憶する(後述)。このときサーバ装置1(b1)は、受信者を送信先であるはずであった他のサーバ装置1の識別情報「b2」、受信者へのパケットIDを「NULL」とし、送信完了の論理値を「true」とするパケットID対応情報(pid_map_u2b )のレコードを作成して記憶しておく。この場合、他のサーバ装置1(b2)側で、データベース3(「store 」及び「store_target_broker」テーブル)に記憶されている自身宛のメッセージが保存されていることを認識でき、受信処理がなされるはずである。セッションJが切断された後、パブリッシャからメッセージの再送を受けたとしても、同一の送信者からの同一のパケットIDを含み、他のサーバ装置1(b2)を受信者とするレコードを検索でき、しかも送信完了が「true」であるから、セッションLが再接続されたとしても再送を行なわれることが回避される。これにより、メッセージが重複して到達することはない。
図40の状態でセッションJが切断された場合に、サーバ装置1(b1)に直接的に通信接続しているサブスクライバであるクライアント装置2(s2)へのメッセージ到達についても「Exactly once」(QoS =2)とすることができる。
サーバ装置1(b1)は、切断される前にパブリッシャであるクライアント装置2(p1)から受信したpublish メッセージについて、クライアント装置2(s2)へのpublish メッセージの送信を完了している場合、パケットID対応情報のレコード(pid_map_u2u )を一時記憶している。したがって、再送されたpublish メッセージをパブリッシャから受信した場合、サーバ装置1(b1)は、同一の送信者からの同一のパケットIDを含み、クライアント装置2(s2)を受信者とするレコードを検索できる(source_user_id=p1, source_pid=0x112, target_user_id=s2)。
レコードが検索できた場合、送信先のクライアント装置2(s2)から、サーバ装置1(b1)へpubrecメッセージが送信される前であれば、検索されたレコードにおける送信完了の論理値(sent)は「false 」である。この場合、サーバ装置1(b1)は、検索されたレコードに含まれる受信者へのパケットID(target_pid=0x126)を用いてpublish メッセージを再送する。サーバ装置1(b1)からのpublish メッセージの再送を受けたクライアント装置2(s2)は、pubrelメッセージを受信するまでは、再送されたpublish メッセージを受信しても受信処理せずに破棄するから、重複して受信処理を行なうことはない。
レコードが検索でき、送信先のクライアント装置2(s2)から、サーバ装置1(b1)へpubrecメッセージが送信された後であれば、検索されたレコードにおける送信完了の論理値(sent)は「true」である。サーバ装置1(b1)は、再送されたpublish メッセージに基づくpublish メッセージの再送を行なわない。クライアント装置2(s2)へ重複してメッセージが到達することはない。
サーバ装置1(b1)は、切断される前にパブリッシャであるクライアント装置2(p1)から受信したpublish メッセージについて、クライアント装置2(s2)へのpublish メッセージの送信を行なう際に、当該クライアント装置2(s2)とのセッションMが切断されているケースが考えられる。このケースは、ブローカ・サブスクライバ間の切断であるから後述にて説明する。
切断のタイミングが図40に示した状態以外である場合、サーバ装置1(b1)は、各セッションにおけるMQTTモデルにおけるネットワークコントローラの送信バッファに残存しているメッセージの有無に基づく処理(図15から図17)により、中断されたやり取りが再開され、メッセージのやり取りが完了する。図41、図42に示したように、pubrecメッセージがパブリッシャへ到達した後は、各セッションにおけるpubrelメッセージ及びpubcomp メッセージのやり取りが実行される。
このように、セッション毎におけるQoS =2のみならず、セッションJ、セッションL及びセッションK、並びにセッションJ及びセッションMを跨ぐメッセージの到達保証を、セッションJが切断された場合でもQoS =2で達成することができる。
(4.2.2)ブローカ・サブスクライバ間
図40に示した状態で、サブスクライバであるクライアント装置2(s1)と、ブローカであるサーバ装置1(b2)との間で確立されていたセッションKが切断された場合のQoS =2の到達保証について説明する。図43は、サーバ装置1(b2)におけるサブスクライバとのセッション切断検知時の処理手順の一例を示すフローチャートである。
サーバ装置1(b2)の制御部10は、自身に通信接続していたサブスクライバであるクライアント装置2との切断を検知すると(ステップS601)、図15Aのフローチャートに示したMQTTの中途メッセージ情報の処理手順にしたがって、切断されたセッションの接続先のクライアント装置2向けのpublish メッセージが送信バッファに残存しているか否かを判断する(ステップS602)。残存していると判断された場合(S602:YES)、制御部10は、このpublish メッセージを中途メッセージ情報(パケットイメージと送信先のクライアント装置2の識別情報)としてデータベース3(「keep_mqtt 」テーブル)に記憶する(ステップS603)。送信バッファに残存していたpublish メッセージは消去される。
制御部10は、一時記憶しているパケットID対応情報(pid_map_b2u 又はpid_map_u2u )の内、切断されたセッションの接続先のクライアント装置2を受信者とするレコードをデータベース3に自身の識別情報(broker_id)を対応付けて記憶する(ステップS604)。制御部10は、記憶したレコードを、一時記憶から削除する(ステップS605)。
制御部10は、切断されたセッションの接続先のクライアント装置2が再度自身へ通信接続のリクエストを送信してきたか否かを判断する(ステップS606)。送信してきたと判断された場合(S606:YES)、制御部10は、図4のフローチャートに示した処理手順(S1−S3:NO、S16)を実行する。制御部10は、自身が記憶し、接続先のクライアント装置2を受信者とするパケットID対応情報のレコードをデータベース3(pid_map_b2u )から参照する(ステップS607)。制御部10は、ステップS16の状態情報の復元の一環として、読み出したレコード(pid_map_b2u 又はpid_map_u2u )を一時記憶部13による一時記憶に戻す(ステップS608)。
続いて制御部10は、図15Bのフローチャートに示した処理手順にしたがい、接続先のクライアント装置2へのpublish メッセージの送信は完了しているか否かを判断する(ステップS609)。送信が完了していないと判断された場合(S609:NO)、制御部10は、データベース3から、接続先のクライアント装置2へ送信されるべきであったメッセージ情報(中途メッセージ情報(「keep_mqtt」テーブル))をデータベース3から読み出す(ステップS610)。制御部10は、読み出したパケットIDをそのまま含むパケットイメージでpublish メッセージを送信する(ステップS611)。そして制御部10は、パケットID対応情報を参照し、再送したpublish メッセージに対応するpubrecメッセージをパブリッシャ側のサーバ装置1(b1)へ送信し(ステップS612)、切断検知時の処理を終了し、以後のMQTTモデルに基づくメッセージのやり取りを続行する。図4のフローチャートに示したステップS18の処理が終了し、サーバ装置1(b2)は配信処理を続行する(S9)。
ステップS609にて、送信は完了していると判断された場合(SS609:YES)、制御部10は切断検知時の処理をそのまま終了する。またステップS606にて、送信されていないと判断された場合(S606:NO)、制御部10は、切断検知時の処理をそのまま終了する。この場合制御部10は、図4のフローチャートのS9へ処理を進めて配信処理を続行する。なおステップS606において送信されないと判断された場合、データベース3に記憶される各クライアント装置2の接続情報(「connections 」)を確認して自身ではないと判断してもよい。
一方、切断された先のクライアント装置2(s1)が新たに通信接続をリクエストした先のサーバ装置1における処理について説明する。新たな接続先のサーバ装置1は、新たな通信接続のリクエストに対し、図4のフローチャートに示した処理手順を実行する。この場合、セッション情報がデータベース3(「keep_sub」テーブル)に記憶されているので、接続先のサーバ装置1は、ステップS16にて状態情報を復元する。
サーバ装置1は、データベース3から接続先のクライアント装置2(s1)への送信に係るパケットID対応情報(pid_map_b2u )を検索し、検索された場合にはこれを読み出して状態情報の一部として復元する(S16)。新たな接続先であるサーバ装置1は、図15Bの処理手順にしたがって、データベース3の保存メッセージ及び配信先情報又は中途メッセージ情報(「store 」及び「store_target_broker_user」テーブル、又は「keep_mqtt」テーブル)を検索し、メッセージがあると判断された場合(S106:YES)、メッセージを読み出してクライアント装置2へ送信する(S107)。制御部10は、送信したメッセージをデータベース3から削除する(S108)。制御部10は、パケットID対応情報から、publish メッセージの送信元(他のサーバ装置1又はパブリッシャ)へ向けて、pubrec メッセージを送信し、pubrelメッセージ及びpubcomp メッセージのやり取りを完了させる。これによりデータベース3からの配信(S18)を終了する。
図43のフローチャートに示した処理手順を具体的に説明する。図40におけるセッションKが、サーバ装置1(b2)がクライアント装置2(s1)へ(30)のタイミングでpublish メッセージを送信する前に切断されるケースが考えられる。このケースでは、keep接続の処理(図9、図10から図14)により、切断されている間に配信されたメッセージは、保存メッセージ及び配信先情報(「store 」及び「store_target」テーブル)として記憶される(クライアント装置2(s2)がkeep接続している場合)。再接続後にサーバ装置1(b2)又は新たなサーバ装置1の処理によってデータベース3から配信される(クライアント装置2(s1)がkeep接続している場合)。再接続後のサーバ装置1では、切断されたクライアント装置2を対象とするパケットID対応情報を復元できるので、既にクライアント装置2がpublish メッセージを受信処理済みであるか否か(pubrecメッセージを送信しているか否か)を把握することができ、メッセージを重複して送信することなくQoS =2を達成できる。
セッションKが、サーバ装置1(b2)がクライアント装置2(s1)へ(30)のタイミングでpublish メッセージを送信した後、pubrecメッセージを受信する前に切断されるケースも考えられる。このケースでは、再接続後にサーバ装置1(b2)又は新たなサーバ装置1の処理によって、データベース3の中途メッセージ情報(「keep_mqtt 」テーブル)を参照した処理(図15から図19)により、中断されたやり取りが再開され、メッセージのやり取りが完了する。
また、図40に示した例で、パブリッシャであるクライアント装置2(p1)から受信したpublish メッセージについて、サーバ装置1(b1)がクライアント装置2(s2)へのpublish メッセージの送信を行なう際に、当該クライアント装置2とのセッションMが切断されているケースもブローカ・サブスクライバ間の切断である。セッションMが切断されるケースでは、切断中にクライアント装置2(s2)が受信すべきメッセージは、識別情報「s2」とする配信先情報と共にデータベース3(「store 」及び「store_target」テーブル)に記憶される(クライアント装置2(s2)がkeep接続している場合)。そしてこのときサーバ装置1(b1)は、受信者を送信先であるはずであったクライアント装置2の識別情報「s2」、受信者へのパケットIDを「NULL」とし、送信完了の論理値を「true」とするパケットID対応情報(pid_map_u2u )のレコードを作成して記憶している。
このケースでは、セッションMが再接続された場合、keep接続の処理により(図4)、記憶されている保存メッセージ及び配信先情報に基づくデータベース3(「store 」及び「store_target」テーブル)からのクライアント装置2(s2)への配信処理が行なわれる。再接続先であるサーバ装置1(b1)では、パケットID対応情報を復元できる。セッションJが切断された後、パブリッシャからメッセージの再送を受けたとしても、同一の送信者、同一のパケットID、クライアント装置2(s2)を受信者とするレコードを検索でき、検索されたレコードの送信完了は「true」であるから、セッションMが再接続されたとしても再送が行なわない。このようにメッセージの重複到達が回避される。
このケースにおいてクライアント装置2(s2)が別のサーバ装置1に通信接続した場合も、データベース3(「store 」及び「store_target」テーブル)から配信される。この場合も、別のサーバ装置1にて復元されるパケットID対応情報(pid_map_u2u )によって、既に送信済みであることが認識されて重複した送信が回避される。
(4.2.3)ブローカ・ブローカ間
パブリッシャからサブスクライバへのメッセージを仲介する2つのブローカ間で確立されていたセッションが切断された場合の到達保証について説明する。ブローカ間のセッションは上述したようにkeep接続が選択されている。ブローカ間のセッションの切断(図40におけるセッションLの切断)については、keep接続に対する保存メッセージの記憶(「store 」)と、(2.2.3)で説明した切断されている他のサーバ装置1を経由して送信されるメッセージであったことを示すブローカ経由の配信先情報(「store_target_broker_user」テーブル)の記憶とをパケットID対応情報と共に用いて処理を行なう。
QoS =2の場合、ブローカ間のセッションが切断された場合のサーバ装置1による処理は、QoS =1について図24のフローチャートに示した処理手順と基本的に同様である。ただしQoS =2の場合には、ステップS306で送信するpubackメッセージではなくpubrecメッセージであり、ステップS316で保存メッセージを削除するステップS315のトリガはpubackメッセージではなく、pubcomp メッセージを受信することである。そしてステップS305にて記憶される「本来であれば他のサーバ装置1とセッションを確立しているクライアント装置2へ送信されていたはずのメッセージ」とその配信先情報(「store 」及び「store_target_broker_user」テーブル)に、送信完了しているか否か(pubrecメッセージをその時点で受信しているか否か)の情報を共に記憶する。
ブローカ間が切断された場合の処理について、具体例を挙げて説明する。ブローカ間のセッションが切断された場合の処理について具体例を挙げて説明する。図44から図46は、ブローカ間のセッションが切断された場合の処理の例を示す説明図である。図44の例で示される装置の接続構成は、クライアント装置2(s2)を省略している点以外は図38にて示した例と同一である。
図44は、ブローカであるサーバ装置1(b1, b2)間のセッションが切断された場合にサーバ装置1の一時記憶部13及びデータベース3に記憶される情報の内容例を示している。図44に示した例は、QoS =1の場合の図25を参照して説明した処理と、切断が検知されるまで同様である。図44のQoS =2の場合には、各サーバ装置1がパケットID対応情報を記憶している点で異なる。
図45は、図44に示した状態から、ブローカ間のセッションLが再確立された後の処理を示し、サーバ装置1(b2)と、サブスクライバであるクライアント装置2(s1)との間のセッションKが維持されている場合の処理を示している。図44で説明したように保存メッセージ及びブローカ経由の配信先情報がデータベース3(「store 」及び「store_target_broker_user」テーブル)に記憶されている。これにより、QoS =1の場合は、ブローカ間のセッションLが切断された場合には、サーバ装置1(b2)からクライアント装置2(s1)へのメッセージの送信がなされたかが不明であるため、サーバ装置1(b2)から念のためにメッセージを送信しておき、確実に送信することが達成できた。QoS =2の場合は、これらの情報とパケットID対応情報との併用により、1回の送信(Excactry once )とすることができる。
具体的には、QoS =2の場合、まず図45に示すようにセッションKが維持されている場合には、サーバ装置1(b2)からサブスクライバであるクライアント装置2(s1)へパケットIDが採番できてパケットID対応情報(pid_map_b2u )が記憶されるから、そのままパブリッシャからのpublish メッセージがクライアント装置2(s1)に到達しているはずである(sent=true になる)。仮にセッションKが切断された場合であっても、keep接続及び中途メッセージ情報(keep_mqtt )等に基づいてブローカであるサーバ装置1(b2)の制御により、送信しようとされていたpublish メッセージはクライアント装置2(s1)へ送達されるはずである。したがってQoS =2では送信を1回とするために、対応するパケットID対応情報が記憶されている場合には、保存メッセージ及びブローカ経由の配信先情報からの送信は回避されるべきである。そこでサーバ装置1(b2)は、データベース3(「store 」及び「store_target_broker_user」テーブル)から、自身(b2)宛てに、パケットID「0x125 」で、クライアント装置2(s1)向けに送信されたメッセージがあることを認識した場合に、ここからの送信をしないように処理を行なう。具体的にはサーバ装置1(b2)は自身宛のサーバ装置1(b1)からのメッセージのパケットID「0x125 」で識別情報「s1」を受信者としたパケットID対応情報のレコードがあるか否かを確認する。ブローカ間のセッションLが切断された場合には、再確立後MQTT上のやり取りが再開されず、pubrelメッセージを受信しないため、対応するパケットID対応情報のレコードが削除されずに残っているはずである。したがってサーバ装置1(b2)は、サーバ装置1(b1)から受信したメッセージのパケットIDと、そのメッセージをサブスクライバへ送信する際に用いるパケットIDとの対応関係を示すパケットID対応情報(pid_map_b2u )から、ブローカ経由の配信先情報に対応するレコード(source_broker_id==broker_id(b1), target_user_id=user_id(s1), source_pid==broker_pid(0x125))を検索により抽出できる。この場合、サーバ装置1(b2)は、データベース3に記憶してあるブローカ経由の配信先情報(「store_target_broker_user」)からの送信は行なわない。QoS =1の場合は、メッセージがデータベース3に記憶されていれば再送されていたのに対し、QoS =2では上述のように既に送信がされているはずである。このように同一メッセージに基づくpublish メッセージの重複を回避できる。なおサーバ装置1(b2)は、pubrelメッセージを受信できないために残っているブローカ経由の配信先情報と対応するパケットID対応情報(pid_map_b2u)を、その配信先情報と共にここで削除する。ブローカ経由の配信先情報に対応するレコードを検索で抽出できない場合は、サーバ装置1(b2)はブローカ経由の配信先情報からの送信が行ない、この場合、送信先のクライアント装置2からのpubrecメッセージ、pubcomp メッセージの受信により、配信先情報(「store_target_broker_user」)を削除する。
図46は、図44に示した状態から、ブローカ間のセッションLが再確立された後の処理を示す。図46は更に、ブローカ間が切断されている間に、サブスクライバであるクライアント装置2(s1)が、サーバ装置1(b1)との間のセッションを切断し、サーバ装置1(b1)へ接続した場合の例を示している。
図46に示したケースでは、サーバ装置1は特定の処理を実行する。図47は、QoS =2におけるブローカ間のセッションの再確立後のメッセージ送信処理の一例を示すフローチャートである。図47の処理は例えば、図24のフローチャートに示した処理手順の内、ステップS309とステップS310の間に判断処理を加え、その判断処理でYESと判断されたときのみ行なう。判断処理とは、切断されていたセッションの相手のブローカに接続していたサブスクライバであるクライアント装置2が相手のブローカと通信接続を切断したか否かである。
サーバ装置1の制御部は、データベース3(「store 」及び「store_target_broker_user」テーブル)に記憶されているブローカ経由の配信先情報を参照する(ステップS801)。ブローカ経由の配信先情報は、パブリッシャ側のブローカ(送信者)であるサーバ装置1(図40においてはサーバ装置1(b1))が記憶する情報である。制御部10は、ブローカ経由の配信先情報における送信完了しているか否かの情報(他のサーバ装置1からpubrecメッセージを受信しているか、[already_sent])、及び再送しているか否かの情報(再送時のパケットIDがNULLでないか)を参照する(ステップS802)。制御部10は、再送されているか否か(再送時のパケットIDがNULLでないか否か)を判断し(ステップS803)、再送されていると判断された場合(S803:YES)、送信が完了しているか否かの論理値を参照し、完了しているか否かを判断する(ステップS804)。送信が完了していると判断された場合(S804:YES)、制御部10は、配信先情報における再送時のパケットIDを用いてpubrelメッセージを送信し(ステップS805)、以後のMQTTモデルに基づくメッセージ処理を続行し、処理を終了する。
ステップS804にて送信が未完であると判断された場合(S804:NO)、制御部10は、配信先情報における再送時のパケットIDを用いてpublish メッセージを再送し(ステップS806)、以後のMQTTモデルに基づくメッセージ処理を続行し、処理を終了する。
ステップS803にて再送されていないと判断された場合(S803:NO)、制御部10は、ステップS801で参照した配信先情報と、送信者([source_user(broker)_id] )及び受信者([target_user(broker)_id])が同一であるパケットID対応情報のレコードをデータベース3から検索により抽出できるか否かを判断する(ステップS807)。
ステップS807にて検索により抽出できないと判断された場合は(S807:NO)、読み出された配信先情報に記憶されているパケットID対応情報の有無に応じた処理(情報が無い場合であっても実行するか否か)の可否を示す情報が、可を示すか否かを判断する(ステップS808)。
不可を示すと判断された場合(S808:NO)、制御部10は、処理をそのまま終了する。可を示すと判断された場合(S808:YES)、この場合、サブスクライバ側のブローカからパブリッシャ側のブローカへのpubrecメッセージの送信が未完了である(publish メッセージが送信されていない可能性がある)。制御部10は、新たなパケットIDを採番し(ステップS809)、採番したパケットIDを用いてpublish メッセージをサーバ装置1へ送信し(ステップS810)、処理を終了する。
ステップS807にて検索により抽出できると判断された場合は(S807:YES)、図45で説明したようにパケットID対応情報が存在しているので、他のブローカにおける制御により、サブスクライバへ配信がされるはずであるからそのサーバ装置1に処理を任せる。したがって制御部10は、処理をそのまま終了する。
図46を参照して具体的に説明する。サーバ装置1(b1)側ではブローカ間のメッセージについて、図24のフローチャートに示した処理手順の内で、puslish メッセージが残存していると判断される。(20)のタイミングにおけるpublish メッセージに対するpubrecメッセージを受信していないからである。ただしこのケースでは、残存しているpublish メッセージに基づくサブスクライバへのメッセージの送信は、再確立させたサーバ装置1(b2)を経由して行なうか否かは不明である。サーバ装置1(b2)がクライアント装置2(s1)と切断されているので、サーバ装置1(b1)は、ブローカ間のメッセージについて図47の処理を実行する。図46の例では、パケットID対応情報が記憶されているので(S807)、は特に何も送信されず、処理が終了する。
なお図46に示した例においてサーバ装置1(b1)は、クライアント装置2(s1)がサーバ装置1(b1)へセッション確立をリクエストし、これを承諾するとデータベース3における接続先情報を識別情報「b1」に書き換える。この後同期処理が実行され、サーバ装置1(b1及びb2)間で接続情報が共有される。サーバ装置1(b1)は、状態情報を記憶しているクライアント装置2の識別情報「s1」と、データベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)における識別情報「s1」とを照合し(図24のS309)、接続先情報でも自身が接続先であると判断する(S310:YES)。そしてサーバ装置1(b1)は、ステップS311−S313の処理において、後述するようにサーバ装置1(b2)がデータベース3に記憶(移動)したパケットID対応情報にて、自身を送信者とし、接続してきたクライアント装置2(s1)を受信者とするレコードを検索し、検索されるとそのレコードに記憶されている送信完了の論理値([sent])を参照する。論理値が送信完了である場合、そのレコードの受信者向けのパケットID([target_pid])を用いてpubrelメッセージを送信し、送信完了でない場合、同パケットIDを用いてpublish メッセージを再送することができる。
図46で示す例においてサーバ装置1(b2)側では、サーバ装置1(b1)とのセッションを再確立すると(図24、S307)、同期処理を行なう(S308)。サーバ装置1(b2)は、状態情報とデータベース3に記憶されている各クライアント装置2の接続先情報(「connections 」)における識別情報「s1」を照合し(S309)、自身が接続先でないと判断する(S310:NO)。サーバ装置1(b2)は、クライアント装置2(s1)についての状態情報を削除する(S311)。そしてサーバ装置1(b2)は、図43のフローチャートに示した手順にしたがい、クライアント装置2(s1)との関係におけるパケットID対応情報(図中のpid_map_b2u )をデータベース3に記憶(移動)する(S604)。その後、再度通信接続してきていないと判断されるため(S606:NO)、以後のクライアント装置2(s1)向けの処理はサーバ装置1(b1)側に任される。
このように、MQTTモデルにおける到達保証のメッセージのやり取りの途中でブローカ間のセッションが切断された場合であっても、パブリッシャであるクライアント装置2からQoS =2が指定されたメッセージの到達保証をクライアント装置2からブローカまでのセッションのみならず、サブスクライバであるクライアント装置2までの経路においてQoS =2とすることができる。
(5)QoS =2、ブローカダウン保証
ブローカがダウンした場合もメッセージの到達を保証するという前提において、(4)同様に、経路である全てのセッションにてQoS が「2」となるQoS =2が指定されたpublish メッセージのサブスクライバまでの到達について説明する。なお以下の説明でも(4)同様に、当該メッセージのトピックについてサブスクライバであるクライアント装置2がQoS として「2」以外を指定している場合については、説明を省略する。
図48は、QoS =2でブローカダウンを保証する際の処理を示す図である。図48で示す装置の構成は、ブローカダウンを保証しない場合について説明した図38で示した例と同一である。図48と図38とを比較すると明らかであるように、差異はパケットID対応情報の記憶先である。QoS =2で更にブローカダウンを保証する場合、keep接続におけるデータベース3(store, store_target )の記憶に加え、各サーバ装置1がパケットID対応情報を一時記憶部13に一時記憶するのではなく、いずれのブローカの情報であるかを対応付けてデータベース3に記憶し、復旧後にパケットIDの異なるセッション間の一時記憶を復旧することを可能にする。
(5.1)正常運用時
ブローカがダウンした場合にメッセージの到達を保証する場合、ダウンしたことを自身で検知できないので、ダウンした場合の処理に切り替えるといったことができない。この場合サーバ装置1は、一時記憶して用いる情報(送信バッファ、及びパケットID対応情報)、データベース3に記憶して用いる。QoS =2の場合、ブローカダウンを保証する場合もサーバ装置1は基本的に、図39のフローチャートに示した処理手順を実行する。ただし、パケットID対応情報の記憶先がデータベース3であることと、QoS =1の場合について説明した図29のフローチャートで示したように、publish メッセージを送信する前に、keep接続しているクライアント装置2が自身に接続している場合は必ず、データベース3(「store 」及び「store_target」又は「store_target_broker 」)にメッセージを記憶する処理を実行する。即ちサーバ装置1は、図29のフローチャートに示した処理手順の内、S221、S222、S223−S225、S226、S227、S228−S229の処理を、図39のフローチャートにおけるpublish メッセージの送信処理(S508、S518)の前に行なう。なお図29におけるpubackメッセージに関する処理に関してはpubrecメッセージの処理に置換される。
図48に示すQoS =2の場合でのパケットID対応情報は、記憶先がデータベース3であって、また具体的内容(記憶処理を行なったサーバ装置1の識別情報(broker_id )が最初に対応付けられて記憶)が異なる以外は、ダウンを保証外とする場合の処理手順と同様である(図38を参照した(4.1)における説明)。
(5.2)切断時
ブローカがダウンした場合もQoS =2が指定されたメッセージの到達を保証する場合において、切断又はダウンが発生したケースについて具体例を挙げて説明する。基本的に、図48で示したように、パケットID対応情報の記憶先が常にデータベース3であることを除いては、ダウンを保証しない場合の処理と同様である。ブローカダウン時もメッセージの到達をQoS =2で保証する場合には、publish メッセージの送信の都度、データベース3に事前に保存メッセージとして記憶され、完了する都度に削除されると共に、その際のパケットID対応情報もデータベース3に記憶されるから、ダウンした場合も復旧時にデータベース3から、それらの情報を参照して状態情報を復旧することができる。この場合具体的にはサーバ装置1は復旧時に、(3)のQoS =1におけるダウン保証の説明で示した図34のフローチャートの処理手順を実行する。このとき、ステップS409の対応メッセージは、pubcomp メッセージの受信に読み替えられる。つまり記憶された配信先情報及び保存メッセージは、サーバ装置1におけるpubcomp メッセージの受信をトリガに削除される。
ブローカダウン時もメッセージの到達をQoS =2で保証する場合、メッセージの送受信に係る多くの情報をデータベース3に記憶することになる。データベース3への更新及び削除の処理は、時間を要するものである。したがってこのケースでは特に、データベース3をKVSで構成し、全てのイベントを書き込みとすることで処理速度を向上させることが期待できる。
このように、本実施の形態1における通信システム100では、ブローカダウンを考慮した上でパブリッシャからサブスクライバまでのメッセージの到達保証を実現する。完全なる到達保証を実現するには、各ブローカであるサーバ装置1が全てをデータベース3に記憶することで実現することは可能であるが、処理速度が低下し、Pub/Sub 型メッセージ送受信システムの負荷の軽さの利点を享受できない。本実施の形態における通信システム100では、システムを利用するユーザのクライアント装置2が、ブローカへ通信接続する際(keep)、そしてブローカ起動時、即ちサブスクライバから接続するブローカを選択する際(ブローカダウン時保証の有無)、ブローカへサブスクライブを実行する際(サブスクライブ時のQoS の指定)、更にメッセージを送信する際に(パブリッシュ時のQoS の指定)、各々で保証レベルを選択することが可能である。
本開示の実施形態はすべての点で例示であって、制限的なものではないと考えられるべきである。本発明の範囲は、上記した意味ではなく、特許請求の範囲によって示され、特許請求の範囲と均等の意味及び範囲内でのすべての変更が含まれることが意図される。