百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

EMQ X VS RabbitMQ:两大消息服务器 MQTT 性能对比结果全解析(下)

bigegpt 2024-08-01 11:54 6 浏览

之前的文章中,我们采用相同的硬件资源分别对 MQTT 消息服务器 EMQ X 和 RabbitMQ 进行了压力测试。结果表明:在「多对一」 场景中,EMQ X 和 RabbitMQ 相比并没有太大差别;而在「一对多」场景中,RabbitMQ 则较 EMQ X 产生了较为明显的差距。

本期文章,我们将对这一结果进行进一步的解析。

造成差距的原因主要有三个:节点间通讯的方式、消息流架构的方式、队列的使用。

节点间的通讯

RabbitMQ - 委托架构

RabbitMQ 使用了 Erlang 语言的分布式连接,即每个节点之间两两互相连接,每个节点用一个单一的链接连接着另一个节点。在图中的情况下,三个节点依次连接;当节点之间需要通信时,一条消息需要通过这个单一连接从一个节点发送到另一节点。

在扇出(fan-out)的例子中,正常来讲你需要将消息推送到所有节点的队列上。RabbitMQ 使用的优化方式则是:你的消息只需要发送一次,之后其内置的代理委托框架会将这一条消息派送并且发到其他节点的队列上。这个过程中,消息是有序发送的,所以保证了消息在不同队列里都是相同的顺序。

但是这个方案也不是十全十美的,因为你会将所有的消息只发送一次,在分发工作都依靠同一个委托进程。而且 RabbitMQ 选择这个代理进程的策略是根据发布者的哈希算法。所以,当如果你只有一个发布者,所有的消息都会被一直推送到单个的委托代理进程。


EMQ X - Gen_RPC

在 EMQ X 中有个精妙的设计:其不仅存在着分布式连接,还存在着 Gen_RPC。分布连接和 Gen_RPC 各司其职,前者用于交换 Mnesia 的数据信息,后者则只适用于消息的转发。每当你需要从一个节点向另一个节点发布一个消息的时候,EMQ X 不是重新自动生成新的节点间连接(默认 1 个连接),再通过这些新的连接去处理把一个消息从一个节点推送到另一个节点的工作。而是依靠针对此场景特地设计的,专有的 Gen_RPC 连接来处理这个消息推送的工作。所以在扇出(一对多)的例子中,这些链接会被完全有效地利用。

但这种设计在网络分区环境中其性能有可能受到影响,RabbitMQ 节点之间只有一个分布式连接,所以当连接断开造成脑裂时,愈合修复的工作将会更简单。

消息流

MQTT 插件

RabbitMQ 在使用 MQTT 插件后会监听使用 MQTT 协议发布的消息。得到消息之后,消息被解析,之后再通过 AMQP 协议进行转化,最后才会被发送到 RabbitMQ 上。

如果要发送一条消息,需要经过套接字后进入 mqtt_reader,接下来再进入下图所示的所有过程。然而如果要在同一条通道里同时接收刚刚发送的这条消息,所有上图所示的过程则需要反着重新进行一次,包括 mqtt_reader。其中,mqtt_reader 不仅负责了读,也负责了写。

AMQP

AMQP 场景则不同,每条消息都被一个 reader 读取,一个 writer 写入。这两条通道读写独立,reader 只负责读内容,而 writer 只负责写内容,它们各司其职、相互独立。而唯一的通道 channel 则是一个主 Erlang 进程,其负责着消息的交换。

可见 RabbitMQ 在 MQTT 场景中存在的明显的设计问题会导致性能下降,那么如果引入 AMQP 模式的 RabbitMQ 测试用例将会如何呢?将 RabbitMQ 调制成使用 MQTT 插件的和使用单一 AMQP 的模式使用,再对比 EMQ X 在压力测试下的情况,可以看出 EMQ X 在所有测试中仍是更胜一筹,但总体来说使用 AMQP 模式的 RabbitMQ 要比自己原有的成绩更好。

  • 多对一

此场景中 RabbitMQ 与 EMQ X 已经有了接近的性能表现。

  • 一对多

但如果在 fan-out(一对多)场景里,EMQ X 仍然具有显著优势,但 RabbitMQ(AMQP)的差距已经明显缩小。

队列

以上的测试均使用了 QoS 1 的消息。当发送 QoS 1 的消息时,这些消息每次都要作为可持久化的备份保存在硬盘上。所以队列空间的使用也尤为重要。

RabbitMQ

RabbitMQ 成熟地使用了一个默认的队列空间执行方式(可以被替换成其他队列使用)。这个可变队列在消息的持久度和给客户端发送消息的时延里做了均衡。但是在最坏的情况下,一个消息可能会被存入内存。不过这也帮助了 RabbitMQ 在崩溃重启之后可以让服务器再上线,并且所有的客户端还可重连且收到原来持久化的消息。

EMQ X

EMQ X 对队列的实现方式非常简单,即在内存中使用了优先队列。如果发来的消息无法推入接收者的队列,则这个消息会被丢掉。在 EMQ X 中,只有用一些其他持久化的插件才能使消息持久化保存,这些功能在商业版中提供。

EMQ X 的设计初衷是将接入层独立,所以将消息持久化的问题留给了后端完成。这一问题在未来具有持久性会话的版本中会解决(persistence session)。

节流

RabbitMQ - 控流

RabbitMQ 采用了一种比较有名的控流机制,它给每一个流程了一个信用值,如下图所示。假设说我们的服务端接收到了一个消息并由 reader 进行了读取后,这条消息被送到 channel。这个过程将会消费掉 reader 和 channel 的相应的信用值。这样一来,就可以通过使两方信用值保持匹配同步的方法实现不超额的发送了。

这其实是一个不错的解决方案。设想我们有许多的用户,即有许多的队列,每发送一条消息就意味着将要将这条消息分发给许多的队列,这会严重影响 RabbitMQ 实例。然而,这一套流程会阻止 RabbitMQ 再继续读取接收缓冲区的消息——因为发送缓冲区已经快满了!

EMQ X - 限流

EMQ X 的节流主要是靠限制读取一方的流量去实现的。首先,根据预设,将会一次从套接字内读取 200 条消息。当这些消息被完全收到了之后才会逐个将他们处理。一旦套接字报告它已经到达了读取一方的最大限额,它将会检查有发布者的数量和已经被阅读的字节数量,并根据这个数值去休眠一段时间。接收缓冲区最终会被填满,发布者根据 TCP 协议中飞行窗口的要求也将不会再发布任何内容。

总结

以上就是这个横向评测的结果和分析。最终的赢家很难断言,但是如果就服务器的性能上来讲,EMQ X 肯定是略胜一筹的。不过 RabbitMQ 也有它独特的优势。

EMQ X 的设计原则

EMQ X 在设计上,首先分离了前端协议 (FrontEnd) 与后端集成 (Backend),其次分离了消息路由平面 (Flow Plane) 与监控管理平面 (Monitor/Control Plane):

  1. EMQ X 核心解决的问题:处理海量的并发 MQTT 连接与路由消息。
  2. 充分利用 Erlang/OTP 平台软实时、低延时、高并发、分布容错的优势。
  3. 连接 (Connection)、会话 (Session)、路由 (Router)、集群 (Cluster) 分层。
  4. 消息路由平面 (Flow Plane) 与控制管理平面 (Control Plane) 分离。
  5. 支持后端数据库或 NoSQL 实现数据持久化、容灾备份与应用集成。

EMQ X 的系统分层

  1. 连接层 (Connection Layer):负责 TCP 连接处理、 MQTT 协议编解码。
  2. 会话层 (Session Layer):处理 MQTT 协议发布订阅消息交互流程。
  3. 路由层 (Route Layer):节点内路由派发 MQTT 消息。
  4. 分布层 (Distributed Layer):分布节点间路由 MQTT 消息。
  5. 认证与访问控制 (ACL):连接层支持可扩展的认证与访问控制模块。
  6. 钩子 (Hooks) 与插件 (Plugins):系统每层提供可扩展的钩子,支持插件方式扩展服务器。

而 RabbitMQ 则更类似于 Kafka 的消息队列缓存设计。建议在 IoT 项目中将两者结合使用。

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...