4. Mosquitto Broker 部署与配置

这一章我们聊聊 Mosquitto Broker 的实战部署。说实话,我在很多物联网项目里都离不开它——轻量、稳定、社区活跃。但真正把它用好,光会 apt install 可不够。源码交叉编译、配置文件调优、自启动服务、性能摸底,这些才是生产环境的关键。

本章核心脉络:从交叉编译开始,到配置详解,再到服务化与性能测试,一条线走通 Mosquitto 的嵌入式部署全流程。

Mosquitto Broker 部署知识体系 Mosquitto Broker 部署 源码交叉编译 配置文件详解 系统服务自启动 Broker 性能测试 工具链配置 依赖库处理 编译选项 监听端口 认证配置 ACL 规则 systemd 单元 init.d 脚本 mosquitto_sub/pub 吞吐量测试 延迟测试 嵌入式环境:交叉编译是必选项,配置精简是基本功 性能测试:用数据说话,别靠感觉调优

4.1 源码交叉编译:从 PC 到嵌入式板卡

为什么非要源码交叉编译?我遇到过不少朋友直接在开发板上 apt install mosquitto,结果发现版本太老,或者缺少某些功能(比如 TLS 支持)。嵌入式环境里,交叉编译是基本功。

先准备好交叉编译工具链。以 ARM Cortex-A7 为例:

# 设置环境变量
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export AR=arm-linux-gnueabihf-ar
export RANLIB=arm-linux-gnueabihf-ranlib

# 下载 Mosquitto 源码
wget https://mosquitto.org/files/source/mosquitto-2.0.18.tar.gz
tar xzf mosquitto-2.0.18.tar.gz
cd mosquitto-2.0.18

然后配置编译选项。我个人习惯把依赖库都静态链接进去,避免目标板上缺库:

# 配置编译选项
make CC=${CC} CXX=${CXX} \
     CFLAGS="-I/path/to/openssl/include -I/path/to/cjson/include" \
     LDFLAGS="-L/path/to/openssl/lib -L/path/to/cjson/lib" \
     WITH_TLS=yes \
     WITH_SRV=no \
     WITH_WEBSOCKETS=yes \
     WITH_CJSON=yes \
     prefix=/usr/local/mosquitto

make install DESTDIR=/path/to/target/rootfs

我的经验:WITH_WEBSOCKETS 这个选项,如果你的网关需要支持 Web 端 MQTT 连接(比如浏览器直接订阅),一定要打开。我有个项目就是忘了开这个,后来返工重编,浪费时间。

编译完成后,检查一下生成的文件:

# 查看编译产物
file /path/to/target/rootfs/usr/local/mosquitto/sbin/mosquitto
# 输出示例:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked

嗯,确认是 ARM 架构的可执行文件,这一步就对了。

4.2 配置文件详解:监听端口、认证与 ACL

Mosquitto 的配置文件默认在 /etc/mosquitto/mosquitto.conf。说实话,默认配置只能用于开发测试,生产环境必须自己手写。

4.2.1 监听端口配置

最基本的配置就是监听端口。你可以监听多个端口,每个端口绑定不同的协议:

# 标准 MQTT 端口
listener 1883

# 加密 MQTT 端口(TLS)
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false

# WebSocket 端口
listener 8083
protocol websockets

我曾经在项目里踩过一个坑:同时开了 1883 和 8883,但忘了给 8883 配证书,结果客户端连不上。排查了半天才发现是证书路径写错了。

4.2.2 认证配置

认证方式有三种:匿名、密码文件、外部认证。生产环境我强烈建议用密码文件:

# 关闭匿名访问
allow_anonymous false

# 指定密码文件
password_file /etc/mosquitto/passwd

# 创建用户(在目标板上执行)
mosquitto_passwd -c /etc/mosquitto/passwd admin
# 然后输入密码,比如:Admin123!

密码文件是加密存储的,直接 cat 看不到明文。但要注意,mosquitto_passwd 工具必须在目标板上运行,或者用交叉编译版本。

注意:密码文件权限要设置为 600,否则 Mosquitto 会拒绝启动。我见过有人把 passwd 文件设成 777,结果 broker 直接报错退出。

4.2.3 ACL 访问控制

ACL(Access Control List)用来控制每个用户能发布和订阅哪些主题。没有 ACL,任何用户都能往任何主题发消息,那不乱套了?

# 启用 ACL
acl_file /etc/mosquitto/acl

# 示例 ACL 文件内容
# 用户 admin 有所有权限
user admin
topic readwrite #

# 用户 sensor1 只能发布到 sensors/ 下
user sensor1
topic write sensors/#

# 用户 app1 只能订阅 alerts/ 下
user app1
topic read alerts/#

# 匿名用户只能读取 public/ 下
topic read public/#

ACL 的匹配规则是从上到下,第一条匹配就生效。所以要把精确的规则写在前面,宽泛的写在后面。

配置项 作用 生产建议
allow_anonymous 是否允许匿名连接 false(关闭)
password_file 用户密码文件路径 权限 600,放在 /etc/mosquitto/
acl_file 访问控制列表路径 按最小权限原则设计
listener 监听端口与协议 1883+8883 双端口

4.3 Mosquitto 作为系统服务自启动

嵌入式设备经常断电重启,Mosquitto 必须能自动启动。我一般用 systemd,但如果你的板子比较老(比如 Busybox 环境),那就用 init.d 脚本。

4.3.1 systemd 方式(推荐)

创建服务单元文件 /etc/systemd/system/mosquitto.service:

[Unit]
Description=Mosquitto MQTT Broker
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/usr/local/mosquitto/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
User=mosquitto
Group=mosquitto

[Install]
WantedBy=multi-user.target

然后启用并启动:

systemctl daemon-reload
systemctl enable mosquitto
systemctl start mosquitto
systemctl status mosquitto

小技巧:RestartSec=5 的意思是如果崩溃了,等 5 秒再重启。我遇到过因为网络延迟导致启动失败的情况,这个参数能避免频繁重启。

4.3.2 init.d 方式(老系统)

如果你的板子没有 systemd,那就用传统的 init.d 脚本:

#!/bin/sh
# /etc/init.d/mosquitto

case "$1" in
  start)
    echo "Starting Mosquitto..."
    /usr/local/mosquitto/sbin/mosquitto -d -c /etc/mosquitto/mosquitto.conf
    ;;
  stop)
    echo "Stopping Mosquitto..."
    killall mosquitto
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac
exit 0

然后设置开机启动:

chmod +x /etc/init.d/mosquitto
update-rc.d mosquitto defaults

4.4 Broker 性能测试:用数据说话

配置好了,跑起来了,但性能怎么样?别猜,测一下。我习惯用 Mosquitto 自带的 mosquitto_sub 和 mosquitto_pub 做基础测试。

4.4.1 基础连通性测试

# 终端1:订阅主题
mosquitto_sub -h 192.168.1.100 -p 1883 -t "test/topic" -u admin -P "Admin123!"

# 终端2:发布消息
mosquitto_pub -h 192.168.1.100 -p 1883 -t "test/topic" -m "Hello, MQTT!" -u admin -P "Admin123!"

如果终端1收到了 "Hello, MQTT!",说明基本功能正常。

4.4.2 吞吐量测试

用 mosquitto_pub 的 -n 参数可以指定消息数量,配合 -r 看速率:

# 发布 10000 条消息,每条 100 字节
mosquitto_pub -h 192.168.1.100 -t "perf/test" \
              -n 10000 -l -u admin -P "Admin123!" \
              -m "$(python3 -c 'print("A"*100)')"

我一般会记录三个指标:

指标 说明 参考值(ARM Cortex-A7)
消息吞吐量 每秒能处理多少条消息 5000-15000 msg/s
延迟(P99) 99% 的消息延迟上限 < 10ms
并发连接数 同时连接的客户端数量 500-2000

注意:性能数据受硬件、网络、消息大小影响很大。上面是我在某个项目上的实测值,你的环境可能不同。一定要在自己板子上跑一遍。

4.4.3 压力测试工具

如果要做更专业的压力测试,我推荐用 mqtt-benchmark 或者 emqtt_bench。不过对于嵌入式环境,自带的工具已经够用了。

# 用 bash 脚本模拟多客户端
for i in {1..100}; do
  mosquitto_sub -h 192.168.1.100 -t "sensor/$i/data" -u "user$i" -P "pass$i" &
done
# 然后观察 CPU 和内存占用
top -b -n 1 | grep mosquitto

嗯,到这里,Mosquitto 的部署与配置就基本成型了。从交叉编译到配置调优,再到服务自启动和性能摸底,每一步都有讲究。记住一句话:生产环境不要偷懒,该编译的编译,该配置的配置,该测试的测试。