借助 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 建立会话保持。我们使用一致的参数,以便在上游服务器发生故障时,将其流量平均分发给其余服务器,而不影响这些服务器上已建立的会话。
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 。
客户端 ID 替换
出于安全原因,您可以选择不在 MQTT Broker 的数据库中存储客户端可识别信息。例如,设备发送的 MQTT CONNECT 消息中可能会有序列号或其他敏感数据。只需将设备的标识符替换为从客户端接收的其他已知静态值,便可为尝试访问 NGINX Plus 代理的 Broker 的每台设备建立一个新的唯一标识符。
在本例中,我们从设备的客户端 SSL 证书中提取了一个唯一标识符,并用它来屏蔽其 MQTT 客户端 ID。客户端证书身份验证(双向 TLS)通过 ssl_verify_client 指令进行控制。当参数设置为 on 时,NGINX 可确保客户端证书由受信任证书颁发机构(CA)签发。受信任 CA 证书通过 ssl_client_certificate 指令进行定义。
客户端证书作为身份验证凭证
对 MQTT 客户端进行身份验证的一种常见方法是使用客户端证书中存储的数据作为用户名。NGINX Plus 可以解析客户端证书并重写 MQTT username 字段,从后端 Broker 卸载这项任务。在下面的示例中,我们提取客户端证书的持有者专有名称(持有者 DN),并将其复制到 MQTT CONNECT 消息的 username 部分。
有关 NGINX Plus MQTT CONNECT 消息重写的完整规范,请参阅 ngx_stream_mqtt_filter_module 规范。
立即行动
NGINX Plus 中 MQTT 的后续开发可能包括对其他 MQTT 消息类型进行解析,并能够更深入地解析 CONNECT 消息以启用以下功能:
额外的身份验证和访问控制机制
通过对频繁通信的客户端进行速率限制来保护 Broker
消息遥测和连接指标
欢迎您就所看重的特性给我们反馈,请在评论区告诉我们您的想法,或者添加小 N 助手(微信号:nginxoss)加入官方讨论群,与社区用户交流探讨。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
版权声明: 本文为 InfoQ 作者【NGINX开源社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/e3c9678442488b397581b9a8c】。文章转载请联系作者。
评论