セッションとは
クライアントからサーバーへのMQTT接続要求が開始されてから、接続が終了するまでのメッセージのやりとりをセッションと呼びます。セッションは1つのネットワーク接続で完結する場合もあれば、(セッションが切れる前にクライアントが接続を再確立できれば)セッションは複数のネットワーク接続にまたがって存在する場合もあります。
MQTT v5では、セッションの有効期限は、クライアントのCONNECTパケット中にあるSession Expiry Interval
で設定されます。v5以前のプロトコルでは、セッションの有効期限に制限はなく、MQTTサーバーが実際の有効期限を決定していました。
セッションステートとは
MQTTでは、クライアントとサーバーは、クライアントIDに関する状態をセッションの有効期間中は保持する必要があり、これをセッションステートと呼びます。
クライアントは以下のセッションステートを保存している必要があります:
- サーバーに送信したが、受信確認が完了していないQoS 1/2のメッセージ
- サーバーから受信したが、受信確認が完了していないQoS 2メッセージ
サーバーは以下のセッションステートを保持している必要があります:
- セッションが存在するかどうか(他のセッションステートが存在しない場合も、このセッションステートは存在する)
- あるクライアントがsubscribeしているtopic
- クライアントに送信したが、受信確認が完了していないQoS 1/2のメッセージ
- 配信を待機しているQoS 0/1/2メッセージ(QoS 0はoptional)
- クライアントから受信したが、受信確認が完了していないQoS 2メッセージ、
Will
、Will Delay Interval
- セッションの有効期限
セッションステートが存在する理由
クライアントがネットワークの障害などで一時的に接続を中断し、セッションの有効期限が切れる前にサーバーとの接続を再確立した場合、クライアントは前回の接続で確立したsubscriptionを継続して使用することができます。低帯域で不安定なネットワーク環境では、ネットワークの中断が頻繁に起こる可能性があります。セッションステートを保存しておくことで、接続するたびにsubscriptionすることを避けることができ、再接続時のクライアントとサーバーのリソース消費を抑えることができます。サーバーは、クライアントが切断している間、クライアントに対する受信確認などが完了していないメッセージを保持します。これにより、メッセージが失われることを防ぐことができ、ユーザーがネットワークの障害に影響されにくくなります。
セッションの開始と終了
MQTT v5.0とv3.1.1では、セッションに大きな変更があります。MQTT v3.1.1には、接続時にクライアントが指定するClean Session
というフィールドのみ存在しています。このフィールドの値が1に設定されている場合、クライアントとブローカーはそれまでのセッションを破棄して新しいセッションを作成しなければならず、セッションのライフサイクルは一回のネットワーク接続に紐づけられることになります。値が0の場合、サーバーはクライアントとの通信を回復する際に、クライアントIDに紐づけられたセッションを使用しなければなりません(セッションが存在しない場合を除く)。この場合、クライアントとサーバーは、切断が起きた際にセッションステートを保持する必要があります。
MQTT v3.1.1では、保持されているセッションをいつ終了させるかは規定されていません。プロトコルレベルでは、セッションは永遠に存在します。しかし、これではサーバーのリソースを非常に多く占有することになるため、現実的ではありません。そのため、MQTTサーバーは通常、プロトコルに従って無限に保持するのではなく、設定からセッションの有効期限を制限することができるようになっています。
MQTT 5.0では、この問題が解決されています。Clean Session
フィールドが、Clean Start
とSession Expiry Interval
という二つのフィールドに分かれています。Clean Start
フィールドでは、セッションを新しく作るかを指定し、Session Expiry Interval
フィールドでは、セッションの有効期限を指定します。これらは接続時に指定されますが、クライアントは接続の終了時にSession Expiry Intervalフィールドを更新することができます。したがって、ネットワーク接続の異常によりクライアントが切断した場合はセッションを保持し、クライアントが正常にオフラインになったときにはセッションを終了させるということが簡単に実装できます。
クライアントはどのようにしてセッションが再開されたことを知るのか
クライアントが、以前に確立されたセッションの再開を期待して接続を開始する場合、サーバーに対応するセッションが存在するかどうかを知る必要があります。MQTTプロトコルはv3.1.1からCONNACKパケットにSession Presentというフィールドを用意しました。このフィールドは、現在使用しているセッションが新しいものかどうかを表すためのもので、クライアントはこのフィールドの値によって判断することができます。新しいセッションの場合、クライアントは接続確立後に再びトピックにsubscribeします。
注意
MQTTを使ったサービスを作る場合、クライアントIDとセッションの関連性に注意する必要があります。同じクライアントIDを異なるアプリケーションやユーザーが複数回使用する場合は、接続するたびに新しいセッションを要求するようにする必要があります。
セッションの保持が不要な場合は、サーバーによるリソースの占有を減らすために、セッションを即時失効に設定するべきです。
セッションの保持が必要な場合、セッションの有効期限を適切に設定します。時間を短く設定しすぎると、セッションの状態を保存する意味がなくなってしまいます。有効期限が長すぎると、サーバーのリソースを過剰に消費する可能性があります。