# インフライトとメッセージキュー

## はじめに

メッセージのスループットを向上させ、ネットワークの変動による影響を軽減するために、EMQXは複数の未アック済みのQoS 1およびQoS 2メッセージを同時にインフライト状態にすることを可能にしています。送信済みでまだ確認されていないこれらのメッセージは、アックが完了するまでインフライトウィンドウに保存されます。

インフライトウィンドウの最大数（`max_inflight`を参照）に達した場合、新たに到着したメッセージは即座に転送されず、一時的にメッセージキューに格納されます。

配信が再開されると、トピック優先度が無効の場合はEMQXはFIFO順にメッセージをデキューします。トピック優先度が有効な場合は、EMQXはトピックの優先度に従ってメッセージをスケジューリングし、各優先度内ではFIFO順を保持します。配信されたQoS 1およびQoS 2メッセージはインフライトウィンドウに追加されますが、配信されたQoS 0メッセージはインフライトウィンドウに入りません。

QoS 0メッセージは通常インフライトウィンドウをバイパスして即座に転送されます。インメモリセッションの場合、接続の送信キューが混雑するとEMQXは後続のQoS 0メッセージをメッセージキューに格納します。インフライトウィンドウが満杯でかつ`mqueue_store_qos0`が有効な場合も、EMQXはQoS 0メッセージをキューに入れて通常のキュースケジューリングに従わせます。接続が回復するかインフライトウィンドウに空きができると、EMQXはキューに入ったメッセージの配信を再開します。

トピック優先度ごとのメッセージキューが長さ制限に達すると、EMQXはまずその優先度の最も古いQoS 0メッセージを削除します。該当するQoS 0メッセージがない場合は、その優先度の最も古い残りのメッセージを削除します。トピック優先度が無効な場合はすべてのメッセージが同じ優先度を共有します。このポリシーにより、QoS 0のバースト時にもQoS 1およびQoS 2メッセージが進行しやすくなります。したがって、適切なメッセージキューの長さ制限を設定することが重要です。詳細は`max_mqueue_len`を参照してください。

メッセージキューは、サブスクライバーがオフラインであってもセッションが残っている間に到着したメッセージも保存します。サブスクライバーが再接続するとEMQXはこれらのメッセージを配信します。オフライン時のQoS 0メッセージの保存を除外するには、`mqueue_store_qos0`を`false`に設定してください。

なお、インフライトウィンドウとメッセージキューはグローバルではなく、EMQXは各クライアント接続ごとに別々のインフライトウィンドウとメッセージキューを割り当てます。

## インフライトウィンドウとReceive Maximum

MQTT v5プロトコルはCONNECTパケットに`Receive Maximum`属性を追加しており、その公式説明は以下の通りです。

> クライアントはこの値を使用して、同時に処理可能なQoS 1およびQoS 2のパブリッシュメッセージの最大数を制限します。サーバーが送信しようとするQoS 0のパブリッシュメッセージを制限する仕組みはありません。

つまり、サーバーはアックを待つ間に異なるメッセージ識別子を持つPUBLISHパケットをクライアントに連続して送信できますが、未アック済みメッセージ数が`Receive Maximum`の制限に達するまで送信を続けられます。

このことから、`Receive Maximum`は実質的にEMQXのインフライトウィンドウ機構と同じであることがわかります。ただし、EMQXはMQTT v5.0プロトコルがリリースされる前からこの機能をMQTTクライアントに提供していました。現在、MQTT v5.0プロトコルを使用するクライアントはReceive Maximumの仕様に従ってインフライトウィンドウの最大長を設定し、以前のバージョンのMQTTクライアントは設定に基づいて設定されます。

ただし、EMQXはCONNECTパケットで要求された`Receive Maximum`値を必ずしも許可するわけではありません。代わりに、CONNACKパケットで許可される`Receive Maximum`は`mqtt.max_inflight`設定によって上限が決まります。

## 設定項目

| 設定項目               | 型       | オプション値       | デフォルト値 | 説明                                                                                   |
| ---------------------- | -------- | ------------------ | ------------ | -------------------------------------------------------------------------------------- |
| mqtt.max_inflight      | integer  | (0, 65536)         | 32           | インフライトウィンドウの長さ制限。0は制限なし                                         |
| mqtt.max_mqueue_len    | integer  | [0, ∞)             | 1000         | メッセージキューの長さ制限。`0`は制限なし                                            |
| mqtt.mqueue_store_qos0 | enum     | `true`, `false`    | true         | クライアントがオフライン時、インメモリ接続の送信キューが混雑している時、またはインフライトウィンドウが満杯の時に、EMQXがQoS 0メッセージをメッセージキューに保存するかどうか |
