EMQX 跨域集群:增强可扩展性,打破地域限制

跨域集群的概念

提到 EMQX,人们通常首先会想到它的可扩展性。尽管 EMQX 能随着硬件数量的增加几乎实现线性扩展,但在单个计算实例上的扩展能力终究有限:资源总会耗尽,升级成本也会急剧上升。这时,分布式部署就显得尤为重要。通过在多个计算实例上部署 EMQX 集群节点,可以进一步扩展其能力。得益于 EMQX 强大的集群功能,这项任务变得相对简单。

通过分布式部署,我们不再局限于单一地理位置。我们甚至可以在不同大洲的多个数据中心部署 EMQX 集群,这个过程称为跨域集群(Geo-Distribution)。跨域集群的主要优势在于,当客户端分布在世界各地时,可以让它们连接到最近的 EMQX 实例,从而获得更低的延迟和更高的可靠性,提高整体吞吐量。另一个显著的优势是增强了容错性:如果某个数据中心出现故障,影响的只是部分服务,而不是整个系统。

挑战

然而,任何分布式部署都会带来成本,跨域集群尤其如此。

  1. 实例之间通过网络连接,网络速度相对较慢。

    虽然网络速度并不算非常慢,但比起同一实例上 CPU 核心之间的通信还是要慢得多,后者的延迟以纳秒计,网络引入了延迟。实例之间的距离越远,延迟就越高,这是物理定律使然,我们无法改变,因此,需要在某些方面做出妥协。如果我们希望更靠近某些客户端(他们可能在澳大利亚也可能在巴西),那么有些 EMQX 节点之间的距离必然会增加,导致它们之间的通信速度变慢。在这种情况下,延迟可能会达到几十毫秒。

  2. 网络不够可靠。

    数据包会丢失,连接会因网络拥塞、硬件故障、配置错误甚至恶意活动而中断。两个 EMQX 节点之间距离越远,中间需要经过的网络设备和传输电缆就越多,出现故障的几率就越大。虽然其中一些问题可以通过网络协议栈处理,只会表现为有较高的延迟,但有些问题会影响到应用层,带来许多不确定性。在出现这种故障时,EMQX 节点无法判断是某个远程节点宕机,还是网络异常。这就是所谓的部分故障,可能导致可用性降低。

严格来说,当我们谈论延迟时,还需要考虑吞吐量。即使高延迟网络也可以具有很高的吞吐量,但网络的不可靠性通常会影响高吞吐量的实现。在 TCP 连接中,即使是单个数据包丢失也会显著降低吞吐量,因为 TCP 协议栈需要重新传输数据包,并大幅缩小传输窗口。而且,通信双方距离越远,这种情况发生的频率就越高。

更糟糕的是,原始网络吞吐量对许多客户端来说并不重要。相反,通过 MQTT 协议进行的各种操作的吞吐量才是最重要的,例如消息发布的吞吐量或 SUBSCRIBE 操作的吞吐量。这就是共享状态发挥作用的地方,更重要的是,需要协调这种状态的更新。

由于 MQTT 协议的异步特性,客户端相对独立,因而共享状态的问题并不明显,但它依然存在。为了更好地理解这个问题,让我们首先从设置一个基本的跨域 EMQX 集群开始。

一个跨越 12600 公里的集群

EMQX 5 采用了一种新的部署模型,即集群由两种类型的节点组成:核心节点和复制节点。这种设计旨在支持更广泛的部署场景(包括跨域集群),但也存在一些隐患,我们稍后将对此进行探讨。在这个模型中,核心节点负责管理共享状态的关键部分,而复制节点则只复制核心节点的状态更改,不参与状态管理。

为了更好地理解新模型的优势,我们首先以传统的方式部署一个集群。这个“传统”集群由分布在三个大洲的三个核心节点组成:

位置 节点名称
法兰克福 (eu-central-1) emqx@euc1.emqx.dev
香港 (ap-east-1) emqx@ape1.emqx.dev
开普敦 (af-south-1) emqx@afs1.emqx.dev

EMQX Geo-Distribution 1

以下是集群的配置片段,我们可以通过该配置片段更好地理解问题的复杂性,并展示说明我们所做的改进:

broker.routing.storage_schema = v1  # 使用 5.4.0 之前的路由表架构

首先,集群从启动到开始运行所需的时间就暗示这不是个好的方式。日志显示,某些 mria 初始化步骤需要整秒才能完成。

15:11:42.654445 [notice] msg: Starting mria, mfa: mria_app:start/2
15:11:42.657445 [notice] msg: Starting shards, mfa: mria_app:start/2
15:11:47.253059 [info] msg: Setting RLOG shard config, mfa: mria_config:load_shard_config/2, shard: '$mria_meta_shard', tables: ['$mria_rlog_sync',mria_schema]
15:11:48.714293 [info] msg: Setting RLOG shard config, mfa: mria_config:load_shard_config/2, shard: emqx_common_shard, tables: [bpapi,emqx_app,emqx_banned,emqx_trace]
15:11:50.188986 [info] msg: Setting RLOG shard config, mfa: mria_config:load_shard_config/2, shard: emqx_cluster_rpc_shard, tables: [cluster_rpc_commit,cluster_rpc_mfa]
15:11:51.662162 [info] msg: Setting RLOG shard config, mfa: mria_config:load_shard_config/2, shard: emqx_cluster_rpc_shard, tables: [cluster_rpc_commit,cluster_rpc_mfa]
...

为什么会这样?这些节点之间的距离其实并不算远。从 ping 时间中可以看出这一点。

v5.7.0(emqx@euc1.emqx.dev)> timer:tc(net_adm, ping, ['emqx@afs1.emqx.dev']).
{161790,pong}
v5.7.0(emqx@euc1.emqx.dev)> timer:tc(net_adm, ping, ['emqx@ape1.emqx.dev']).
{202801,pong}

确实,数据包从法兰克福到开普敦再返回需要大约 160 毫秒,到香港再返回需要大约 200 毫秒。这是因为 mria 在底层使用 mnesia,而 mnesia 是一个分布式数据库。每个初始化步骤本质上都是一个数据库事务,而每个事务都需要在大多数节点之间进行协调。而每个协调步骤都需要在参与节点之间进行多次往返。在这种情况下,共享状态是数据库模式,这种协调对于确保集群中所有节点的模式一致性是必要的。

考虑到这一点,让我们看看这如何影响单个操作的性能:SUBSCRIBE

延迟的影响

经过几分钟的等待,集群启动成功并可以正常工

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值