メッセージ再送信
メッセージ再送信はMQTTプロトコル仕様の一部です。
このプロトコルでは、通信当事者であるサーバーおよびクライアントが送信するPUBLISHパケットは、それぞれのQoS(サービス品質)レベルの要件を満たす必要があると規定しています。具体的には以下の通りです:
- QoS 1:メッセージは少なくとも1回は配信されることを意味します。つまり、送信者は相手からの確認応答を受け取るまで、常にメッセージを再送信します。このため、同じQoS 1メッセージがMQTTプロトコルの上位層(サービスのアプリケーション層)で複数回受信される可能性があります。
- QoS 2:メッセージは正確に1回だけ配信されることを意味します。つまり、上位層ではメッセージが1回だけ受信されます。
QoS 1およびQoS 2のPUBLISHパケットはMQTTプロトコルスタック層で再送信されますが、以下の点に注意してください:
- QoS 1メッセージの再送信が発生した場合、再送信されたPUBLISHパケットもMQTTプロトコルスタックの上位層で受信されます。
- QoS 2メッセージは再送信されても、MQTTプロトコルスタックの上位層では1つのPUBLISHパケットのみが受信されます。
基本設定
メッセージが再送信されるシナリオは以下の2つです:
- PUBLISHパケットを相手に送信後、指定時間内に応答が得られなかった場合にパケットを再送信する。
- セッションを維持している状態でクライアントが再接続した際、EMQXは未応答のメッセージを自動的に再送信し、正しいQoS処理を保証する。
設定ファイルで以下のように設定可能です:
| 設定項目 | 型 | オプション値 | デフォルト値 | 説明 |
|---|---|---|---|---|
| retry_interval | duration | - | 30s | タイムアウト間隔を待ち、応答がなければメッセージを再送信する時間間隔 |
一般的には上記内容だけを理解していれば十分です。
EMQXがMQTTプロトコルの再送信をどのように処理するかの詳細は、この記事の後半をご参照ください。
プロトコル仕様と設計
再送信対象
まず、EMQXの再送信機構設計を理解する前に、プロトコルにおけるQoS 1およびQoS 2の送信プロセスを理解している必要があります。未確認の場合は以下を参照してください。
ここでは簡単にレビューし、各QoSでの再送信対象を示します。
QoS 1
QoS 1はメッセージを少なくとも1回配信する必要があるため、送信者が確認応答を受け取るまでMQTTプロトコル層でメッセージが継続的に再送信される可能性があります。
処理の模式図は以下の通りです:
PUBLISH
#1 送信者 ---------------> 受信者 (*)
PUBACK
#2 送信者 <--------------- 受信者- 2つのパケットが関与し、送信者と受信者で合計2回の送信動作があります。両パケットは同じPacketIdを保持します。
- 行末に*がある場合は、確認応答待ちがタイムアウトした際に送信者が再送信を開始する可能性を示します。
したがって、QoS 1メッセージはPUBLISHメッセージのみを再送信します。
QoS 2
QoS 2はメッセージを正確に1回だけ配信する必要があるため、より複雑な処理が必要です。処理の模式図は以下の通りです:
PUBLISH
#1 送信者 ---------------> 受信者 (*)
PUBREC
#2 送信者 <--------------- 受信者
PUBREL
#3 送信者 ---------------> 受信者 (*)
PUBCOMP
#4 送信者 <--------------- 受信者- 4つのパケットが関与し、送信者と受信者で合計4回の送信動作があります。これら4つのパケットはすべて同じPacketIdを保持します。
- 行末に*がある場合は、確認応答待ちがタイムアウトした際に送信者が再送信を開始する可能性を示します。
したがって、QoS 2メッセージはPUBLISHパケットとPUBRELパケットのみを再送信します。
まとめると:
- 再送信動作は、メッセージ送信後に指定時間内に期待する応答が得られなかった場合にトリガーされます。
- 再送信対象は以下の3種類のみです:
- QoS 1のPUBLISHパケット
- QoS 2のPUBLISHパケット
- QoS 2のPUBRELパケット
EMQXがPUBLISHメッセージの受信者として動作する場合、再送信操作は不要です。
インフライトウィンドウと最大受信値
この概念の定義と説明については、Inflight Window and Message Queueをご参照ください。
これらの概念を導入する目的は以下の通りです:
- EMQXが送信者として動作する場合、再送信されるメッセージはインフライトウィンドウに格納されているメッセージでなければならない。
- EMQXが受信者として動作し、送信者がメッセージを再送信した場合:
- QoS 1では、EMQXは直接PUBACKで応答する。
- QoS 2では、EMQXは最大受信メッセージキューに格納されたPUBLISHまたはPUBRELパケットを解放する。
メッセージの順序
上記の概念は理解するだけで十分ですが、特にQoS 1メッセージの再送信後のメッセージ順序の変化に注意が必要です。例として:
現在のインフライトウィンドウサイズが2に設定されている状態で、EMQXがクライアントに対して4つのQoS 1メッセージを配信しようとします。途中でクライアントプログラムまたはネットワークに問題が発生した場合、送信処理は以下のようになります:
#1 [4,3,2,1 || ] -----> []
#2 [4,3 || 2, 1] -----> [1, 2]
#3 [4 || 3, 2] -----> [1, 2, 3]
#4 [4 || 3, 2] -----> [1, 2, 3, 2, 3]
#5 [ || 4] -----> [1, 2, 3, 2, 3, 4]
#6 [ || ] -----> [1, 2, 3, 2, 3, 4]この6ステップのうち、左側はEMQXのメッセージキューとインフライトウィンドウを||で区切って示し、右側はクライアントが受信したメッセージの順序を示しています。各ステップの説明は以下の通りです:
- ブローカーが4つのメッセージをメッセージキューに格納。
- ブローカーが順に
1、2を送信し、インフライトウィンドウに格納。クライアントはメッセージ1にのみ応答。送信ストリームに問題があり、以降の応答は送信されない。 - ブローカーはメッセージ
1の応答を受信し、インフライトウィンドウから1を削除し、3を送信。引き続き2、3の応答を待つ。 - 応答待ちがタイムアウトし、ブローカーは
2、3を再送信。クライアントは再送信された2、3を受信し正常に応答。 - ブローカーは
2、3をインフライトウィンドウから削除し、4を送信。クライアントは4を受信し応答。 - すべてのメッセージ処理が完了。クライアントが受信したメッセージ順序は
[1, 2, 3, 2, 3, 4]で、順にMQTTプロトコルスタックの上位層に報告される。
重複メッセージが存在しますが、これはプロトコル仕様に完全に準拠しています。各メッセージの最初の出現は順序通りであり、繰り返し受信されたメッセージ2、3は再送信メッセージであることを示す識別ビットを持ちます。
MQTTプロトコルおよびEMQXはこのトピックをOrdered Topicとして扱います。詳細はMQTTv3.1.1 - メッセージの順序付けを参照してください。
これにより、同一トピックかつ同一QoSにおいてメッセージが順序通りに配信・応答されることが保証されます。
なお、ユーザーがすべてのトピックのQoS 1およびQoS 2メッセージを厳密に順序付けしたい場合、インフライトウィンドウの最大長を1に設定する必要がありますが、クライアントのスループットは低下します。
関連設定
以下は上記機構で使用されるすべての設定項目です。すべて設定ファイルに含まれています。
| 設定項目 | 型 | オプション値 | デフォルト値 | 説明 |
|---|---|---|---|---|
| mqueue_store_qos0 | bool | true, false | true | QoS 0メッセージをメッセージキューに保存するかどうか |
| max_mqueue_len | integer | >= 0 | 1000 | メッセージキューの長さ |
| max_inflight | integer | >= 0 | 0 | インフライトウィンドウのサイズ。デフォルト0は無制限を意味する |
| max_awaiting_rel | integer | >= 0 | 0 | 最大受信数。デフォルト0は無制限を意味する |
| await_rel_timeout | duration | > 0 | 300s | 最大受信での解放待機の最大タイムアウト値。超過するとメッセージは破棄される |