借助 NGINX Plus 优化企业环境中的 MQTT 部署
原文作者:Michael Vernik - F5 高级产品经理
原文链接:借助 NGINX Plus 优化企业环境中的 MQTT 部署
转载来源:NGINX 中文官网
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
在宣布推出 NGINX Plus R29 版本时,我们简要介绍了其对 MQTT 消息解析的全新原生支持。本文将在此基础上探讨如何配置 NGINX Plus,以优化企业环境中的 MQTT 部署。
什么是 MQTT?
MQTT 是指“消息队列遥测传输”,是一种常用的轻量级“发布-订阅”消息协议,非常适合通过互联网连接物联网(IoT)或机器对机器(M2M)设备和应用。MQTT 可在低带宽或低功耗环境中高效运行,因此是有着众多远程客户端的应用的理想之选,适用于多个行业,包括消费类电子产品、汽车、运输、制造及医疗行业。
NGINX Plus MQTT 消息处理
NGINX Plus R29 支持 MQTT 3.1.1 和 MQTT 5.0。它充当了客户端和 Broker 之间的代理,可从核心系统卸载数据加密任务,简化可扩展性并降低计算成本。具体来说,NGINX Plus 能够解析并重写 MQTT CONNECT 消息的部分内容,从而实现以下功能:
-
MQTT Broker 负载均衡
-
会话保持(将客户端重新连接到同一 Broker)
-
SSL/TLS 卸载
-
客户端证书身份验证
MQTT 消息处理指令必须在 NGINX 配置文件的 stream
上下文中进行定义,并由 ngx_stream_mqtt_preread_module
和 ngx_stream_mqtt_filter_module
提供。
preread
模块先于 NGINX 的内部代理处理 MQTT 数据,允许根据解析的消息数据做出负载均衡和上游路由决策。
filter
模块支持重写已接收 CONNECT 消息中的 clientid
、username
及 password
字段,并允许将这些字段设置为变量和复值,这可大幅扩展配置选项,支持 NGINX Plus 屏蔽敏感设备信息或插入 TLS 证书专有名称等数据。
MQTT 指令和变量
现有多个新指令和嵌入式变量可用于调整 NGINX 配置,以优化 MQTT 部署并满足您的特定需求。
preread 模块指令和嵌入式变量
-
mqtt_preread
– 启用 MQTT 解析,以便从客户端设备发送的 CONNECT 消息中提取clientid
和username
字段。这些值通过嵌入式变量提供,可帮助将会话散列到负载均衡的上游服务器上(示例请见下文)。 -
$mqtt_preread_clientid
– 表示设备发送的 MQTT 客户端标识符。 -
$mqtt_preread_username
– 表示客户端发送的用于身份验证的用户名。
filter 模块指令
-
mqtt
– 定义是否启用 MQTT 重写。 -
mqtt_buffers
– 覆盖每个连接可分配的最大 MQTT 处理缓冲区数以及每个缓冲区的大小。默认情况下,NGINX 将限制每个连接 100 个缓冲区,每个缓冲区的长度为 1k。通常,这对于性能来说是最佳的,但在特殊情况下可能需要进行调整。例如,较长的 MQTT 消息需要较大的缓冲区。在短时间内为给定连接处理大量 MQTT 消息的系统可能会受益于缓冲区数量的增加。在大多数情况下,由于 NGINX 是从内部内存池构建缓冲区的,调整缓冲区参数对底层系统性能影响不大。 -
mqtt_rewrite_buffer_size
– 指定用于构建已修改 MQTT 消息的缓冲区的大小。该指令已被弃用,并且自 NGINX Plus R30 起已过时。 -
mqtt_set_connect
– 重写从客户端发送的 CONNECT 消息的参数。支持的参数包括:clientid
、username
及password
。
MQTT 示例
下面我们来更详细地了解一下使用 NGINX Plus 处理 MQTT 消息的优势以及相关的最佳实践。请注意,在下面的示例中,我们使用的是端口 1883 和端口 8883。端口 1883 是默认的不安全 MQTT 端口,而端口 8883 是默认的 SSL/TLS 加密端口。
MQTT Broker 负载均衡
MQTT 设备的短暂连接行为可能导致客户端 IP 意外更改,不利于将设备连接路由到正确的上游 Broker。在将设备连接从一个上游 Broker 移动到另一个上游 Broker 时,会带来高开销的 Broker间同步操作,进而增加延迟和成本。
通过解析 MQTT CONNECT 消息中的 clientid
字段,NGINX 可与上游服务 Broker 建立会话保持。其实现方法是,使用 clientid
作为哈希键来维护与后端 Broker 服务的连接。
在本例中,我们使用 clientid
作为令牌来代理 MQTT 设备数据,从而与三个上游 Broker 建立会话保持。我们使用一致的参数,以便在上游服务器发生故障时,将其流量平均分发给其余服务器,而不影响这些服务器上已建立的会话。
stream { mqtt_preread on; upstream backend { zone tcp_mem 64k; hash $mqtt_preread_clientid consistent; server 10.0.0.7:1883; # upstream mqtt broker 1 server 10.0.0.8:1883; # upstream mqtt broker 2 server 10.0.0.9:1883; # upstream mqtt broker 3 } server { listen 1883; proxy_pass backend; proxy_connect_timeout 1s; } }
NGINX Plus 还能够解析 MQTT CONNECT 消息的 username 字段。更多详情,请参阅 ngx_stream_mqtt_preread_module 规范
。
SSL/TLS 卸载
加密设备通信是确保数据保密性和抵御中间人攻击的关键。不过,TLS 握手、加密和解密可能会给 MQTT Broker 带来资源负担。为了解决这一问题,NGINX Plus 可从 Broker(或 Broker 集群)卸载数据加密,从而简化安全规则,支持 Broker 全力处理设备消息。
在本例中,我们展示了如何使用 NGINX 将 TLS 加密的 MQTT 流量从设备代理到后端 Broker。ssl_session_cache
指令定义了一个 5 MB 缓存,该容量足以存储约 20,000 个 SSL 会话。根据 proxy_connect_timeout
指令的定义,NGINX 将尝试在五秒钟(超时期限)内访问代理的 Broker 。
stream { server { listen 8883 ssl; ssl_certificate /etc/nginx/certs/tls-cert.crt; ssl_certificate_key /etc/nginx/certs/tls-key.key; ssl_session_cache shared:SSL:5m; proxy_pass 10.0.0.8:1883; proxy_connect_timeout 5s; } }
客户端 ID 替换
出于安全原因,您可以选择不在 MQTT Broker 的数据库中存储客户端可识别信息。例如,设备发送的 MQTT CONNECT 消息中可能会有序列号或其他敏感数据。只需将设备的标识符替换为从客户端接收的其他已知静态值,便可为尝试访问 NGINX Plus 代理的 Broker 的每台设备建立一个新的唯一标识符。
在本例中,我们从设备的客户端 SSL 证书中提取了一个唯一标识符,并用它来屏蔽其 MQTT 客户端 ID。客户端证书身份验证(双向 TLS)通过 ssl_verify_client
指令进行控制。当参数设置为 on 时,NGINX 可确保客户端证书由受信任证书颁发机构(CA)签发。受信任 CA 证书通过 ssl_client_certificate
指令进行定义。
stream { mqtt on; server { listen 8883 ssl; ssl_certificate /etc/nginx/certs/tls-cert.crt; ssl_certificate_key /etc/nginx/certs/tls-key.key; ssl_client_certificate /etc/nginx/certs/client-ca.crt; ssl_session_cache shared:SSL:10m; ssl_verify_client on; proxy_pass 10.0.0.8:1883; proxy_connect_timeout 1s; mqtt_set_connect clientid $ssl_client_serial; } }
客户端证书作为身份验证凭证
对 MQTT 客户端进行身份验证的一种常见方法是使用客户端证书中存储的数据作为用户名。NGINX Plus 可以解析客户端证书并重写 MQTT username 字段,从后端 Broker 卸载这项任务。在下面的示例中,我们提取客户端证书的持有者专有名称(持有者 DN),并将其复制到 MQTT CONNECT 消息的 username 部分。
stream { mqtt on; server { listen 8883 ssl; ssl_certificate /etc/nginx/certs/tls-cert.crt; ssl_certificate_key /etc/nginx/certs/tls-key.key; ssl_client_certificate /etc/nginx/certs/client-ca.crt; ssl_session_cache shared:SSL:10m; ssl_verify_client on; proxy_pass 10.0.0.8:1883; proxy_connect_timeout 1s; mqtt_set_connect username $ssl_client_s_dn; } }
有关 NGINX Plus MQTT CONNECT 消息重写的完整规范,请参阅 ngx_stream_mqtt_filter_module
规范。
立即行动
NGINX Plus 中 MQTT 的后续开发可能包括对其他 MQTT 消息类型进行解析,并能够更深入地解析 CONNECT 消息以启用以下功能:
-
额外的身份验证和访问控制机制
-
通过对频繁通信的客户端进行速率限制来保护 Broker
-
消息遥测和连接指标
欢迎您就所看重的特性给我们反馈,请在评论区告诉我们您的想法,或者添加小N助手(微信号:nginxoss)加入官方讨论群,与社区用户交流探讨。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
GreatSQL 构建高效 HTAP 服务架构指南(MGR)
GreatSQL 构建高效 HTAP 服务架构指南(MGR) 引言 全文约定:$为命令提示符、greatsql>为 GreatSQL 数据库提示符。在后续阅读中,依据此约定进行理解与操作 上一篇已经介绍了如何在主从复制架构中,搭建一个专属 HTAP 服务。本篇将在 MGR 架构中部署一个专属 HTAP 服务。 整体方案架构图 本服务架构采用 GreatSQL MGR 架构,在 MGR 架构中部署一个专属 HTAP 服务节点。Primary 节点采用默认 InnoDB 引擎,Secondary 节点使用辅助引擎 Rapid 加速查询构建专属 HTAP 只读节点。加上 MySQL Router 等之类的代理/中间件负责读写分离来完成 HTAP 服务架构。 高查询效率 : Rapid引擎的引入使得从节点能够加速查询处理,特别适用于 OLAP(联机分析处理)场景。 读写分离及读负载均衡 : 利用代理/中间件实现读写分离,确保主节点(写操作)和从节点(读操作)的读写负载得到有效均衡。 高可用 : GreatSQL 针对 MGR 做了大量的改进和提升工作,进一步提升 MGR 的高可靠等级,例...
- 下一篇
百行代码实现 Kafka 运行在 S3 之上
01 TL;DR 是的,你没有看错。AutoMQ[1] 当前已经支持完全构建于像 S3 这样的对象存储之上。你可以参考快速上手[3] 即刻开始体验。AutoMQ 在已有的流存储引擎之上仅仅通过对顶层 WAL 的抽象进行拓展实现少量代码即可做到一些友商引以为傲的的特性,即将流系统完全构建于像 S3 对象存储之上。值得一提的是,我们也已经将这部分源码完全公开,开发者可以利用 S3Stream[2] 流存储引擎轻松在自己的环境中拥有一个完全部署在对象存储之上的 Kafka 服务,具备极低的存储成本和运维复杂度。AutoMQ 核心的流存储引擎可以如此轻松的完成这项能力和其围绕 WAL 与 共享存储架构设计的优秀流存储顶层抽象是分不开的。也正是基于这套优秀的顶层抽象我们实现了极具创新的 S3Stream[2] 流存储引擎。在这篇文章中,我们将与你分享 AutoMQ 共享流存储引擎的设计细节、背后的思考以及演进的过程。看完前面的内容,你也会真正明白为什么我们说只需要百行代码即可实现将 Kafka 运行在 S3 之上。 02 从共享存储架构启航 在十几年前,Kafka 诞生于一个以 IDC(Inte...
相关文章
文章评论
共有0条评论来说两句吧...