1. MQTT 协议与 Mosquitto 简介
1.1 MQTT 协议核心概念
MQTT(Message Queuing Telemetry Transport)是一种基于发布/订阅模式的轻量级物联网通信协议,由 IBM 于 1999 年发明。它运行在 TCP/IP 之上,采用二进制格式,协议头最小仅 2 字节,特别适合带宽受限、网络不稳定的物联网场景。
核心概念:
发布/订阅模型
MQTT 解耦了消息生产者和消费者。设备(客户端)不直接通信,而是通过中心节点 Broker 路由消息。发布者将消息发送到特定”主题”,订阅者从该主题接收消息。这种架构让设备无需知道彼此的存在。
主题
主题是消息的分类标签,使用 / 分层,如 building/floor1/temperature。订阅时支持通配符:
+:匹配单层,如building/+/temperature匹配所有楼层的温度主题#:匹配多层,如building/#匹配该楼栋下所有主题
QoS(服务质量)
MQTT 提供三级服务质量:
| QoS | 名称 | 语义 | 适用场景 |
|---|---|---|---|
| 0 | 最多一次 | 消息发出去就忘,不保证到达 | 高频传感器数据,丢失一两条无影响 |
| 1 | 至少一次 | 确保到达,但可能重复 | 重要但可去重的数据 |
| 2 | 恰好一次 | 严格保证不丢不重 | 计费、控制指令 |
QoS 是逐跳的——发布者到 Broker 和 Broker 到订阅者可以不同。
保留消息
发布时设置 retain=true,Broker 会存储该主题最后一条保留消息。新客户端订阅时立即收到这条消息,无需等待下次发布。典型用途:设备上线时获取最新配置或状态。
遗嘱消息
客户端连接时可设置遗嘱消息。一旦 Broker 检测到该客户端异常断连(心跳超时),自动发布遗嘱消息到指定主题。用于感知设备离线状态。
1.2 Mosquitto 特点与适用场景
Mosquitto 是 Eclipse 基金会旗下的开源 MQTT Broker,C 语言编写,是业界最广泛使用的 MQTT 实现之一。
核心优势:
- 极轻量:二进制体积小(< 500KB),内存占用低(万级连接仅需几十 MB)
- 单机性能优异:单节点可支撑数万到十万级并发连接
- 完全支持 MQTT 3.1 / 3.1.1 / 5.0 协议
- 桥接功能:通过 MQTT Bridge 实现跨机房消息同步
- 配置简单:单一配置文件,学习曲线平缓
局限:
- 无原生集群:不支持多节点组成逻辑集群,桥接只是消息转发而非真正集群
- 水平扩展困难:无法像 Kafka 那样通过加节点线性扩展
- 无内置持久化到外部存储:持久化依赖本地磁盘,不支持直接写入数据库
适用场景: 设备数在 10 万以下的单机部署;跨机房通过桥接实现消息同步;对集群和高可用不敏感的内部系统。
2.1 版本更新: 2026 年 2 月 Eclipse Mosquitto 2.1 正式发布(截至本文撰写时最新为 2.1.2),带来多项重大变化:内置 Web UI(浏览器端直接管理连接与主题)、全新 C 插件系统(替代旧版 auth_plugin 架构)、内置 WebSocket(无需编译时指定
WITH_WEBSOCKETS)、增强 TLS 1.3 支持等。本指南主要基于 2.0.x 编写,所有配置在 2.0.x 上均可直接使用。若使用 2.1,部分章节需注意差异,文中会以 “2.1 提示” 形式标注。
1.3 生产环境架构抉择
单节点部署(设备 < 1 万)
最简单的部署形态。一台服务器运行 Mosquitto,所有设备直连。配合 TLS 加密和 ACL 权限控制,满足大部分中小规模场景。
优点:部署运维简单,无一致性问题。缺点:单点故障,服务器宕机则所有设备断连。
桥接双活(跨机房高可用)
两台 Mosquitto 分别在两个机房,通过双向 Bridge 互相同步消息。客户端就近连接,单机房故障不影响整体服务。
[机房 A] [机房 B] Clients ←→ Mosquitto A ←→ Mosquitto B ←→ Clients ↕ ↕ 本地消息 本地消息配置要点:topic 映射避免消息环路(设置 bridge_attempt_unsubscribe 等参数);桥接链路同样启用 TLS 加密。
何时切换到 EMQX / VerneMQ
出现以下信号时,考虑迁移到集群型 Broker:
- 设备量突破 10 万,单机 Mosquitto 连接数和内存成为瓶颈
- 需要真正的集群:多节点共享订阅、消息在集群内自动路由
- 需要数据桥接到 Kafka / PostgreSQL / ClickHouse 等外部系统(Mosquitto 桥接只能到另一个 MQTT Broker)
- 需要 Web 管理界面、REST API 管理、多租户等企业特性
EMQX 和 VerneMQ 都支持水平扩展的集群架构,内置数据桥接和规则引擎,但运维复杂度也相应上升。
2. 部署前准备
2.1 硬件与系统要求
| 规模 | CPU | 内存 | 磁盘 |
|---|---|---|---|
| 少量设备(< 1000) | 1-2 核 | 512MB-1GB | 20GB SSD |
| 中等规模(1000-10000) | 2-4 核 | 2-4GB | 50GB SSD |
| 大规模(10000-100000) | 4-8 核 | 8-16GB | 100GB+ SSD |
文件描述符限制
每个 MQTT 连接消耗一个文件描述符。Linux 默认 1024 远远不够。
# 查看当前限制ulimit -n
# 永久修改 /etc/security/limits.confecho "* soft nofile 100000" >> /etc/security/limits.confecho "* hard nofile 100000" >> /etc/security/limits.conf2.2 端口规划与防火墙策略
| 端口 | 协议 | 用途 |
|---|---|---|
| 1883 | MQTT TCP | 默认不加密通信(生产环境建议禁用) |
| 8883 | MQTT over TLS | 标准加密通信端口 |
| 9001 | MQTT over WebSocket | 浏览器端需要时启用 |
防火墙示例(firewalld):
firewall-cmd --permanent --add-port=8883/tcpfirewall-cmd --permanent --add-port=9001/tcp # 按需firewall-cmd --reload云环境安全组规则: 仅开放 8883 端口给设备网段;1883 端口除非有充分理由,否则直接禁用。
2.3 域名与 TLS 证书准备
Let’s Encrypt(公网环境):
# 使用 certbot 获取证书certbot certonly --standalone -d mqtt.example.com内部 CA(企业内网环境):
自建 CA 签发证书,所有设备预置 CA 根证书。适合设备不访问公网的纯内网场景。
自签名证书(测试环境):
openssl req -new -x509 -days 3650 -nodes \ -out /etc/mosquitto/certs/server.crt \ -keyout /etc/mosquitto/certs/server.key生产环境务必使用正式 CA 签名证书,避免所有设备都需要配置忽略证书验证。
3. 安装 Mosquitto
3.1 方式一:系统包管理器安装(推荐)
Ubuntu / Debian:
# 添加官方 PPA(获取最新稳定版)sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppasudo apt updatesudo apt install -y mosquitto mosquitto-clientsRHEL / Rocky / AlmaLinux:
# EPEL 仓库包含 mosquittosudo dnf install -y epel-releasesudo dnf install -y mosquitto mosquitto-clientsRHEL 9 / Rocky 9 可直接使用 CodeReady Linux Builder 仓库中的版本。如需最新版,可从 mosquitto.org 下载 RPM 包。
2.1 提示: 截至本文撰写时,PPA 和 EPEL 仓库仍提供 2.0.x 版本。如需 2.1,可从源码编译或使用 Docker 镜像(见 3.2 节)。
3.2 方式二:Docker 容器化部署
version: "3.8"services: mosquitto: image: eclipse-mosquitto:2.0 container_name: mosquitto restart: unless-stopped ports: - "8883:8883" - "9001:9001" # WebSocket(2.1 内置支持) volumes: - ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro - ./certs:/mosquitto/certs:ro - mosquitto-data:/mosquitto/data - mosquitto-log:/mosquitto/log user: "1883:1883" # mosquitto 镜像内置用户
volumes: mosquitto-data: mosquitto-log:启动:
docker compose up -dDocker 部署的优点:环境隔离、快速迁移、版本固定。注意:挂载配置文件和证书目录的权限必须让 uid 1883 可读。
2.1 提示: 将
image: eclipse-mosquitto:2.0替换为image: eclipse-mosquitto:2.1即可获取 2.1 版本。2.1 镜像内置 Web UI(默认端口 8080),如需启用可通过环境变量或额外端口映射暴露。
3.3 方式三:源码编译
仅当需要打自定义补丁或启用实验性功能时使用。
# 安装编译依赖sudo apt install -y build-essential libssl-dev libc-ares-dev uuid-dev cmake
# 下载并编译(以 2.1.2 为例)wget https://mosquitto.org/files/source/mosquitto-2.1.2.tar.gztar xzf mosquitto-2.1.2.tar.gzcd mosquitto-2.1.2make WITH_TLS=yes WITH_WEBSOCKETS=yessudo make install2.1 提示:(注:2.0.x 版本需显式指定
WITH_WEBSOCKETS=yes;2.1.x 版本此选项默认为开启,但显式指定可增强可读性。libwebsockets-dev在 2.1 中变为可选依赖。)
编译后可执行文件在 /usr/local/sbin/mosquitto,需要手动创建 systemd 服务文件。
3.4 安装后验证
# 检查版本mosquitto -h | head -1
# 最简单的功能测试# 终端1:启动 Broker(前台模式)mosquitto -v
# 终端2:发布消息mosquitto_pub -t "test/hello" -m "world"
# 终端3:订阅消息mosquitto_sub -t "test/#" -v如果订阅端收到 test/hello world,说明 Broker 正常工作。
4. 核心配置与安全加固
4.1 基础参数
# 进程管理pid_file /var/run/mosquitto/mosquitto.pid
# 日志log_dest file /var/log/mosquitto/mosquitto.loglog_type errorlog_type warninglog_type noticelog_type informationconnection_messages true
# 持久化persistence truepersistence_location /var/lib/mosquitto/autosave_interval 300 # 每5分钟自动保存一次持久化状态connection_messages true:记录客户端连接/断连事件,排查问题必备autosave_interval:过短增加磁盘 IO,过长增加重启后消息丢失风险。300s(5分钟)是实践中的平衡值
4.2 网络监听与协议
仅内网监听(安全推荐):
# 仅监听内网 IP,拒绝外部直连bind_address 10.0.0.5禁用不加密端口,强制 TLS:
不配置 listener 1883 即可。只开放 TLS 端口,杜绝明文传输风险。
WebSocket 配置(可选):
listener 9001protocol websockets# 如需 TLS 加密的 WebSocket,使用另一端口:# listener 9002# protocol websockets# certfile /etc/mosquitto/certs/server.crt# keyfile /etc/mosquitto/certs/server.key4.3 TLS/SSL 加密
# TLS 监听器listener 8883protocol mqtt
# 证书配置certfile /etc/mosquitto/certs/server.crtkeyfile /etc/mosquitto/certs/server.keycafile /etc/mosquitto/certs/ca.crt # CA 证书链(Let's Encrypt 使用 fullchain.pem)
# 强制客户端使用 TLSrequire_certificate false # false = 单向认证(服务端向客户端证明身份) # true = 双向认证(客户端也需提供证书)
# 仅允许 TLS 1.2+tls_version tlsv1.2
# 推荐加密套件ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384单向认证 vs 双向认证:
- 单向(
require_certificate false):仅客户端验证服务端,适合用户名密码认证场景 - 双向(
require_certificate true):双方互相验证,需为每个设备签发客户端证书,安全性最高但证书管理成本大
生产环境如果设备端能安全存储证书,推荐双向认证;如果设备能力有限,单向 TLS + 用户名密码也是可接受方案。
4.4 认证后端选择
密码文件(适合少量设备):
password_file /etc/mosquitto/passwd使用 mosquitto_passwd 工具管理(详见第 5 章)。
动态认证插件(适合大规模设备):
Mosquitto 从 2.0 版本起支持动态认证插件。可以对接 HTTP API、MySQL、Redis 等后端,实现用户认证的集中管理和动态更新。
# 使用 mosquitto-go-auth 插件auth_plugin /usr/lib/mosquitto-go-auth.soauth_opt_backends httpauth_opt_http_host http://auth.internal:8080auth_opt_http_path /authauth_opt_http_aclcheckpath /acl动态认证的优点:无需重启 Mosquitto 即可添加/修改/删除用户;与现有用户系统集成;支持 JWT、OAuth2 等现代认证方式。
4.5 ACL 权限控制
acl_file /etc/mosquitto/aclACL(Access Control List)控制谁可以发布/订阅哪些主题。核心原则:最小权限——设备只能在自己需要的主题上操作。
# 最小权限模板示例# 每个设备只允许操作自己的主题前缀
# 普通传感器设备:只能上报数据user sensor_001topic write devices/sensor_001/telemetry/#topic read devices/sensor_001/config/#
# 控制网关:可以发送指令user gateway_001topic read devices/+/telemetry/#topic write devices/+/commands/#
# 运维管理员:全局读写user admintopic readwrite #
# 禁止所有用户访问系统主题pattern readwrite $SYS/#user 针对具体用户名;pattern 针对匹配用户名的模式(如 pattern readwrite devices/%u/# 允许每个用户操作自己的主题)。%u 自动替换为当前用户名。
5. 用户与权限管理实战
5.1 使用 mosquitto_passwd 管理密码文件
密码文件使用 mosquitto_passwd 工具管理。每条记录一行,格式为 username:password_hash。
# 首次创建密码文件(使用 -c 参数)mosquitto_passwd -c /etc/mosquitto/passwd sensor_001
# 添加新用户(注意:不要再加 -c,否则会覆盖已有文件)mosquitto_passwd /etc/mosquitto/passwd sensor_002
# 修改密码(覆盖已存在的用户)mosquitto_passwd /etc/mosquitto/passwd sensor_001
# 删除用户mosquitto_passwd -D /etc/mosquitto/passwd sensor_002
# 查看已加密的密码文件(密码已哈希,不可逆)cat /etc/mosquitto/passwd常见问题: 误用 -c 覆盖已有密码文件导致所有用户丢失。建议用版本控制备份密码文件,或在变更前 cp 备份。
5.2 ACL 文件编写规范
ACL 文件的规则从上到下匹配,命中即停止。权限关键字:
| 关键字 | 含义 |
|---|---|
read | 允许订阅 |
write | 允许发布 |
readwrite | 允许订阅和发布 |
deny | 显式拒绝 |
user 与 pattern 的区别:
user <username>:精确匹配用户名pattern <pattern>:匹配模式,支持%u(用户名)和%c(客户端 ID)
# 典型场景 1:设备遥测上报user sensor_001topic write devices/sensor_001/telemetry/#topic read devices/sensor_001/commands/#
# 典型场景 2:使用 pattern 实现每个用户操作自己的主题空间pattern readwrite devices/%u/#
# 典型场景 3:状态查询(设备可以读取全局状态但不能写入)user status_monitortopic read devices/+/status/#topic deny write #
# 典型场景 4:控制指令下发(应用后端)user backend_servicetopic read devices/+/telemetry/#topic write devices/+/commands/#
# 全局禁止:禁止访问系统内部主题pattern deny $SYS/#通配符说明: ACL 中的 # 匹配所有子主题,相当于”允许该前缀下的一切”。如果需要对单个通配符做更精细的控制,逐一列出主题路径。
5.3 动态权限方案:HTTP 认证 + ACL 插件集成
当设备数量达到数千级时,静态文件管理变得不切实际。推荐使用 mosquitto-go-auth 插件对接外部认证服务。
架构示意:
设备 → TLS → Mosquitto → auth_plugin → HTTP API → 用户数据库/ACL 服务mosquitto.conf 配置示例:
auth_plugin /usr/lib/mosquitto-go-auth.so
# 认证后端:HTTP APIauth_opt_backends httpauth_opt_http_host http://auth.example.comauth_opt_http_port 8080auth_opt_http_getuser_uri /api/mqtt/userauth_opt_http_superuser_uri /api/mqtt/superuserauth_opt_http_aclcheck_uri /api/mqtt/acl
# 缓存(减少认证请求压力)auth_opt_cache trueauth_opt_cache_duration 60auth_opt_cache_type go-cacheHTTP API 需要实现三个端点:
GET /api/mqtt/user:验证用户密码,返回 200 表示通过GET /api/mqtt/superuser:检查是否为超级用户GET /api/mqtt/acl:检查 ACL 权限
自行实现时注意: 认证接口需要低延迟(< 10ms),因为每次连接和发布/订阅操作都会触发。建议在 Mosquitto 本机或同机房部署认证服务,并对结果做本地缓存。
2.1 提示: Mosquitto 2.1 采用全新的 C 插件系统替代旧版
auth_plugin架构,mosquitto-go-auth等基于旧插件 API 的扩展在 2.1 上无法直接使用。2.1 用户需使用内置插件接口或等待社区适配。更多信息参考 Mosquitto 2.1 迁移指南。2.1 提示补充:从 2.0 升级至 2.1 涉及多个重大变更(如
per_listener_settings已在 2.1 中完全移除,不再可用、max_packet_size默认值调整)。请务必参考 官方迁移指南 完成平滑升级。
6. 高可用与桥接
6.1 Mosquitto 桥接原理
Mosquitto Bridge 本质是将一台 Broker 作为另一台的客户端,在两个 Broker 之间同步消息。它是实现跨机房、跨网段消息同步的核心机制。
桥接不是集群——两台 Broker 各自独立,只是互相转发对方关心的消息。消息不会在集群节点间路由或负载均衡。
6.2 双节点双向桥接配置
节点 A 配置(mosquitto.conf):
# 节点 A 连接到节点 Bconnection bridge-to-baddress node-b.example.com:8883
# 使用 TLSbridge_cafile /etc/mosquitto/certs/ca.crtbridge_certfile /etc/mosquitto/certs/node-a.crtbridge_keyfile /etc/mosquitto/certs/node-a.key
# 认证remote_username bridge_userremote_password bridge_password
# 主题映射:将本地消息同步到远端topic devices/# both 1
# 防止消息环路bridge_attempt_unsubscribe truetry_private true
# 断开时清理远端订阅cleansession true
# 自动重连start_type automaticrestart_timeout 10 30
# 桥接心跳keepalive_interval 60节点 B 做镜像配置(address 指向节点 A)。
topic 映射语法: topic <topic_pattern> <direction> <qos> <local_prefix> <remote_prefix>
direction:in(仅收)、out(仅发)、both(双向)local_prefix/remote_prefix:在两端添加前缀,用于避免主题名冲突
避免消息环路的关键参数:
try_private true:告知远端 Broker 此连接是桥接,远端会为桥接消息设置特殊标志,避免回环bridge_attempt_unsubscribe true:桥接断连时,远端 Broker 自动取消该桥接持有的所有订阅
6.3 负载均衡与客户端分发
Mosquitto 本身不支持内置负载均衡。需要在 Broker 前面加一层 TCP 代理(Nginx Stream 或 HAProxy),将客户端连接到不同的 Broker 节点。
HAProxy 配置示例:
frontend mqtt_frontend bind *:8883 ssl crt /etc/haproxy/certs/mqtt.pem mode tcp default_backend mqtt_backend
backend mqtt_backend mode tcp balance leastconn # 按连接数最少分发 server broker1 10.0.0.1:8883 check server broker2 10.0.0.2:8883 check注意事项:
- 负载均衡必须是 TCP 层(Layer 4),不能用 HTTP 层(MQTT 不是 HTTP 协议)
balance leastconn适合 MQTT 长连接场景(连接数均分)- 分发后客户端固定连到同一后端(stick-table / persistence),避免会话状态丢失
- 如果 Broker 间没有桥接,连到不同 Broker 的客户端互相看不到对方的消息
6.4 高可用方案局限性与替代方案
Mosquitto 桥接的局限:
- 桥接是异步的,存在消息延迟(通常几十毫秒到数秒)
- 不保证分布式一致性——两台 Broker 各有一个持久化存储,数据并不总是同步
- 不支持共享订阅:同一主题分发到不同节点上的订阅者时无法负载均衡
- 客户端需要自行处理断线重连和重新订阅(Clean Session)
- 没有内置故障检测和自动故障转移
替代方案:
- EMQX Enterprise:商业版支持真正的集群,内置高可用和自动故障转移,单集群可支持百万级连接
- VerneMQ:开源 Erlang 实现,天然支持集群,共享订阅和会话持久化
- NanoMQ:边缘端超轻量 Broker,适合与 EMQX 配合形成边缘+云端架构
选型建议:如果设备量持续增长且高可用是硬性要求,尽早切换到集群型 Broker 比在 Mosquitto 上不断打补丁更经济。
7. 将 Mosquitto 作为系统服务运行
7.1 Systemd 服务文件编写
包管理器安装的 Mosquitto 通常自带 systemd 单元。自定义编译或需要调优时,可手写服务文件:
[Unit]Description=Mosquitto MQTT BrokerDocumentation=man:mosquitto(8)After=network-online.targetWants=network-online.target
[Service]Type=simpleExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.confExecReload=/bin/kill -HUP $MAINPIDRestart=on-failureRestartSec=5s
# 安全加固(Kubernetes 等特定环境可能需要 MOSQUITTO_UNSAFE_ALLOW_SYMLINKS 环境变量)User=mosquittoGroup=mosquittoNoNewPrivileges=yesPrivateTmp=yesProtectSystem=strictReadWritePaths=/var/lib/mosquitto /var/log/mosquittoReadOnlyPaths=/etc/mosquitto/certs
# 资源限制LimitNOFILE=100000MemoryMax=1GTasksMax=1024
[Install]WantedBy=multi-user.target关键参数说明:
Type=simple:Mosquitto 是前台进程,用 simple 即可(Mosquitto 2.0+ 也支持Type=notify配合-d参数,但 simple 更通用)ExecReload=/bin/kill -HUP $MAINPID:发送 SIGHUP 信号,Mosquitto 会重新加载配置而不会断开现有连接LimitNOFILE=100000:覆盖系统默认的文件描述符限制ProtectSystem=strict:只允许写明确指定的路径
7.2 开机自启与服务管理
# 重新加载 systemd 配置sudo systemctl daemon-reload
# 开机自启sudo systemctl enable mosquitto
# 启动服务sudo systemctl start mosquitto
# 查看状态sudo systemctl status mosquitto
# 重载配置(不中断连接)sudo systemctl reload mosquitto
# 重启服务sudo systemctl restart mosquitto
# 查看日志sudo journalctl -u mosquitto -f配置变更流程(零停机):
- 修改
/etc/mosquitto/mosquitto.conf - 执行
mosquitto -c /etc/mosquitto/mosquitto.conf --check检查配置语法 sudo systemctl reload mosquitto(SIGHUP 重载)- 检查日志确认新配置生效
- 如果配置变更涉及 listener 端口,需要
restart而非reload
8. 监控、日志与运维
8.1 日志配置与轮转
Mosquitto 日志配置:
log_dest file /var/log/mosquitto/mosquitto.loglog_type errorlog_type warninglog_type noticelog_type informationconnection_messages truelog_timestamp truelog_timestamp_format %Y-%m-%dT%H:%M:%Sconnection_messages:记录每次客户端连接/断开事件——排查设备掉线问题必备log_timestamp_format:ISO 8601 格式便于日志分析工具解析
logrotate 配置:
/var/log/mosquitto/mosquitto.log { daily rotate 30 missingok notifempty compress delaycompress postrotate /bin/kill -HUP $(cat /var/run/mosquitto/mosquitto.pid 2>/dev/null) 2>/dev/null || true endscript}8.2 内置主题监控($SYS)
Mosquitto 通过 $SYS 主题层级暴露内部运行状态。需要在配置中启用:
sys_interval 60 # 每60秒更新一次 $SYS 主题关键监控指标:
| 主题 | 说明 |
|---|---|
$SYS/broker/clients/connected | 当前连接数 |
$SYS/broker/clients/maximum | 历史最大连接数 |
$SYS/broker/messages/received | 累计接收消息 |
$SYS/broker/messages/sent | 累计发送消息 |
$SYS/broker/messages/stored | 当前持久化存储的消息数 |
$SYS/broker/bytes/received | 累计接收字节 |
$SYS/broker/bytes/sent | 累计发送字节 |
$SYS/broker/heap/current | 当前堆内存使用量 |
$SYS/broker/store/messages/count | 持久化存储消息计数 |
$SYS/broker/version | Broker 版本 |
$SYS/broker/version 主题可用于在混合版本环境中确认各节点版本。
注意: $SYS 主题默认仅允许本地连接查看。如果远程查看,需要在 ACL 中显式放行,但这会暴露内部信息——通常不推荐。
8.3 对接外部监控
Prometheus + mosquitto_exporter:
# 拉取并运行 mosquitto_exporterdocker run -d \ --name mosquitto-exporter \ -p 9234:9234 \ -e MOSQUITTO_URL=mqtt://localhost:1883 \ sapcc/mosquitto-exportermosquitto_exporter 作为 MQTT 客户端订阅 $SYS/# 主题,将指标转为 Prometheus 格式。配合 Grafana 仪表盘实现可视化监控。
关键告警规则:
groups: - name: mosquitto rules: - alert: HighConnectionCount expr: mosquitto_clients_connected > 50000 for: 5m labels: severity: warning annotations: summary: "Mosquitto 连接数超过 50000"
- alert: BrokerDown expr: up{job="mosquitto"} == 0 for: 1m labels: severity: critical annotations: summary: "Mosquitto Broker 宕机"8.4 定期健康检查脚本
#!/bin/bashBROKER="localhost"PORT="8883"TOPIC="health/check/$(hostname)"MESSAGE="ok-$(date +%s)"CAFILE="/etc/mosquitto/certs/ca.crt"
# 发布并订阅——验证完整的发布/订阅链路timeout 10 mosquitto_sub \ --cafile "$CAFILE" \ -h "$BROKER" -p "$PORT" \ -t "$TOPIC" -C 1 &SUB_PID=$!
sleep 1
timeout 5 mosquitto_pub \ --cafile "$CAFILE" \ -h "$BROKER" -p "$PORT" \ -t "$TOPIC" -m "$MESSAGE"
wait $SUB_PID 2>/dev/nullEXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then echo "[OK] MQTT broker is healthy" exit 0else echo "[ERROR] MQTT broker health check failed" exit 1fi将脚本加入 cron 或监控调度器,每分钟执行一次。
9. 性能调优
9.1 系统级调优
# 增加 TCP 缓冲区net.core.rmem_max = 8388608net.core.wmem_max = 8388608net.ipv4.tcp_rmem = 4096 87380 8388608net.ipv4.tcp_wmem = 4096 65536 8388608
# 启用 TCP Fast Open(减少 TLS 握手延迟)net.ipv4.tcp_fastopen = 3
# 增大 backlognet.core.somaxconn = 4096net.ipv4.tcp_max_syn_backlog = 4096
# TIME_WAIT 优化net.ipv4.tcp_tw_reuse = 1应用配置:
sudo sysctl -p /etc/sysctl.d/99-mosquitto.conf确保文件描述符限制已配置(见 2.1 节)。
9.2 Mosquitto 调优参数
# 最大连接数(根据服务器能力设置,避免 OOM)max_connections 100000
# 单次可发送的最大未确认消息数(飞行窗口)# QoS 1/2 场景尤其重要——过低影响吞吐,过高消耗内存max_inflight_messages 20
# 单客户端最大队列消息数(QoS 1/2 离线消息)# 过大可能导致客户端重连时一次性推送过多消息max_queued_messages 1000
# 最大消息体大小(默认无限制)message_size_limit 256K
# TCP_NODELAY:禁用 Nagle 算法,降低延迟# 对 MQTT 这种小消息频繁发送的场景提升明显set_tcp_nodelay true参数调优优先级(由高到低):
set_tcp_nodelay true——立竿见影降低延迟max_inflight_messages——根据客户端网络质量调整。局域网可设 50-100;公网 IoT 建议 10-20max_queued_messages——内存和离线可靠性之间的权衡
9.3 持久化与 autosave 频率调优
# 持久化保存间隔(秒)autosave_interval 300
# 消息变更次数达到阈值时立即保存(不等 autosave_interval)autosave_on_changes true
# 持久化时是否只保存变更(增量保存,减少 IO)persistence truepersistence_location /var/lib/mosquitto/权衡: autosave_interval 越短,重启后丢失的持久化消息越少,但磁盘 IO 越高。10000 设备以下的规模,300 秒是合适值。如果每条消息都至关重要(如计费数据),降低到 60 秒。
如果消息量极大且不需要 Broker 保留离线消息(客户端重连后从上游重新拉取),将 QoS 0 作为默认值可大幅降低持久化压力。
10. 测试与验证
10.1 基本发布/订阅测试
# 终端1:订阅mosquitto_sub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t "test/#" -v
# 终端2:发布mosquitto_pub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t "test/hello" -m "hello world"
# QoS 1 测试(要求确认)mosquitto_pub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t "test/qos1" -m "qos1" -q 1
# 保留消息测试mosquitto_pub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t "test/retained" -m "retained" -r# 新开订阅窗口,应立即收到 retained 消息mosquitto_sub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t "test/retained" -C 110.2 TLS 连接测试
# 单向 TLS 测试mosquitto_sub -h mqtt.example.com -p 8883 \ --cafile /etc/ssl/certs/ca-certificates.crt \ -t "test/tls" -v
# 双向 TLS 测试(客户端提供证书)mosquitto_sub -h mqtt.example.com -p 8883 \ --cafile /etc/mosquitto/certs/ca.crt \ --cert /etc/mosquitto/certs/client.crt \ --key /etc/mosquitto/certs/client.key \ -t "test/tls" -v
# 使用 openssl 验证证书链openssl s_client -connect mqtt.example.com:8883 -showcerts10.3 认证与 ACL 权限测试
# 用户名密码认证测试mosquitto_pub -h localhost -p 8883 \ --cafile /etc/mosquitto/certs/ca.crt \ -u sensor_001 -P "password123" \ -t "devices/sensor_001/telemetry/temperature" -m "25.5"
# 验证 ACL 拒绝:尝试写入无权主题(应失败)mosquitto_pub -h localhost -p 8883 \ --cafile /etc/mosquitto/certs/ca.crt \ -u sensor_001 -P "password123" \ -t "devices/sensor_002/telemetry/temperature" -m "25.5"# 预期:Connection Refused: not authorised
# 验证 $SYS 主题禁止访问mosquitto_sub -h localhost -p 8883 \ --cafile /etc/mosquitto/certs/ca.crt \ -u sensor_001 -P "password123" \ -t '$SYS/broker/clients/connected'# 预期:Connection Refused: not authorised10.4 性能基准测试工具
mqtt-benchmark(Go 实现,轻量推荐):
# 安装go install github.com/krylovsk/mqtt-benchmark@latest
# 1000 个客户端,每个每秒发 10 条消息,持续 60 秒mqtt-benchmark \ --broker tcp://localhost:8883 \ --count 1000 \ --size 100 \ --clients 100 \ --qos 1 \ --time 60 \ --username "bench_user" \ --password "bench_pass"emqtt-bench(Erlang 实现,高并发基准测试):
# 10 万连接建立测试emqtt_bench conn -h localhost -p 8883 -c 100000解释关键指标:
- 连接建立速率(conn/s):系统接受新连接的效率
- 消息吞吐(msg/s):实际生产负载能力
- 端到端延迟(p99):99% 的消息在多少毫秒内送达
11. 备份与灾难恢复
11.1 需要备份的内容
| 备份项 | 路径 | 重要性 |
|---|---|---|
| 配置文件 | /etc/mosquitto/mosquitto.conf | 高(恢复后即可启动) |
| 密码文件 | /etc/mosquitto/passwd | 高(丢失则所有设备无法认证) |
| ACL 文件 | /etc/mosquitto/acl | 高 |
| TLS 证书 | /etc/mosquitto/certs/ | 高 |
| 桥接配置 | /etc/mosquitto/conf.d/ | 中(如有桥接) |
| 持久化数据库 | /var/lib/mosquitto/mosquitto.db | 低(离线消息丢了影响有限) |
11.2 自动化备份脚本
#!/bin/bashBACKUP_DIR="/backup/mosquitto/$(date +%Y%m%d_%H%M%S)"RETENTION_DAYS=30
mkdir -p "$BACKUP_DIR"
cp -r /etc/mosquitto "$BACKUP_DIR/config"cp /var/lib/mosquitto/mosquitto.db "$BACKUP_DIR/" 2>/dev/null || true
# 打包tar czf "$BACKUP_DIR.tar.gz" -C "$(dirname "$BACKUP_DIR")" "$(basename "$BACKUP_DIR")"rm -rf "$BACKUP_DIR"
# 清理 30 天前的旧备份find /backup/mosquitto -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $BACKUP_DIR.tar.gz"cron 定时执行:
0 2 * * * /usr/local/bin/mosquitto-backup.sh >> /var/log/mosquitto-backup.log 2>&111.3 从备份恢复并验证
# 1. 停止 Mosquittosudo systemctl stop mosquitto
# 2. 解压备份BACKUP_FILE="/backup/mosquitto/20260516_020000.tar.gz"tar xzf "$BACKUP_FILE" -C /tmp/restore
# 3. 恢复配置文件sudo cp /tmp/restore/*/config/mosquitto.conf /etc/mosquitto/sudo cp /tmp/restore/*/config/passwd /etc/mosquitto/sudo cp /tmp/restore/*/config/acl /etc/mosquitto/sudo cp /tmp/restore/*/config/certs/* /etc/mosquitto/certs/
# 4. 恢复持久化数据(可选)sudo cp /tmp/restore/*/mosquitto.db /var/lib/mosquitto/sudo chown mosquitto:mosquitto /var/lib/mosquitto/mosquitto.db
# 5. 检查配置mosquitto -c /etc/mosquitto/mosquitto.conf --check
# 6. 启动并验证sudo systemctl start mosquittosudo systemctl status mosquittomosquitto_sub -h localhost -t "test" -C 112. 版本升级策略
12.1 升级前兼容性检查
# 查看当前版本mosquitto -h | head -1
# 备份(升级前必须做)sudo systemctl stop mosquittosudo tar czf /backup/mosquitto-pre-upgrade-$(date +%Y%m%d).tar.gz /etc/mosquitto /var/lib/mosquitto
# 检查配置兼容性(用新版本检查旧配置)# 下载新版本但不安装,用 --check 模式验证/path/to/new/mosquitto -c /etc/mosquitto/mosquitto.conf --check重点关注:Eclipse Mosquitto 发布说明 中的 Breaking Changes 部分。2.0 版本引入了大量不兼容变更(如默认仅监听 localhost、需显式配置 listener 和 allow_anonymous)。
12.2 原地升级步骤
# 1. 备份(见 12.1)
# 2. 停止旧版本sudo systemctl stop mosquitto
# 3. 升级(Ubuntu 示例)sudo apt updatesudo apt install --only-upgrade mosquitto mosquitto-clients
# 4. 检查配置(如果包管理器提示配置冲突,选择保留旧配置,手动合并)diff /etc/mosquitto/mosquitto.conf /etc/mosquitto/mosquitto.conf.dpkg-new
# 5. 启动新版本sudo systemctl start mosquittosudo systemctl status mosquittojournalctl -u mosquitto -n 20 --no-pager12.3 回退方案
# 降级到旧版本(已知旧版本号的情况)sudo apt install mosquitto=2.0.18-0mosquitto1~ubuntu22.04.1
# 或从备份完全恢复sudo systemctl stop mosquittotar xzf /backup/mosquitto-pre-upgrade-20260516.tar.gz -C /sudo systemctl start mosquitto升级后至少观察 24 小时,确认连接数、消息吞吐等指标正常,再视为升级成功。
13. 常见问题排查
无法绑定端口 / 权限拒绝
Error: Unable to bind to port 8883原因:端口已被占用,或非 root 用户绑定 1024 以下端口。
排查:
# 检查端口占用ss -tlnp | grep 8883
# 检查 SELinux(RHEL 系列)sudo ausearch -m avc -ts recent | grep mosquitto解决:如果 Mosquitto 以非 root 用户运行,用 setcap 授权:
sudo setcap 'cap_net_bind_service=+ep' /usr/sbin/mosquittoTLS 握手失败
OpenSSL Error: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed常见原因:
- 证书过期:
openssl x509 -in /etc/mosquitto/certs/server.crt -noout -dates - 客户端未指定 CA 证书(单向认证时需
--cafile参数) - 加密套件不匹配:客户端 TLS 版本过低
- 证书中的 CN/SAN 与客户端连接的域名不匹配
ACL 限制导致订阅失败
Connection Refused: not authorised定位方法:
# 查看 Mosquitto 日志sudo grep "denied" /var/log/mosquitto/mosquitto.log# 输出示例:1727848012: Denied PUBLISH to devices/sensor_002/data for sensor_001根据日志中的用户名和主题调整 ACL 文件中的规则。
大量 “connection refused” — 文件描述符上限
Error: Too many open files检查:
# 查看进程的 fd 限制cat /proc/$(pidof mosquitto)/limits | grep "open files"
# 查看当前 fd 使用量ls /proc/$(pidof mosquitto)/fd | wc -l如超出限制,按 2.1 节和 7.1 节增大 nofile 限制。
内存异常增长
常见原因:max_queued_messages 设置过大(如 0 表示无限),大量离线客户端堆积 QoS 1/2 消息。
排查:
# 查看堆内存使用mosquitto_sub -t '$SYS/broker/heap/current' -C 1
# 查看存储消息数mosquitto_sub -t '$SYS/broker/store/messages/count' -C 1调小 max_queued_messages(如 500-1000),确认 autosave_interval 合理。
客户端频繁重连(遗嘱消息风暴)
现象:Broker 发布大量遗嘱消息,客户端反复重连。
可能原因:
- 客户端超时设置过短,网络波动时频繁触发遗嘱
- Broker 处理能力不足,导致心跳超时
解决:
- 增大客户端的
keepalive参数(如从 30s 提升到 120s) - 检查 Broker 是否 CPU 或 IO 饱和——用
$SYS主题或top排查
14. 附录
14.1 生产环境完整 mosquitto.conf 模板
# ============================================================# Mosquitto MQTT Broker - 生产就绪配置模板# 适用版本:2.0.x(2.1 用户请参考官方迁移指南,大部分基础配置仍兼容。注意:在 2.1.x 中,原 acl_file 和 password_file 的功能已由官方插件 mosquitto_acl_file 与 mosquitto_password_file 提供,配置方式有所变化,具体请查阅官方迁移指南。)# ============================================================
# --- 基础参数 ---pid_file /var/run/mosquitto/mosquitto.piduser mosquitto
# --- 日志 ---log_dest file /var/log/mosquitto/mosquitto.loglog_type errorlog_type warninglog_type noticelog_type informationconnection_messages truelog_timestamp truelog_timestamp_format %Y-%m-%dT%H:%M:%S
# --- 持久化 ---persistence truepersistence_location /var/lib/mosquitto/autosave_interval 300autosave_on_changes true
# --- 网络:仅 TLS(禁用明文) ---# 不配置 listener 1883,强制所有客户端使用 TLS
listener 8883protocol mqtt
# --- TLS 证书(单向认证) ---certfile /etc/mosquitto/certs/server.crtkeyfile /etc/mosquitto/certs/server.keycafile /etc/mosquitto/certs/ca.crtrequire_certificate falsetls_version tlsv1.2ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
# --- WebSocket(按需启用) ---# listener 9001# protocol websockets
# --- 认证 ---allow_anonymous falsepassword_file /etc/mosquitto/passwd
# --- 权限控制 ---acl_file /etc/mosquitto/acl
# --- 性能 ---max_connections 100000max_inflight_messages 20max_queued_messages 1000message_size_limit 256Kset_tcp_nodelay true
# --- 系统监控(仅限本地访问) ---sys_interval 60
# --- 自定义配置目录(拆分配置文件) ---include_dir /etc/mosquitto/conf.d14.2 常用 mosquitto_passwd 命令速查
# 创建密码文件(首次)mosquitto_passwd -c /etc/mosquitto/passwd <username>
# 添加用户mosquitto_passwd /etc/mosquitto/passwd <username>
# 删除用户mosquitto_passwd -D /etc/mosquitto/passwd <username>
# 批量添加(脚本)while IFS=: read -r user pass; do mosquitto_passwd -b /etc/mosquitto/passwd "$user" "$pass"done < users.txt
# 重载密码文件(不重启 Mosquitto)sudo systemctl reload mosquitto # 或 kill -HUP $(pidof mosquitto)14.3 ACL 文件最佳实践示例
# ============================================================# ACL 文件最佳实践# ============================================================
# 规则 1:超级管理员(全局读写)user admintopic readwrite #
# 规则 2:后端服务(可读所有设备数据,可发控制指令)user backendtopic read devices/+/telemetry/#topic read devices/+/status/#topic write devices/+/commands/#topic readwrite health/#
# 规则 3:使用 pattern 为每个设备创建独立主题空间# %u 自动替换为用户名pattern read devices/%u/telemetry/#pattern write devices/%u/telemetry/#pattern readwrite devices/%u/config/#
# 规则 4:只读监控用户user monitortopic read devices/+/status/#
# 规则 5:公共主题(所有认证用户可读)pattern read public/#
# 规则 6:全局禁止访问系统主题(放在最后)pattern deny $SYS/#参考资源: