# 部署架构与集群要求

自 EMQX 5.0 起，引入了全新的 [Mria](https://github.com/emqx/mria) 集群架构，并重构了数据复制逻辑，使 EMQX 的水平扩展能力获得指数级提升。这也是 EMQX 5.0 单个集群能够支持 1 亿 MQTT 连接的关键因素之一。

本页将介绍新架构下 EMQX 集群部署模型，以及部署过程中需要注意的事项。如需实现集群的自动化部署，可参考 [EMQX Kubernetes Operator](https://www.emqx.com/zh/emqx-kubernetes-operator) 和[配置 EMQX Core 与 Replicant 节点](https://docs.emqx.com/zh/emqx-operator/latest/tasks/configure-emqx-core-replicant.html)。

:::tip 前置知识准备

建议先了解 [EMQX 集群](./introduction.md)。
:::

## Mria 架构简介

Mria 是对 Erland 原生数据库 Mnesia 的开源扩展，支持最终一致性的数据复制。启用异步方式同步事务日志后，EMQX 节点之间的连接模式从 Mnesia 的**全网状拓扑**结构转向 Mria 的**网状+星型**状拓扑结构。

<img src="./assets/emqx-mria.png" alt="EMQX Mria 架构" style="zoom:25%;" />

### 节点角色说明

集群中节点可以按角色分为**核心节点（Core）**或**复制节点（Replicant）**。

#### 核心节点

核心节点作为数据库的数据层，节点间以全网状连接。每个节点都包含一个最新的数据副本，这保证了容错性：只要有一个节点存活，数据就不会丢失。核心节点一般是静态和持久的，不建议进行自动伸缩（即经常添加、删除或替换节点）。

#### 复制节点

复制节点会连接到核心节点，并被动地复制来自核心节点的数据更新。复制节点不允许执行任何写操作，而是将其转交给核心节点代为执行。同时，由于复制节点有一个完整的本地数据副本，因此数据读取速度非常快，有助于降低 EMQX 路由的时延。

### Mria 架构的优势

Mria 架构融合了“无主复制”与“主从复制”的优点，具有以下优势：

- 更高的水平可扩展性：EMQX 5.0 已能支持包含 23 个节点的大规模集群。
- 更轻松的集群自动扩展：通过复制节点的自动伸缩简化集群的自动扩展。

相比 4.x 版本所有节点采用全连接的方式，节点数量越多节点之间完成数据同步的成本就越高，EMQX 5.0 中由于复制节点不参与数据写入，当更多的复制节点加入集群时，表的更新效率不会受到影响，进而允许创建更大的 EMQX 集群。

另外，复制节点被设计成可以按需增删，添加或删除它们不会改变数据冗余，所以它们可以被放在一个自动伸缩组中，从而实现更好的 DevOps 实践。

> **注意**：随着总数据量的增大，从核心节点初始化复制数据是一个相对繁重的操作，所以复制节点的自动伸缩策略不能太过于激进。

## 部署架构

若未进行角色配置，所有节点都默认作为核心节点运行，兼容 4.x 版本的部署方式，方便用户迁移与上手。

只有集群规模超过 7 个节点，才建议使用 Core + Replicant 架构。

:::tip

集群中至少要有一个核心节点，我们建议设置 3 个核心节点 + N 个复制节点作为初始集群规格。

:::

节点角色如何分配，应结合实际业务需求与集群规模考虑：

| 场景                        | 建议部署方式                                                 |
| --------------------------- | ------------------------------------------------------------ |
| 小型集群（7 个节点或更少）  | 没有必要使用 Core + Replicant 复制模式，所有节点作为核心节点承载 MQTT 连接。 |
| 中型集群                    | 核心节点是否承载 MQTT 连接取决于许多因素，需要根据实际的场景测试选择。 |
| 大型集群（10 个节点或更多） | 核心节点不承载 MQTT 连接，仅作为数据库使用，复制节点承载连接，以提高稳定性和水平扩展性。 |

## 启用 Core + Replicant 模式

要启用 Core + Replicant 模式，需要将某些节点指定为复制节点。这可以通过设置 `node.role` 参数为 `replicant` 来实现。此外，您需要启用一个自动集群[发现策略](./create-cluster.md#节点发现)（`cluster.discovery_strategy`）。

:::tip
Replicant 节点不能使用 `manual` 策略来发现 Core 节点集群。
:::

配置示例：

```bash
node {
    ## 将节点设置为复制节点：
    role = replicant
}
cluster {
    ## 启用静态发现策略：
    discovery_strategy = static
    static.seeds = [emqx@host1.local, emqx@host2.local]
}
```

## 网络与硬件要求

### 网络

- 核心节点之间的网络延迟应 **小于 10ms**，超过 **100ms** 可能导致集群不可用。
- 强烈建议将核心节点部署在同一私有网络中。
- 复制节点与核心节点之间也建议部署在同一私有网络，但网络质量要求略低。

### CPU 与内存

核心节点需要较大的内存，在不承接连接的情况下 CPU 消耗较低。复制节点硬件配置与 4.x 一致，可按连接和吞吐配置估算其内存要求。

## 故障处理机制

- **核心节点故障**：复制节点会自动连接到其他存活的核心节点，此过程中客户端不会掉线，但可能导致路由更新延迟。
- **复制节点故障**：所有连接到该节点的客户端会被断开，但由于复制节点是无状态的，所以不会影响到其他节点的稳定性，如果客户端设置了重连机制（大多数客户端库都默认支持），客户端将重新连接至另一个复制节点。

## 集群监控和故障排查

<!-- TODO 后续补充数值类型 Gauge or Counter -->

EMQX 提供完善的监控能力，您可以通过 Prometheus 指标 或 Erlang 控制台命令来跟踪 Mria 的运行状态与性能。

### Prometheus 系统指标

#### 核心节点

| 指标名                             | 含义说明                                                     |
| ---------------------------------- | ------------------------------------------------------------ |
| `emqx_mria_last_intercepted_trans` | 自节点启动以来，分区收到的事务数量。注意，这个值在不同的核心节点上可能不同。 |
| `emqx_mria_weight`                 | 一个用于负载平衡的值，它的变化取决于核心节点的瞬间负载。     |
| `emqx_mria_replicants`             | 连接到核心节点的复制节点数量。                               |
| `emqx_mria_server_mql`             | 等待发送至复制节点的未处理的事务数量。这个指标越少越好，如果指标有增长的趋势，则可能需要为当前的核心节点增加算力资源，或添加更多的核心节点。 |

#### 复制节点

| 指标名                         | 含义说明                                                     |
| ------------------------------ | ------------------------------------------------------------ |
| `emqx_mria_lag`                | 复制节点滞后情况，表示复制节点滞后上游核心节点的程度，数值越低越好。 |
| `emqx_mria_bootstrap_time`     | 复制节点启动花费时间，这个值在复制节点的正常运行过程中不会变化。 |
| `emqx_mria_bootstrap_num_keys` | 在初始复制过程中从核心节点复制的数量，这个值在复制节点的正常运行中不会变化。 |
| `emqx_mria_message_queue_len`  | 复制进程的消息队列长度，应该一直保持在 0 左右。              |
| `emqx_mria_replayq_len`        | 复制节点内部重放队列长度，越少越好。                         |

### Erlang 控制台命令

执行 `emqx ctl eval 'mria_rlog:status().'` 命令，获得更多关于嵌入式数据库状态的信息。

如需进一步了解 Mria 架构的实现细节或调优建议，请参阅：[集群设计原理](../../design/clustering.md)。
