# 共有サブスクライブ

共有サブスクライブは、複数のサブスクライバー間でロードバランシングを実現するためのサブスクライブモードです。クライアントは複数のサブスクリプショングループに分割され、メッセージはすべてのサブスクリプショングループに転送されますが、各サブスクリプショングループ内では同時に1つのクライアントのみがメッセージを受信します。EMQXプラットフォームは、共有サブスクライブのプレフィックスとして2つの形式をサポートしています。グループ用共有サブスクライブ（`$share/<group-name>/`で始まる）と、グループ用でない共有サブスクライブ（`$queue/`で始まる）です。

以下に、2つの共有サブスクライブプレフィックス形式の例を示します。

| プレフィックス形式              | 例             | プレフィックス   | 実際のトピック名 |
| ------------------------------ | -------------- | -------------- | --------------- |
| グループ用共有サブスクライブ    | $share/abc/t/1 | $share/abc/    | t/1             |
| グループ用でない共有サブスクライブ | $queue/t/1     | $queue/        | t/1             |

クライアントツールを使用してEMQXプラットフォームに接続し、このメッセージングサービスを試すことができます。本ページでは共有サブスクライブの仕組みを紹介し、[MQTTX Desktop](https://mqttx.app/)を使ってクライアントをシミュレートし、共有サブスクライブ機能を試す方法を説明します。

## グループ用共有サブスクライブ

グループ用共有サブスクライブは、元のトピックにプレフィックス `$share/<group-name>` を追加することで有効にできます。グループ名は任意の文字列です。EMQXプラットフォームは異なるグループに同時にメッセージを転送し、同じグループに属するサブスクライバーはロードバランシングされた形でメッセージを受信します。

例えば、サブスクライバー`s1`、`s2`、`s3`がグループ`g1`のメンバーで、サブスクライバー`s4`、`s5`がグループ`g2`のメンバーであり、全てのサブスクライバーが元のトピック`t1`をサブスクライブしている場合、共有サブスクライブトピックはそれぞれ`$share/g1/t1`と`$share/g2/t1`となります。EMQXが元のトピック`t1`にメッセージ`msg1`をパブリッシュすると：

- EMQXは`msg1`をグループ`g1`と`g2`の両方に送信します。
- `s1`、`s2`、`s3`のうちのいずれか1つだけが`msg1`を受信します。
- `s4`と`s5`のうちのいずれか1つだけが`msg1`を受信します。

<img src="./_assets/shared_subscription_group.png" alt="グループ用共有サブスクライブ" style="zoom:50%;" />

## グループ用でない共有サブスクライブ

`$queue/`で始まる共有サブスクライブトピックは、グループに属さないサブスクライバー向けです。これは`$share`プレフィックスを使った共有サブスクライブトピックの特殊なケースと考えられます。すべてのサブスクライバーが`$share/$queue`のようなサブスクリプショングループに属していると理解できます。

<img src="./_assets/shared_subscription_queue.jpg" alt="グループ用でない共有サブスクライブ" style="zoom:50%;" />

## 共有サブスクライブとセッション

共有サブスクライブの概念とMQTTクライアントのパーシステントセッションの利用は矛盾しており、両方の機能を同時に使用することはできません。共有サブスクライブ機能を使用する場合は、クライアントの`clean_session`パラメータを`true`に設定してクリーンセッションを有効にする必要があります。

パーシステントセッション（`clean_session=false`）は、サブスクライバーが再接続後にメッセージを失うことなくデータフローを再開できることを保証し、信頼性の高いメッセージ配信に不可欠です。`clean_session`を`false`に設定すると、クライアントがオフラインになってもセッションは維持され、デバイスはメッセージを受信し続けます。しかし、デバイスがオフラインのため、受信したメッセージを即座に処理できず、セッション内にメッセージが蓄積される可能性があります。

共有サブスクライブが有効で、同じグループ内の別のデバイスがオフラインのデバイスのデータフローを引き継いだ場合、蓄積されたメッセージは元のデバイスのセッションに属するとみなされるため、引き継いだデバイスはそれらのメッセージを受け取りません。そのため、デバイスが長期間オフラインの場合、パーシステントセッションのメッセージバッファが溢れ、メッセージの損失が発生する恐れがあります。この状況はロードバランシングを妨げ、最終的にはメモリやストレージリソースの枯渇を招き、システムの安定性や全体的なパフォーマンスに悪影響を及ぼします。

パーシステントセッションの詳細については、[MQTT Persistent Session and Clean Session Explained](https://www.emqx.com/en/blog/mqtt-session)をご参照ください。

## MQTTXを使った共有サブスクライブのテスト

MQTTXを使ってクライアントのサブスクライブをシミュレートします。

* s1、s2はトピック`$share/g1/test`をサブスクライブ
* s3はトピック`test`をサブスクライブ

![shared_subscription_1](./_assets/shared_subscription_1.png)

MQTTXでクライアントP1を作成し、トピック`test`に3つのメッセージを送信します。

![shared_subscription_2](./_assets/shared_subscription_2.png)

s1がmsg1、msg2を受信し、s2がmsg3を受信、s3はすべてのメッセージを受信します。

![shared_subscription_3](./_assets/shared_subscription_3.png)
