点赞
评论
收藏
分享
举报
借助 NGINX Plus 优化企业环境中的 MQTT 部署
发表于2024-07-16 11:52

浏览 4k

原文作者: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.1MQTT 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 消息中的 clientidusernamepassword 字段,并允许将这些字段设置为变量和复值,这可大幅扩展配置选项,支持 NGINX Plus 屏蔽敏感设备信息或插入 TLS 证书专有名称等数据。

 

MQTT 指令和变量

现有多个新指令和嵌入式变量可用于调整 NGINX 配置,以优化 MQTT 部署并满足您的特定需求。

 

preread 模块指令和嵌入式变量

    • mqtt_preread – 启用 MQTT 解析,以便从客户端设备发送的 CONNECT 消息中提取 clientidusername 字段。这些值通过嵌入式变量提供,可帮助将会话散列到负载均衡的上游服务器上(示例请见下文)。
    • $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 消息的参数。支持的参数包括:clientidusernamepassword

   

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

更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源: 开源社区官网 | 微信公众号 | B 站

已修改于2024-07-16 11:52
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
331
文章
21
问答
201
粉丝
相关文章
NGINX开源版本和商用版本的差异化对比 先从官方的对比图讲起: 其中NGINXPLUS一栏代表当前商用版本的功能/场景支持列表,NGINXOSS一栏代表社区开源版本的功能支持列表。 再从NGINX模块增强角度的对比图讲起: 其中新增的商业版本模块,是在原来开源模块基础上额外具备的,简单地说是商业版本独有的;其次,开源模块的增强部分,在商业版本里相比传统的开源模块,又做了些许优化与提升。 出处引用:https://www.nginx.com/products/nginx/#compare-versions 最后从NGINXController角度和社区开源版本的行业定制的对比图说起: 某行业基于开源版本的定制化视图: NGINX官方部分摘录: 从这一系列的结构介绍里可以看出,NGINXController对部署的要求及NGINX服务的纳管情况,简单地说提供一个平台工具来定位用了哪些NGINX服务,NGINX服务的进程情况如何,NGINX相关监控指标运行情况等,相比某行业基于开源版的定制,一个是追求原味的呈现,另一个是更贴近客
点赞 1
浏览 9.1k
通常使用的nginx负载均衡技术,在网络分层中处于应用层(第七层)的,nginx与客户端建立TCP连接(握手),然后再根据请求信息以及本地配置信息,将请求灵活的分发到不同的服务上。nginx这类7层负载均衡的优缺点都很明显。除了nginx这种7层负载均衡策略,还有基于传输层(4层)的负载均衡策略。通过分析请求的IP地址以及端口号进行请求的负载均衡。根据请求处理的模式不同4层负载均衡算法可以分为:NAT,D-NAT,DR以及TUN隧道技术等。4层负载均衡的实现方式有:LVS。负载模式NAT(NetworkAddressTranslation,网络地址转换)技术,在专用内部网络中,分配一台实现了NAT技术的路由或服务LoadBalanceService。这台负载均衡服务器分配了公网IP(VIP,VirtualIP),所有客户端请求服务都请求此IP。LBS通过不同的算法,将请求数据包的源IP以及目标IP修改,转发到真实服务器(RealService)上进行业务处理。其具体的步骤可以分为:1、客户端发送请求,源IP为:CIP,目标IP为:VIP3、RS接收到请求,进行业务处理
点赞 4
浏览 9.2k
前言nginx系列之一:nginx入门nginx系列之二:配置文件解读nginx系列之三:日志配置nginx系列之四:web服务器nginx系列之五:负载均衡nginx系列之六:cache服务nginx系列之七:限流配置nginx系列之八:使用upsync模块实现负载均衡转自:在此感谢原博主的整理分享使用nginx做负载均衡的两大模块:upstream定义负载节点池。location模块进行URL匹配。proxy模块发送请求给upstream定义的节点池。一、upstream模块解读nginx的负载均衡功能依赖于ngx_http_upstream_module模块,所支持的代理方式有proxy_pass(一般用于反向代理),fastcgi_pass(一般用于和动态程序交互),memcached_pass,proxy_next_upstream,fastcgi_next_pass,memcached_next_pass。upstream模块应该放于http{}标签内。模块写法:upstreambackend{ ip_hash; server
点赞 5
浏览 11.1k