おそらく最初に明確にするポイントは、メッセージIDがクライアントごとおよび方向ごとに処理されることです。つまり、ブローカーは、接続されているクライアントごとにQoS> 0の送信メッセージごとにメッセージIDを作成し、これらのメッセージIDは、他のクライアントに公開された同じメッセージに使用される他のメッセージIDから完全に独立します。同様に、各クライアントは、送信するメッセージに対して独自のメッセージIDを生成します。
メッセージIDは一意である必要はないため、QoSレベル2で1時間に15メッセージを送信するクライアントは、ある時点でオーバーフローするだけです。実際の制限は、「飛行中」の方向ごとに一度に最大65535のメッセージしか存在できないことです(つまり、メッセージハンドシェイクの途中)。指定されたIDのメッセージが完全に処理されると、そのメッセージIDを再利用できます。
別の見方をすれば、メッセージの送信速度が原因であろうと、メッセージの処理方法の設計によるものであろうと、クライアントが一度に1つのメッセージしか送信しなかった場合にどのように機能するかを検討することです。この場合、重複する可能性は決してないため、メッセージごとにメッセージIDを1に設定しておくことができます。
一度に複数のメッセージを送信することをサポートしたい場合は、新しいメッセージを割り当てる前に、メッセージIDの重複がないことを確認するのは比較的簡単です。
メッセージIDはクライアントごとであるため、1つのメッセージを> 65535クライアントに送信する場合、メッセージIDが衝突する可能性はありません。一度に各クライアントに65535を超えるメッセージを送信し、メッセージフローが完了しない場合は、問題が発生します。
「すべてのMQTTブローカーが最後のQoS1/2メッセージのみを配信する傾向があることに気づきました」というコメントに答える:
ブローカーは、知っているクライアントにのみメッセージを送信します。初めて接続する場合、保持されたメッセージという1つの例外を除いて、過去のメッセージを取得する方法はありません。メッセージが保持されるように設定されている場合、それは「最後の既知の正常な」値です。新しいクライアントがサブスクライブすると、保持されたメッセージがすぐに送信されるため、更新頻度の低いものに役立ちます。これがあなたが言及していることだと思います。クライアントが接続されていないときにメッセージをキューに入れたい場合は、「クリーンセッション」オプションを無効にして接続し、クライアントを永続化する必要があります。また、QoS>0サブスクリプションおよびQoS>0パブリケーションを使用する必要があります。クライアントが再接続すると(クリーンセッションが無効に設定されたまま)、キューに入れられたメッセージが配信されます。通常、ブローカーでこの方法でキューに入れるメッセージの数を構成できます。これ以降のメッセージは破棄されます。重要な点は、以前に接続したことがないクライアントのキューイングメッセージは設計上サポートされていないということです。