# EMQX クラスタリング

EMQX クラスタリングとは、複数の EMQX ノードが連携して統一されたシステムとして動作する展開形態を指します。これらのノードはクライアントのセッション、トピックのサブスクリプション、およびルーティング情報を自動的に共有し、シームレスなメッセージ配信と水平スケーラビリティを実現します。

::: tip 注意

クラスタリング機能はトライアル期間中に利用可能です。トライアル期間終了後は商用ライセンスが必要であり、ライセンスがない場合は機能が無効化されます。

:::

本章では、[クラスタリングの利点](#why-use-emqx-clustering)、新しい[Mria と RLOG](./mria-introduction.md) アーキテクチャ、[クラスタの手動および自動作成方法](../../guides/cluster/create-cluster.md)、[ロードバランシングの実装方法](../../guides/cluster/lb.md)、およびクラスタ内の[通信セキュリティの確保方法](../../guides/cluster/security.md)について紹介します。

このアーキテクチャは、MQTT を基盤とした大規模かつミッションクリティカルな IoT およびメッセージングプラットフォームに最適です。

## 章の概要

本章では、EMQX クラスタリングの包括的な概要と実際の展開への適用方法を解説します。以下の内容を学べます：

- [クラスタリングの利点](#why-use-emqx-clustering)
- [EMQX クラスタリングの動作原理](#how-clustering-in-emqx-works)
- [Mria と RLOG アーキテクチャ](./mria-introduction.md)
- [クラスタの手動および自動作成方法](../../guides/cluster/create-cluster.md)
- [ノード間通信のセキュリティ確保方法](../../guides/cluster/security.md)
- [ロードバランシングの実装方法](../../guides/cluster/lb.md)
- [クラスタの負荷再分散とノードの退避方法](../../guides/cluster/rebalancing.md)
- [システムチューニングとパフォーマンステストの実施方法](../../guides/performance/overview.md)

高可用性の MQTT プラットフォーム構築や本番規模の準備に役立つガイドです。

## なぜ EMQX クラスタリングを使うのか

EMQX クラスタリングは、信頼性、スケーラビリティ、パフォーマンスを要求される大規模かつミッションクリティカルな用途向けに設計されています。主な利点は以下の通りです：

- **スケーラビリティ**：ノードを追加することで容易に展開を拡張でき、増加する MQTT クライアントやメッセージ数に対応しながらサービスの中断を防ぎます。
- **高可用性**：分散アーキテクチャにより単一障害点がなく、1台または複数のノードがオフラインになってもシステムは継続稼働します。
- **ロードバランシング**：MQTT トラフィックとクライアントセッションをノード間で分散し、ボトルネックを防ぎハードウェアの利用効率を最大化します。
- **集中管理**：すべてのノードを単一のダッシュボードまたは API エンドポイントから管理・監視でき、運用と保守を簡素化します。
- **データの一貫性とセキュリティ**：セッションやルーティング状態はノード間で自動的に複製され、一貫性を保ちつつクラスタ全体で安全な通信を維持します。

## EMQX クラスタリングの動作原理

EMQX クラスターは複数のノードで構成され、それぞれが EMQX のインスタンスを実行しています。これらのノードは連携してメッセージのルーティング、MQTT セッションの管理、高可用性とスケーラビリティを実現します。各ノードは他のノードと通信し、クライアントのサブスクリプションやルーティング情報を共有することで、どのノードに接続されているクライアントにもメッセージが確実に届くようにします。

この分散設計により、EMQX はダウンタイムを最小限に抑えつつ柔軟に拡張可能なミッションクリティカルなメッセージングシステムをサポートします。

### クラスターアーキテクチャの進化

#### EMQX 5.0 以前：Mnesia ベースのクラスタリング

初期の EMQX は Erlang/OTP の組み込みデータベース Mnesia とフルメッシュトポロジーを利用していました。各ノードは Erlang 分散プロトコル（デフォルトポート：4370）を使い、すべての他ノードと直接 TCP 接続を維持し、密結合のシステムを形成していました。

<img src="./assets/mnesia-cluster.png" alt="mnesia-cluster" style="zoom: 40%;" />

しかし、このモデルには以下の制約がありました：

- クラスタサイズの増加に伴う高い同期オーバーヘッド
- 5 ノード以上のクラスタでの不安定化リスク
- スケーラビリティの制限（主に垂直スケーリングで対応）

> EMQX 4.3 はベンチマークテストで 1,000 万の同時接続を達成しましたが、高度なチューニングと高性能ハードウェアが必要でした。詳細は[パフォーマンスレポート](https://www.emqx.com/en/resources/emqx-v-4-3-0-ten-million-connections-performance-test-report)を参照してください。

#### EMQX 5.0 以降：Mria + RLOG

バージョン 5.0 からは、新しい[Mria クラスターアーキテクチャ](./mria-introduction.md)が導入され、より大規模かつ安定したクラスタをサポートしています。

主な変更点は以下の通りです：

- **Core ノードと Replicant ノードの役割分担**：Core ノードは書き込み処理と完全なデータ複製を担当し、Replicant ノードは読み取り専用でクライアントセッションを処理します。
- **レプリケーションログ（RLOG）**：Core から Replicant への非同期かつ高スループットなデータ複製を可能にします。
- **スケーラビリティ**：1 クラスターあたり最大 1 億の MQTT 接続をサポートします。

<img src="./assets/EMQX_cluster.png" alt="EMQX_cluster" style="zoom:40%;" />

::: tip 注意

明確な上限はありませんが、EMQX オープンソース版ではクラスタサイズを 3 ノードに制限することを推奨します。Core タイプのノードのみで構成した小規模クラスタの方が安定性が高い傾向にあります。

:::

このアーキテクチャを支えるために、EMQX は Erlang/OTP とルーティングおよび配信のための内部データ構造群を利用しています。[Erlang/OTP の基礎](#erlangotp-foundation)および[クラスタデータ構造](#cluster-data-structures)の節で、ランタイムの基盤とこれらの構造のクラスタ内での動作を説明します。

### Erlang/OTP の基礎

EMQX は分散型の通信システム構築向けに設計されたランタイムおよびフレームワークである[Erlang/OTP](https://www.erlang.org/)上に構築されています。Erlang では各ランタイムインスタンスを **ノード** と呼び、`<name>@<host>` 形式の名前で識別します。例：`emqx1@192.168.0.10`。

Erlang ノードは TCP 経由で接続し、軽量メッセージパッシングで通信します。これが EMQX クラスタリングの基盤となっています。すべてのノードは同じ cookie を用いて認証を行い、接続と認証が完了するとノードは自動的に EMQX クラスターに参加します。EMQX 5.x 以降では、ノードの役割（Core または Replicant）がデータ複製やルーティングへの参加方法を決定します。

### クラスタデータ構造

分散クラスタ内で効率的にメッセージをルーティングするため、EMQX はサブスクリプションテーブル、ルーティングテーブル、トピックツリーという3つの主要な内部データ構造を使用しています。これらは連携して、クライアントが多数のノードに分散していてもメッセージが正しくサブスクライバーに届くようにします。

#### サブスクリプションテーブル（パーティション化）

各 EMQX ノードは、自身に直接接続されたクライアントの MQTT トピックとクライアントのマッピングを保持するローカルなサブスクリプションテーブルを管理します。データはパーティション化されており、各ノードは自分のクライアントのサブスクリプションのみを格納するため、オーバーヘッドが減りスケーラビリティが向上します。

メッセージがノードにルーティングされると、そのノードはサブスクリプションテーブルを参照して、どのローカルクライアントにメッセージを配信すべきか判断します。

例：

```
node1:
    topic1 -> client1, client2
    topic2 -> client3

node2:
    topic1 -> client4
```

この例では、同じトピック（`topic1`）に複数ノードでサブスクライバーが存在し、各ノードは独自のローカルマッピングを管理していることがわかります。

#### ルーティングテーブル（Core から複製）

ルーティングテーブルは、どのノードがどのトピックにサブスクライブしているかを追跡します。EMQX 5.x ではこのテーブルは Core ノードのみが管理・複製し、Replicant ノードは RLOG メカニズムを通じて読み取り専用コピーを受け取ります。

クライアントが任意のノード（通常は Replicant）でトピックをサブスクライブすると、そのイベントは Core ノードに転送され、クラスタ全体のルーティングテーブルが更新・複製されます。

例：

```
topic1 -> node1, node2
topic2 -> node3
topic3 -> node2, node4
```

#### トピックツリー（Core から複製）

トピックツリーは階層構造で、パブリッシュされたトピックとサブスクリプションパターン（[MQTT ワイルドカード](../../get-started/mqtt-basics.md#mqtt-topics-and-wildcards)の `+` や `#` を含む）を照合するために使用されます。これにより複雑なトピックフィルターの高速解決が可能です。

ルーティングテーブル同様、トピックツリーも Core ノードによって複製され、Replicant ノードと共有されます。新しいサブスクリプション（例：`client1` が `t/+/x` をサブスクライブ）を受けると、トピックツリーはすべてのノードで更新されます。更新は Core ノードで処理され複製されます。

トピックとサブスクリプションの例：

| クライアント | ノード  | サブスクライブトピック |
| ------------ | ------- | ----------------------- |
| client1      | node1   | t/+/x, t/+/y            |
| client2      | node2   | t/#                     |
| client3      | node3   | t/+/x, t/a              |

これらのサブスクリプションに基づき、EMQX は以下のトピックツリーとルーティングテーブルを構築します：

<img src="./assets/cluster_2.png" alt="image" style="zoom:67%;" />

#### メッセージ配信フロー

MQTT クライアントがメッセージをパブリッシュすると、そのクライアントが接続しているノード（Core または Replicant）はトピックツリーを使い、メッセージのトピックとすべてのサブスクリプションパターンを照合します。次にルーティングテーブルを参照し、該当するサブスクライバーがいるノードを特定してメッセージを転送します（複数ノードに転送される場合もあります）。受信した各ノードはローカルのサブスクリプションテーブルを参照し、該当するクライアントにメッセージを配信します。

例として、**Client 1** がトピック `t/a` にメッセージをパブリッシュした場合のノード間のルーティングと配信は以下の通りです：

1. **Client 1** は **Node 1** に接続し、トピック `t/a` でメッセージをパブリッシュします。

2. **Node 1** はトピックツリーを参照し、`t/a` がサブスクリプションパターン `t/a` および `t/#` にマッチすることを確認します。

3. **Node 1** はルーティングテーブルを参照し、

   - **Node 2** に `t/#` をサブスクライブするクライアントがいること、
   - **Node 3** に `t/a` をサブスクライブするクライアントがいること

   を特定し、両ノードにメッセージを転送します。

4. **Node 2** はメッセージを受信し、ローカルのサブスクリプションテーブルを参照して `t/#` をサブスクライブするクライアントに配信します。

5. **Node 3** も同様にメッセージを受信し、`t/a` をサブスクライブするクライアントに配信します。

6. メッセージ配信が完了します。

EMQX クラスタリングの詳細な動作理解には、[EMQX クラスタリングの設計](../design/clustering.md)もご参照ください。

## クラスタリング機能の概要

EMQX は、ネイティブの Erlang 分散システムを拡張した[Ekka](https://github.com/emqx/ekka) ライブラリにより、以下の高度なクラスタリング機能を提供します。これにより、自動ノード検出、動的クラスタ形成、ネットワークパーティションの処理、ノードのクリーンアップなどが可能になります。

### ノード検出と自動クラスタリング

EMQX は複数のノード検出メカニズムをサポートし、多様な展開環境でクラスタを自動形成できます：

| 戦略       | 説明                                 |
| ---------- | ------------------------------------ |
| `manual`   | コマンドによる手動クラスタ作成       |
| `static`   | 静的ノードリストによる自動クラスタリング |
| `DNS`      | DNS の A レコードおよび SRV レコードによる自動クラスタリング |
| `etcd`     | etcd を利用した自動クラスタリング    |
| `k8s`      | Kubernetes による自動クラスタリング  |

詳細は[クラスタの作成と管理](../../guides/cluster/create-cluster.md)をご覧ください。

### ネットワークパーティションの自動修復

ネットワークパーティション自動修復は、EMQX がネットワーク分断から手動介入なしに自動復旧する機能であり、ダウンタイムが許されないミッションクリティカルな用途で有用です。

この機能は `cluster.autoheal` 設定で制御され、デフォルトで有効です。

```bash
cluster.autoheal = true
```

有効時、EMQX はクラスタ内ノード間の接続状態を継続的に監視します。ネットワークパーティションを検知すると、影響を受けたノードを分離し、残りのノードで稼働を継続します。パーティションが解消されると、分離されたノードを自動的にクラスタに再統合します。

パーティション検知および復旧時に生成されるログメッセージやアラームについては、[Mria ログとアラーム](../../guides/observability/mria-alarms.md)を参照してください。

### クラスタノードの自動クリーンアップ

クラスタノード自動クリーンアップ機能は、切断されたノードを設定された時間経過後に自動的にクラスタから削除します。この機能によりクラスタの効率的な運用が維持され、時間経過によるパフォーマンス低下を防止します。

デフォルトで有効であり、`cluster.autoclean` 設定（デフォルト：`24h`）で制御されます。

```bash
cluster.autoclean = 24h
```

### ノード間のセッション共有

EMQX はノード間のセッション永続化をサポートし、クライアントが一時的に切断してもセッションとサブスクリプションを保持します。

この機能を有効にするには：

- **MQTT 3.x クライアント**：`clean_start = false` を設定
- **MQTT 5.0 クライアント**：`clean_start = false` かつ `session_expiry_interval > 0` を設定

これにより、クライアントが切断時に関連付けられたクライアントIDの以前のセッションデータが保持されます。再接続時に EMQX は前回のセッションを再開し、切断中にキューイングされたメッセージを配信し、サブスクリプションも維持します。

## ネットワーク要件

EMQX クラスタの最適なパフォーマンスを確保するため、ネットワークのレイテンシは 10 ミリ秒未満が望ましいです。100 ミリ秒を超える場合、クラスタは利用できなくなります。

Core ノードは同一のプライベートネットワーク内に配置する必要があります。Mria+RLOG モードでは、Replicant ノードも同一プライベートネットワーク内に配置することが推奨されます。

## 次のステップ：EMQX クラスタの作成

以下のセクションを続けて読み、EMQX クラスタの作成方法を学べます：

- [クラスタアーキテクチャ](./mria-introduction.md)
- [クラスタの作成](../../guides/cluster/create-cluster.md)
- [クラスタのセキュリティ](../../guides/cluster/security.md)
