🤖

MQTT の Session State についてざっくり理解する

2024/05/02に公開

Session とは何か

Client Identifier(クライアントID)で識別される、クライアントとの接続を一意に表す概念。つまり、同じクライアントIDの接続が2つ以上同時に存在することはできない[1]

Session State とは何か

文字通り、Sessionの状態を指す。以下の2つの状態がある。

  • サブスクライブ状態
    クライアントがどのトピックをどのQoSでサブスクライブしているか、という情報の集合。
  • 未完了のパブリッシュ・シーケンスの状態
    PUBLISHパケットやPUBRELパケットを送信したが、その応答パケットが返ってきていない、という情報の集合。これは、QoS1QoS2にのみ適用される。

ブローカーは、以下の2つのいずれかの条件を満たすとき、Session Stateを維持する。

  • クライアントが接続されている
  • クライアントが切断されているが、Session Stateの有効期限が切れていない

有効期限の設定方法

MQTTのバージョンで違いがある。

MQTT V3.1.1の場合

そもそも有効期限の規定がない。
CONNECTパケット送信時にConnect FlagsCrean Session0を指定することで、以前のSessionがあればそのSessionが使用される。1を指定した場合は、それまでのSessionは破棄され新しいSessionが作成される。

MQTT V5.0の場合

MQTT V3.1.1のCrean SessionはMQTT V5.0ではCrean Startに変更されている。また、CONNECTパケットのSession Expiry Intervalのプロパティに秒数を指定することで設定できる。
Session Expiry Interval

  • 省略されたとき
    0扱いとなる。
  • 0のとき
    ブローカーはクライアントとの切断後にSession Stateを維持しない。
  • 0でないとき
    ブローカーはクライアントとの切断後も指定された秒数だけSession Stateを維持する。
  • 0xFFFFFFFFのとき
    Session Stateの有効期限は無期限という扱いになる。

動作イメージ

クライアントAとブローカーの間で以下のようなやり取りが行われる:

  1. クライアントAがブローカーに接続する際、CONNECTパケットを送信し、Session Expiry Intervalを例えば300秒に指定する。これにより、クライアントAとブローカー間の接続が切断された後も、ブローカーはクライアントAのSession Stateを300秒間維持するようになる。

  2. クライアントAは/hello/worldというトピックをSubscribeする。ブローカーは、クライアントAのSession Stateを維持する。このSession Stateには、クライアントAがSubscribeしているトピック(/hello/world)の情報が含まれている。

  3. その後、何らかの理由でクライアントAとブローカー間の接続が切断されたとする。この時点から、ブローカーはクライアントAのSession Stateを300秒間維持し続ける。

  4. 接続が切断されている間に、別のクライアントであるクライアントBが/hello/world宛てのメッセージをPublishしたとする。ブローカーは、クライアントAのSession Stateを維持しているため、このメッセージを破棄せずに保持する。

  5. 300秒が経過する前にクライアントAがMQTTブローカーに再接続すると、ブローカーは維持していたクライアントAのSession Stateを再利用する。これにより、クライアントAは以前にSubscribeしていたトピック(/hello/world)を再度Subscribeする必要がなくなる。また、ブローカーが保持していたメッセージ(クライアントBがPublishしたメッセージ)がクライアントAに配信される。

このように、Session Expiry Intervalを設定することで、一時的な接続の切断があっても、クライアントとブローカー間のSession Stateが維持され、メッセージの損失を防ぐことができる。

参考

脚注
  1. AWS IoTのブローカーの場合、あるクライアントIDを持つクライアントAがブローカーに接続している状態で同一のクライアントIDを持つクライアントBが接続すると、元々接続していたクライアントAの接続が切断される、という動作をする。 ↩︎

Discussion