emqx学习 — 第一章 基础知识
1 参考文档
- 官网 latest(v5.7)(截至2024-07-30是最新版)
- 官网v5.6
2 配置介绍
本文以v5.7版本为例,有涉及docker单机版和docker-compose集群版安装方式的讲解,所以需要提前搭建好docker
以及docker-compose
环境。Centos7安装docker、centos安装docker-compose
安装 EMQX 开源版,注意有多个安装方式的下载。
2.1 EMQX使用的文件和目录
参考:文件和目录
常用的目录(主要是etc、data、log),不同安装方式得到的文件和目录位置有所不同,具体如下:
序号 | 目录 | 权限 | 描述 | 压缩包解压安装 | 二进制包安装 | Docker安装 | 作用 |
---|---|---|---|---|---|---|---|
1 | etc | 读 | 存放配置文件 | ./etc | /etc/emqx | /opt/emqx/etc | emqx.conf :EMQX 的主配置文件,默认包含常用的配置项。emqx-example-en.conf :EMQX 示例配置文件,包含所有可选的配置项。acl.conf :默认 ACL 规则。vm.args :Erlang 虚拟机的运行参数。certs/ :X.509 的密钥和证书文件。这些文件被用于 EMQX 的 SSL/TLS 监听器;当要与和外部系统集成时,也可用于建立 SSL/TLS 连接。 |
2 | data | 写 | 存放 EMQX 的运行数据 | ./data | /var/lib/emqx | /opt/emqx/data | authz :Dashboard 或 REST API 上传的 基于文件进行授权 规则内容。certs :Dashboard 或 REST API 上传的证书。configs :启动时生成的配置文件,或者从 Dashboard/REST API/CLI 进行功能设置时覆盖的配置文件。mnesia :内置数据库目录,用于存储自身运行数据,例如告警记录、客户端认证与权限数据、Dashboard 用户信息等数据,一旦删除该目录,所有业务数据将丢失。— 可包含以节点命名的子目录,如 emqx@127.0.0.1 ;如节点被重新命名,应手动将旧的目录删除或移走。— 可通过 emqx_ctl mnesia 命令查询 EMQX 中 Mnesia 数据库的系统信息,具体请查看 管理命令 CLI。patches :用于存储热补丁.beam 文件,用于补丁修复。trace : 在线日志追踪文件目录。在生产环境中,建议定期备份该文件夹下除 trace 之外的所有目录。 |
3 | log | 读 | 日志文件 | ./log | /var/log/emqx | /opt/emqx/log | emqx.log.* :EMQX 运行时产生的日志文件,具体请查看日志。 |
4 | releases | 未知 | 存放启动相关的脚本 | ./releases | /usr/lib/emqx/releases | ||
5 | bin | 读 | 存放可执行文件 | ./bin | /usr/lib/emqx/bin | emqx 和 emqx.cmd :EMQX 的可执行文件,具体使用可以查看命令行接口。 | |
6 | lib | 未知 | 存放Erlang 代码 | ./lib | /usr/lib/emqx/lib | ||
7 | erts-* | 未知 | 存放Erlang 虚拟机文件 | ./erts-* | /usr/lib/emqx/erts-* | ||
8 | plugins | 未知 | 插件 | ./plugins | /usr/lib/emqx/plugins |
提示:docker下可通过docker exec -it {容器ID} /bin/sh
查看相关配置文件。
EMQX 的配置项存储在
etc
和data/configs
目录下,二者的主要区别是etc
目录存储 只读 的配置文件,用户通过Dashboard
和REST API
提交的配置将被保存到data/configs
目录下,并支持在运行时进行热更新。
etc/emqx.conf
data/configs/cluster.hocon
EMQX
读取这些配置并将其合并转化为Erlang
原生配置文件格式,以便在运行时应用这些配置。
2.2 EMQX使用的端口
EMQX 默认使用以下端口,请确保这些端口未被其他应用程序占用,并按照需求开放防火墙以保证 EMQX 正常运行。
序号 | 端口 | 协议 | 说明 |
---|---|---|---|
1 | 1883 | TCP | MQTT 协议端口 |
2 | 8883 | TCP | MQTT/SSL 端口 |
3 | 8081 | TCP | 管理 API 端口 |
4 | 8083 | TCP | MQTT/WebSocket 端口 |
5 | 8084 | TCP | MQTT/WebSocket/SSL 端口 |
6 | 18083 | HTTP | Dashboard 端口 |
7 | 4370 | TCP | Erlang 分布式传输端口,根据节点名称不同实际端口可能是 BasePort (4370) + Offset 。 |
8 | 5370 | TCP | 集群 RPC 端口(在 Docker 环境下为 5369),根据节点名称不同实际端口可能是 BasePort (5370) + Offset 。 |
提示
即使没有组建集群,EMQX 也会监听 4370 跟 5370 端口。这 2 个端口固定无法修改,且会根据节点名称(Name@Host
)中 Name 部分的数字后缀决定 Offset,没有数字后缀则默认为 0。更多信息请参考集群内通信端口。
2.3 使用限制
参考:使用限制
为什么会有限制?
过多的连接和数据传输可能会使服务器硬件资源紧张导致性能下降,如网络连接与操作响应缓慢,消息延迟增高、消息堆积甚至丢弃等。另一方面,您的使用还会受到来自协议规范的限制。
参考列表:
使用限制有以下分类:
- 来自服务器资源的限制:理论上没有最大使用限制,实际限制取决于服务器规格。
- 硬编码或协议规范的限制:协议规范的限制,或出于服务稳定与效率考虑由
EMQX
设置了限制。注意,某些项目中,EMQX
会在协议规范的基础上提供一个更合理的默认限制,可以通过配置文件修改它。
描述 | 配额 |
---|---|
设备连接 | |
最大并发连接设备数 | 不限 |
最大设备建立连接速度 | 不限 |
最大客户端 ID 长度 | 65535 |
设备订阅 | |
最大订阅数 | 不限 |
最大订阅速度 | 不限 |
单个设备订阅数 | 不限 |
单个设备订阅速度 | 不限 |
网络流量 | |
最大带宽 | 不限 |
单个设备带宽 | 不限 |
MQTT 消息 | |
单条消息大小 | 默认 1024KB,最大 256MB |
最大 QoS | 2 |
MQTT 心跳时长 | |
支持设置的最大心跳时长 | 65535 秒(约18.2小时) |
MQTT 主题 | |
主题数量 | 不限 |
主题层级 | 65535 |
主题长度 | 不限 |
支持的主题别名数量 | 65535 |
MQTT 保留消息 | |
单条消息大小 | 默认 1204KB,最大 256MB |
保留消息总数 | 不限 |
保留消息总大小 | 不限 |
MQTT 5.0 协议 | |
最多可添加用户自定义属性个数 | 65535 |
MQTT 扩展 | |
主题重写规则数量 | 30 |
代理订阅规则数量 | 30 |
延迟发布消息数量 | 不限 |
延迟发布最大时长 | 4294967 秒(约49.7天) |
规则引擎 | |
规则数量 | 不限 |
规则执行超时 | 不限 |
单个规则目的地数量 | 不限 |
数据集成 | |
数据集成数量 | 不限 |
REST API | |
分页最大大小 | 10000 |
API 密钥数量 | 100 |
Dashboard | |
Dashboard 用户数量 | 不限 |
3 发布订阅相关概念
来源:发布/订阅
EMQX 的发布/订阅功能提供了多种特性,使其非常适用于复杂和高性能的消息应用程序。这些特性包括支持通配符主题、基于主题的消息过滤、消息持久化和消息质量等级(QoS)设置。
发布功能允许连接到 EMQX 的设备向特定主题发送消息。消息可以包含任何类型的数据,例如传感器读数、状态更新或命令。当设备发布消息到一个主题时,EMQX 接收该消息并将其转发给所有订阅了该主题的设备。
EMQX 中的订阅功能允许设备从特定主题接收消息。设备可以订阅一个或多个主题,并接收在这些主题上发布的所有消息。这使得设备能够实时监控特定事件或数据流,而无需不断轮询更新。
3.1 MQTT 发布/订阅模式介绍
发布订阅模式(Publish-Subscribe Pattern)是一种消息传递模式,它将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦,使得两者不需要建立直接的联系也不需要知道对方的存在。
MQTT 发布/订阅模式的精髓在于由一个被称为代理(Broker)的中间角色负责所有消息的路由和分发工作,发布者将带有主题的消息发送给代理,订阅者则向代理订阅主题来接收感兴趣的消息。
在 MQTT 中,主题和订阅无法被提前注册或创建,所以代理也无法预知某一个主题之后是否会有订阅者,以及会有多少订阅者,所以只能将消息转发给当前的订阅者,如果当前不存在任何订阅,那么消息将被直接丢弃。
MQTT 发布/订阅模式有 4 个主要组成部分:发布者、订阅者、代理和主题。
-
发布者(Publisher):负责将消息发布到主题上,发布者一次只能向一个主题发送数据,发布者发布消息时也无需关心订阅者是否在线。
-
订阅者(Subscriber):订阅者通过订阅主题接收消息,且可一次订阅多个主题。MQTT 还支持通过共享订阅的方式在多个订阅者之间实现订阅的负载均衡。
-
代理(Broker):负责接收发布者的消息,并将消息转发至符合条件的订阅者。另外,代理也需要负责处理客户端发起的连接、断开连接、订阅、取消订阅等请求。
-
主题(Topic):主题是 MQTT 进行消息路由的基础,它类似 URL 路径,使用斜杠
/
进行分层,比如sensor/1/temperature
。一个主题可以有多个订阅者,代理会将该主题下的消息转发给所有订阅者;一个主题也可以有多个发布者,代理将按照消息到达的顺序转发。MQTT 还支持订阅者使用主题通配符一次订阅多个主题。更多关于 MQTT 主题的介绍可查看博客:通过案例理解 MQTT 主题与通配符。
MQTT 发布/订阅中的消息路由
一般来说,大多数发布/订阅系统主要通过以下两种方式过滤并路由消息。
- 根据主题:订阅者向代理订阅自己感兴趣的主题,发布者发布的所有消息中都会包含自己的主题,代理根据消息的主题判断需要将消息转发给哪些订阅者。
- 根据消息内容:订阅者定义其感兴趣的消息的条件,只有当消息的属性或内容满足订阅者定义的条件时,消息才会被投递到该订阅者。
MQTT 协议是基于主题进行消息路由的,在这个基础上,EMQX 从 3.1 版本开始通过基于 SQL 的规则引擎提供了额外的按消息内容进行路由的能力。关于规则引擎的详细信息,请查看 EMQX 文档。
MQTT 与消息队列
尽管 MQTT 与消息队列的很多行为和特性非常接近,比如都采用发布/订阅模式,但是他们面向的场景却有着显著的不同。消息队列主要用于服务端应用之间的消息存储与转发,这类场景往往数据量大但客户端数量少。MQTT 是一种消息传输协议,主要用于物联网设备之间的消息传递,这类场景的特点是海量的设备接入、管理与消息传输。
在一些实际的应用场景中,MQTT 与消息队列往往会被结合起来使用,以使 MQTT 服务器能专注于处理设备的连接与设备间的消息路由。比如先由 MQTT 服务器接收物联网设备上报的数据,然后再通过消息队列将这些数据转发到不同的业务系统进行处理。
不同于消息队列,MQTT 主题不需要提前创建。MQTT 客户端在订阅或发布时即自动的创建了主题,开发者无需再关心主题的创建,并且也不需要手动删除主题。
结语:
MQTT 的发布/订阅机制可以很轻易地满足我们一对一、一对多、多对一的通信需要。这也在很大程度上拓宽了 MQTT 在 IoT 领域之外的应用,像网络直播互动、手机消息推送等行业场景,都非常适合使用 MQTT。
3.2 主题与通配符
以下是简单总结:
- 什么是 MQTT 主题?
- MQTT 主题通配符:MQTT 主题通配符包含单层通配符 + 及多层通配符 #,主要用于客户端一次订阅多个主题。
- 单层通配符(+)
- 多层通配符(#)
注意:通配符只能用于订阅,不能用于发布。
- 以 $ 开头的主题:
- 以 $SYS/ 开头的主题为系统主题。
- 共享订阅:共享订阅是 MQTT 5.0 引入的新特性,用于在多个订阅者之间实现订阅的负载均衡,MQTT 5.0 规定的共享订阅主题以
$share
开头。
- 不同场景中的主题设计
- MQTT 主题常见问题及解答
-
主题的层级及长度有什么限制吗?
MQTT 协议规定主题的长度为两个字节,因此主题最多可包含 65,535 个字符。建议主题层级为 7 个以内。使用较短的主题名称和较少的主题层级意味着较少的资源消耗,例如
my-home/room1/data
比my/home/room1/data
更好。 -
服务器对主题数量有限制吗?
不同消息服务器对最大主题数量的支持各不一致,目前 EMQX 的默认配置对主题数量没有限制,但是主题数量越多将会消耗越多的服务器内存。考虑到连接到 MQTT Broker 的设备数量一般较多,我们建议一个客户端订阅的主题数量最好控制在 10 个以内。 -
通配符主题订阅与普通主题订阅性能是否一致?
通配符主题订阅的性能弱于普通主题订阅,且会消耗更多的服务器资源,用户可根据实际业务情况选择订阅类型。 -
重叠订阅了普通主题和通配符主题时如何接收消息?
假如客户端同时订阅了#
和test
主题,当向test
主题发送消息时,是否会收到两条重复消息?这取决于 MQTT broker 的实现,例如 EMQX 会为每个匹配的订阅发送消息。但是用户可以使用 MQTT 5.0 中的订阅标识符来区分消息来源,然后在客户端中根据订阅标识符来处理这类重复的消息。 -
同一个主题能被共享订阅与普通订阅同时使用吗?
可以,但是不建议同时使用。 -
常见的 MQTT 主题使用建议有哪些?
- 不建议使用
#
订阅所有主题; - 不建议主题以
/
开头或结尾,例如/chat
或chat/
; - 不建议在主题里添加空格及非 ASCII 特殊字符;
- 同一主题层级内建议使用下划线
_
或横杆-
连接单词(或者使用驼峰命名); - 尽量使用较少的主题层级;
- 当使用通配符时,将唯一值的主题层(例如设备号)越靠近第一层越好。例如,
device/00000001/command/#
比device/command/00000001/#
更好。
- 不建议使用
-
3.3 QoS
还需要仔细了解各交付等级的实现机制。
MQTT 定义了三种 QoS 等级,来分别提供不同的消息可靠性保证。每条消息都可以在发布时独立设置自己的 QoS。
- QoS 0:最多交付一次,消息可能丢失;
- QoS 1:至少交付一次,消息可以保证到达,但是可能重复;
- QoS 2:只交付一次,消息保证到达,并且不会重复。
QoS 越大,消息的传输复杂程度也越高,我们需要根据实际场景来选择合适的 QoS。
以下是简单总结:
在一个完整的从发布者到订阅者的消息投递流程中,QoS 等级是由发布者在 PUBLISH 报文中指定的,大部分情况下 Broker 向订阅者转发消息时都会维持原始的 QoS 不变。不过也有一些例外的情况,根据订阅者的订阅要求,消息的 QoS 等级可能会在转发的时候发生降级。
例如,订阅者在订阅时要求 Broker 可以向其转发的消息的最大 QoS 等级为 QoS 1,那么后续所有 QoS 2 消息都会降级至 QoS 1 转发给此订阅者,而所有 QoS 0 和 QoS 1 消息则会保持原始的 QoS 等级转发。
3.4 会话
QoS 只是设计了消息可靠到达的理论机制,而会话则确保了 QoS 1、2 的协议流程得以真正实现。
会话是客户端与服务端之间的有状态交互,它可以仅持续和网络连接一样长的时间,也可以跨越多个网络连接存在,我们通常将后者称为持久会话。我们可以选择让连接从已存在的会话中恢复,也可以选择从一个全新的会话开始。
来源:MQTT 持久会话与 Clean Session 详解
3.5 保留消息
与普通消息不同,保留消息可以保留在 MQTT 服务器中。任何新的订阅者订阅与该保留消息中的主题匹配的主题时,都会立即接收到该消息,即使这个消息是在它们订阅主题之前发布的。
一个主题下只能存储一条最新的保留消息的限制。
来源1:保留消息
来源2:MQTT 保留消息是什么?如何使用?
3.6 遗嘱消息
发布订阅模式的特性决定了,除了服务器以外没有客户端能够感知到某个客户端从通信网络中离开。而遗嘱消息则为连接意外断开的客户端提供了向其他客户端发出通知的能力。
客户端可以在连接时向服务器设置自己的遗嘱消息,服务器将在客户端异常断开后立即或延迟一段时间后发布这个遗嘱消息。而订阅了对应遗嘱主题的客户端,将收到这个遗嘱消息,并且采取相应的措施,例如更新该客户端的在线状态等等。
注意:是连接意外断开时才会触发。
来源1:遗嘱消息
来源2:遗嘱消息(Will Message)介绍与示例 | MQTT 5.0 特性详解
如果客户端在连接时指定了遗嘱消息,那么服务端就会将该遗嘱消息存储在相应的会话中,直到以下任一条件满足时发布它:
- 服务端检测到了一个 I/O 错误或者网络故障。
- 客户端在 Keep Alive 时间内未能通讯。
- 客户端在没有发送 Reason Code 为 0x00(正常关闭)的 DISCONNECT 报文的情况下关闭了网络连接。
- 服务端在没有收到 Reason Code 为 0x00(正常关闭)的 DISCONNECT 报文的情况下关闭了网络连接,例如客户端的报文或行为不符合协议要求而被服务端关闭连接。
简单起见,我们可以直接概括为,只要网络连接在服务端没有收到 Reason Code 为 0x00 的 DISCONNECT 报文的情况下关闭,那么服务端都需要发送遗嘱消息。
当客户端完成了预定的工作准备正常下线时,可以发送一个 Reason Code 为 0x00 的 DISCONNECT 报文然后关闭网络连接,避免服务端因此发布遗嘱消息。
3.7 共享订阅
默认情况下,消息会被转发给所有匹配的订阅者。但有时,我们可能希望多个客户端协同处理接收到的消息,以便以水平扩展的方式来提高负载能力。又或者,我们希望为客户端增加一个备份客户端,当主客户端离线时,能够无缝切换到备份客户端继续接收消息,以确保高可用性。
而 MQTT 的共享订阅特性,则提供了这一能力。我们可以将客户端划分为多个订阅组,消息仍然会被转发给所有订阅组,但每个订阅组内每次只会有一个客户端收到消息。
来源1:共享订阅
来源2:共享订阅介绍与示例 | MQTT 5.0 特性详解
3.8 $SYS 主题
以 $SYS/
为前缀的主题被保留给服务器用来发布一些特定的消息,比如服务器的运行时间、客户端的上下线事件通知、当前连接的客户端数量等等。我们一般将这些主题称为系统主题,客户端可以订阅这些系统主题来获取服务器的有关信息。
3.9 MQTT 客户端工具演示
来源:MQTT 客户端工具演示
3.10 排它订阅
来源:排它订阅
3.11 延迟发布
来源:延迟发布
3.12 自动订阅
来源:自动订阅
3.13 主题重写
来源:主题重写
4 MQTT 会话持久化
来源:MQTT 会话持久化
5 客户端SDK使用示例
来源1:客户端SDK使用示例
来源2:更多示例(Github)