4. Mosquitto Broker 部署与配置:从源码到生产环境
这一章,我们来啃 Mosquitto Broker 这块硬骨头。很多初学者喜欢直接 apt install,但在嵌入式 Linux 网关这种资源受限、环境各异的地方,交叉编译才是王道。我自己的习惯是,只要目标板不是 x86,一律走源码交叉编译——这样心里踏实。
4.1 源码交叉编译:别怕,步骤其实很固定
交叉编译 Mosquitto 并不复杂,但有几个坑。我曾经在一个 ARM Cortex-A7 平台上栽过跟头,因为忘了指定 WITH_TLS 导致编译出来的 Broker 不支持加密连接,后来全部重来。嗯,这里要注意。
先准备好工具链,假设你的交叉编译器是 arm-linux-gnueabihf-gcc。下载 Mosquitto 源码后,进入目录,核心配置就这几步:
# 设置交叉编译环境变量
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export AR=arm-linux-gnueabihf-ar
export STRIP=arm-linux-gnueabihf-strip
# 配置编译选项
make WITH_SRV=no \
WITH_DOCS=no \
WITH_TLS=yes \
WITH_TLS_PSK=no \
WITH_THREADING=yes \
CFLAGS="-I/path/to/openssl/include" \
LDFLAGS="-L/path/to/openssl/lib"
这里我解释一下几个关键选项:
| 选项 | 说明 | 我的建议 |
|---|---|---|
WITH_TLS=yes |
启用 TLS/SSL 支持 | 必须开启,除非你只在隔离内网跑 |
WITH_THREADING=yes |
启用多线程 | 建议开启,提升并发性能 |
WITH_DOCS=no |
不编译文档 | 嵌入式环境省空间,果断关掉 |
WITH_SRV=no |
禁用 DNS SRV 记录 | 大多数场景用不到,关掉减少依赖 |
编译完成后,src/mosquitto 就是我们要的 Broker 可执行文件。用 file 命令确认一下架构:
$ file src/mosquitto
src/mosquitto: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked
看到 ARM 字样,说明交叉编译成功了。然后 make install 或者手动把二进制和配置文件拷贝到目标板上。
DESTDIR=/tmp/mosquitto_install,这样所有输出文件都会集中到临时目录,方便一次性打包拷贝到目标板。
4.2 配置文件详解:别被那么多参数吓到
Mosquitto 的配置文件默认是 /etc/mosquitto/mosquitto.conf。说实话,刚接触时我也觉得选项太多,但真正核心的就那么几个。你想想看,一个 Broker 无非就是:监听端口、认证方式、权限控制、日志和持久化。
4.2.1 监听端口与绑定地址
# 默认监听1883(非加密)
listener 1883 0.0.0.0
# 加密监听8883端口
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
# 只监听本地回环(用于内部进程通信)
listener 1884 localhost
我个人习惯把非加密端口绑定到内网接口,加密端口暴露给外网。曾经有个项目,我把 1883 端口绑到了 0.0.0.0,结果被安全扫描扫出来,被客户怼了一顿。从那以后,我对外网端口一律只开 8883。
4.2.2 认证配置:从匿名到用户名密码
默认情况下 Mosquitto 允许匿名连接。这在开发阶段很方便,但生产环境必须关掉。
# 禁止匿名访问
allow_anonymous false
# 指定密码文件
password_file /etc/mosquitto/passwd
# 生成密码文件(在目标板上执行)
mosquitto_passwd -c /etc/mosquitto/passwd admin
# 然后输入两次密码
这里有个坑:mosquitto_passwd 生成的密码文件是明文哈希,不是加密的。所以文件权限一定要设置成 600,属主是 mosquitto 用户。
mosquitto_passwd /etc/mosquitto/passwd newuser,不要加 -c 参数,否则会覆盖已有用户。
4.2.3 ACL:精细控制谁可以做什么
ACL(访问控制列表)是 Mosquitto 的权限管理核心。说白了,就是定义某个用户能订阅哪些主题、能发布哪些主题。
# 启用ACL
acl_file /etc/mosquitto/acl
# acl 文件内容示例
# 只允许admin用户订阅所有主题
user admin
topic readwrite #
# 允许sensor用户只发布到sensors/主题
user sensor
topic write sensors/#
# 允许app用户只订阅sensors/主题
user app
topic read sensors/#
# 匿名用户只能读取public/主题
topic read public/#
我曾经在一个智慧农业项目中,因为 ACL 配置太宽松,导致一个传感器误发布了控制指令,把大棚的卷帘机给打开了。嗯,从那以后我对 ACL 的配置就格外小心——最小权限原则,能不给写权限就坚决不给。
4.2.4 TLS 配置:让数据在网络上裸奔?不存在的
TLS 配置其实不复杂,核心就是三件套:CA 证书、服务器证书、服务器私钥。我建议用自签名证书做内部测试,生产环境还是用正规 CA 签发的证书。
# TLS 配置
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
tls_version tlsv1.2
require_certificate false
require_certificate false 表示客户端不需要提供证书,只用用户名密码认证。如果设置为 true,那就是双向认证,安全性更高,但管理成本也上去了。
4.3 Mosquitto 作为系统服务运行
交叉编译出来的 Mosquitto 默认不会自启动。我们需要写一个 Systemd 服务文件,让它随系统启动。
# /etc/systemd/system/mosquitto.service
[Unit]
Description=Mosquitto MQTT Broker
After=network.target
[Service]
Type=simple
User=mosquitto
Group=mosquitto
ExecStart=/usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
然后执行:
systemctl daemon-reload
systemctl enable mosquitto
systemctl start mosquitto
systemctl status mosquitto
这里我踩过一个坑:User=mosquitto 这个用户必须存在,而且要对日志目录、持久化目录有写权限。否则 Broker 启动后直接报错退出。记得先创建用户:
adduser --system --group --no-create-home mosquitto
mkdir -p /var/log/mosquitto /var/lib/mosquitto
chown -R mosquitto:mosquitto /var/log/mosquitto /var/lib/mosquitto
4.4 Broker 性能测试与调优
Broker 部署好了,到底能扛多少并发?延迟怎么样?别猜,用数据说话。我常用的压测工具是 mosquitto_pub 和 mosquitto_sub 的组合,以及 mqtt-bench 这个开源工具。
4.4.1 基础压测命令
# 启动一个订阅者
mosquitto_sub -h 192.168.1.100 -t "test/#" -q 1 &
# 用100个并发客户端发布消息
for i in $(seq 1 100); do
mosquitto_pub -h 192.168.1.100 -t "test/$i" -m "hello" -q 1 -d &
done
用 top 或者 htop 观察 CPU 和内存占用。如果 CPU 飙到 100%,说明 Broker 处理不过来,需要调优。
4.4.2 核心调优参数
| 参数 | 默认值 | 调优建议 |
|---|---|---|
max_connections |
1024 | 根据硬件内存调整,每连接约消耗 4KB |
max_inflight_messages |
20 | 网络不稳定时可适当增大到 50-100 |
max_queued_messages |
100 | 订阅者离线时缓存的消息数,根据业务调整 |
persistence |
false | 需要消息持久化时开启,但会降低性能 |
autosave_interval |
1800 | 持久化写入间隔(秒),频繁写入会拖慢性能 |
我个人在嵌入式网关上的经验是:不要开启持久化。嵌入式设备的 Flash 寿命有限,频繁写入会加速损坏。如果非要持久化,用外部数据库或者云端存储。
4.4.3 实战调优案例
我曾经在一个项目里,网关需要同时处理 500 个传感器连接。默认配置下,CPU 占用率 85%,延迟飙到 200ms。经过调优后,CPU 降到 30%,延迟稳定在 10ms 以内。核心改动就这几条:
# 增大连接数
max_connections 1000
# 减少 inflight 消息数,避免内存暴涨
max_inflight_messages 10
# 关闭持久化
persistence false
# 增大线程池(如果编译时开启了 WITH_THREADING)
thread_pool_size 4
4.5 本章知识体系
下面这张图总结了 Mosquitto Broker 从编译到调优的完整链路,你可以把它当作操作手册的索引:
这张图把本章内容串起来了:从源码编译出发,到配置文件的四个核心模块,再到系统服务化,最后用性能测试和调优收尾。每个环节都有坑,也都有对应的解决方案。