Mosquitto监控与日志管理实战:从$SYS主题到Prometheus告警

发布时间:2026/9/12 2:48:33
Mosquitto监控与日志管理实战:从$SYS主题到Prometheus告警 1. 1 先讲清楚为什么Mosquitto监控与日志管理不是可选项干物联网、嵌入式、智能硬件运维的朋友应该都有这种感觉设备一多消息链路就像早高峰的地铁——谁挤上去了、谁被挤下去了、哪趟车堵在哪了你根本看不见。MQTT Broker在这条链路里就是那个总调度室而Mosquitto作为最主流的开源轻量级Broker被嵌在网关、边缘盒子、树莓派、工控机里的情况实在太常见了。可越是这种“默默蹲在角落跑服务”的角色越容易出问题之后让人抓瞎终端侧疯狂重连、消息莫名延迟、内存悄悄涨满等你接到用户投诉再上去看日志已经被冲掉了一半。这时候你才会意识到“监控与日志管理”这几个字在Mosquitto的日常维护里到底有多重。这篇文章想分享的就是一套从零到一给Mosquitto补上“眼睛和记忆”的完整做法怎么把它的日志配置得又全又不占地方怎么用$SYS主题拿到关键运行指标怎么接进Prometheus、Grafana、Alertmanager这一套现代监控体系以及我这些年排查Broker问题攒下来的一些现场经验。不管你是已经在生产环境跑着几十上百台网关还是正在实验室里调一个嵌入式设备这套思路都能直接用能帮你少踩很多坑。顺便说一句主题虽然是“第13章”但你不用觉得自己必须看到前12章才能上手。这一篇是独立成章的前面没看过的朋友也不影响理解核心的命令、配置、思路我都会从实操角度讲清楚。1.2 监控与日志该从哪几个层面去搭我发现很多朋友一上来就问我“用什么工具监控Mosquitto最屌”这个问法本身就偏了。真正的做法不是先选工具而是先把需求拆开。一套完整的Mosquitto可观测体系至少得覆盖下面三个层面。第一层Broker本身的健康状态。包括进程在不在、CPU和内存占用多少、文件描述符有没有耗尽、线程池有没有打满。这一层管的是“Mosquitto还活着吗、活得好不好”的问题。对单机部署的Mosquitto来说直接看systemd状态和系统指标就够用对跑在容器里的节点那就是看容器资源使用率。第二层Broker的业务运行指标。这一层才是MQTT场景的核心包括当前在线客户端数、每秒收发消息量、订阅总数、持久会话数量、消息丢弃数、字节流量等。这些东西Mosquitto本身没直接给出一份JSON统计文件但它在启动后会在$SYS主题树下持续发布内部计数器我们只需要订阅这些主题就能拿到。第三层行为痕迹与异常线索。也就是日志。谁连上来了、谁断线了、谁发了个非法包、ACL拒绝了什么操作、WebSocket握手失败在哪个环节这些全部要落到日志里。平时日志可以安静躺着一旦出问题它就是第一手犯罪现场。想清楚这三层之后再去看工具选型就顺了。我的推荐组合是系统层用Prometheus node_exporter覆盖面广社区资料多。Broker业务指标用mosquitto_exporter稍后会细讲这个开源组件它负责订阅$SYS主题并转成Metrics格式给Prometheus拉取。日志管理直接用logrotate做本地轮转再配合Promtail Loki或Filebeat ELK做集中式日志检索有条件的可以上没条件的先把本地轮转做好也完全够用。这套组合重量最轻、数据从采集到展示的链路最短非常契合嵌入式网关那种资源有限、网络不稳定的现实条件。2.1 日志级别不是越详细越好但要先知道每个开关在干什么Mosquitto的日志系统配置在它的主配置文件mosquitto.conf里核心参数就两个log_type和log_dest。你只要把这两个参数吃透日志管理就掌握了八成。先看log_type它决定的是记什么。常见取值有这些error仅记录错误正常运行时几乎无输出。warning记录潜在隐患比如客户端用了不推荐的协议版本。notice默认级别记录连接断开等关键生命周期事件。information再细一档会记录订阅、取消订阅、转发等操作。subscribe专门记录订阅和退订操作排查某个客户端为何收到/收不到消息时非常有用。unsubscribe记录退订操作。websockets记录WebSocket连接细节注意这个参数在编译时未启用WebSocket支持的版本里会直接报错先确认你的版本。all打开所有日志包括debug调试信息。debug最啰嗦的级别会刷出协议内部状态日常千万别开生产环境开了基本等于把磁盘和CPU往火坑里推。默认情况下Mosquitto开启的是error加warning加notice加information大概相当于“不吵不闹但关键时刻不掉链子”。我的建议是除非你在排一个特别诡异的协议兼容问题否则别动all和debug。如果真要开debug开完立刻关掉。再看log_dest它决定的是记到哪里。常见取值有stdout、stderr、syslog、file和topic。这五个通道可以同时启用多个写法是每行写一个log_dest。这里我贴一份我在边缘网关上常用的配置注释都写清楚了# /etc/mosquitto/conf.d/logging.conf # 记录哪几类事件 log_type error log_type warning log_type notice log_type information # 输出到系统日志方便用 journalctl -u mosquitto 查看 log_dest syslog # 同时落一份到独立文件方便直接tail观察 log_dest file /var/log/mosquitto/mosquitto.log # 输出带时间戳 log_timestamp true这个组合的好处是syslog通道会让你在用systemd管理的发行版上直接journalctl -u mosquitto -f看到实时日志体验非常顺滑而file通道则保证就算journald被清理了也有一份JSON格式友好的原始文本文件留在磁盘上。如果你习惯用Docker部署Mosquitto我建议把日志直接打到stdout然后交给Docker的json-file日志驱动去统一管理不要自己映射一个日志文件进去否则docker logs看不到东西排查时还得docker exec进去看文件绕了一大圈。2.2 日志轮转一条logrotate配置解决磁盘跑满的隐患日志如果不轮转最直接的结果就是半年后/var分区被一个几十GB的单文件塞满到时候别说监控了系统自己先崩给你看。Linux上管理Mosquitto日志轮转最标准的做法是写一个logrotate规则。大部分发行版的Mosquitto安装包自带了一份路径在/etc/logrotate.d/mosquitto但默认配置可能比较简单我通常都会改成下面这样# /etc/logrotate.d/mosquitto /var/log/mosquitto/mosquitto.log { daily rotate 14 compress delaycompress missingok notifempty copytruncate create 640 mosquitto mosquitto }逐行解释几个关键参数daily每天轮转一次。如果消息量大可以改成size 100M按文件大小触发更省心。rotate 14保留14份历史日志也就是两周的现场数据足够应对大多数问题回溯需求。compress轮转后压缩成gzip省不少磁盘。delaycompress推迟到第二轮再压缩给正在写日志的进程一点缓冲避免压缩工具和写日志进程打架。copytruncate这条是给Mosquitto用的关键。不先复制后清空原文件而是直接把原文件截断。为什么需要它因为Mosquitto进程会一直持有日志文件句柄如果logrotate用rename方式把文件挪走Mosquitto还会继续往那个已经被改名甚至删除的在inode上写新的日志文件反而一直是空的你就看到“日志不增长了”的假象。有了copytruncate就能确保切完日志后文件句柄继续指向同一个文件新日志继续写入。create 640 mosquitto mosquitto创建新日志文件时指定用户和权限避免Mosquitto以mosquitto用户运行时因为权限不足写不进去。还有一个容易被忽略的细节Mosquitto日志文件路径所在目录要确保mosquitto用户有写权限。很多时候你配置了log_dest file但进程起不来journalctl里报的是Permission denied原因就是目录所有者是root。如果你想做集中式日志管理也就是把几十台网关、几百个Broker的日志汇到一台服务器上那我建议在logrotate之前先接日志采集器。具体方案可以是Filebeat扫/var/log/mosquitto/*.log推到Elasticsearch也可以是Promtail扫文件推到Loki。后者我比较推荐原因很现实Loki对资源要求比ELK低一个量级适合小团队玩。3.1 原位指标学会从$SYS主题树拿第一手数据Mosquitto最让我喜欢的一点是它自带了“可观测性后门”——$SYS主题树。只要在配置里设置了sys_intervalBroker就会周期性往这套以$SYS开头的主题发布自己的运行状态。默认情况下sys_interval是10秒也就是说每10秒你就能拿到一组新鲜指标这对监控来说足够灵敏。我实际使用中经常订阅的$SYS主题大概有下面这些建议你在服务器上直接跑一条命令验证一下mosquitto_sub -h 127.0.0.1 -t $SYS/broker/# -v拿到的数据会类似下面这样$SYS/broker/clients/connected 0 $SYS/broker/clients/connected 3 $SYS/broker/clients/disconnected 0 $SYS/broker/clients/total 3 $SYS/broker/messages/received 12809 $SYS/broker/messages/sent 25973 $SYS/broker/messages/stored 0 $SYS/broker/messages/dropped 0 $SYS/broker/subscriptions/count 2 $SYS/broker/retained messages/count 0 $SYS/broker/load/bytes/received/1min 456732.23 $SYS/broker/load/bytes/sent/1min 892211.11 $SYS/broker/load/messages/received/1min 380.00 $SYS/broker/load/messages/sent/1min 760.00这些指标每一个都在回答一个具体问题$SYS/broker/clients/connected当前在线客户端数这是最直觉的“活没活着”指标。如果业务高峰期这个数字断崖下跌说明网络分区或认证抖动如果持续上涨超出预期要警惕设备异常重连风暴。$SYS/broker/messages/received与$SYS/broker/messages/sent累计收发消息数看趋势可以算出每秒吞吐量用来做容量规划。$SYS/broker/messages/dropped被丢弃的消息数。这个数字一旦持续增长十有八九是QoS 1/2消息超过最大队列长度或者保留消息处理出问题。$SYS/broker/load/messages/received/1min最近一分钟的消息接收速率比累计值更适合做实时告警。$SYS/broker/subscriptions/count当前订阅总数配合客户端数能大致估算每个客户端的平均订阅数量排查topic设计是否合理。有一点要重点提示$SYS主题默认能被订阅但如果你启用了Mosquitto的动态安全插件mosquitto-dynamic-security或者自定义ACL插件需要在权限配置里显式允许readaccess和subscribe对$SYS/#的通路。我见过不止一个团队升级到2.0之后突然发现监控数据全空了最后排查下来就是ACL把$SYS给挡了。3.2 接入Prometheus生态让指标活起来而不是躺在订阅里用mosquitto_sub看一眼指标没问题但你不能天天拿肉眼看几十台Broker的数据。这时候就需要一个数据采集器把这些$SYS指标转成Prometheus能采集的格式。目前社区用的比较多的是一个叫mosquitto_exporter的开源组件它的逻辑很简单启动后作为一个MQTT客户端订阅$SYS/broker/#主题把拿到的数值解析出来以Prometheus的Metrics文本格式暴露在HTTP端口上Prometheus定时去拉取就行。部署方式我推荐直接下载二进制放到/usr/local/bin/用systemd管理。下面是我在Ubuntu 22.04上实际跑通的流程# 1. 下载并安装 exporter wget https://github.com/kryptonbutterfly/mosquitto_exporter/releases/download/v1.0/mosquitto_exporter-linux-amd64 install -m 0755 mosquitto_exporter-linux-amd64 /usr/local/bin/mosquitto_exporter # 2. 创建 systemd 服务 cat /etc/systemd/system/mosquitto-exporter.service EOF [Unit] DescriptionPrometheus Mosquitto Exporter Afternetwork-online.target [Service] ExecStart/usr/local/bin/mosquitto_exporter \ -mqtt.brokertcp://127.0.0.1:1883 \ -mqtt.usernamemonitor \ -mqtt.passwordyour-password \ -mqtt.topic$SYS/broker/# \ -mqtt.qos0 \ -listen.address:9234 Restartalways RestartSec5 [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now mosquitto-exporter注意我在参数里特意使用了monitor这个MQTT账号。生产环境千万别直接用匿名订阅。即便是监控订阅也应该按最小权限原则在Mosquitto里开一个只能订阅$SYS/#的低权限账号防止监控链路反过来成为安全破口。每个exporter默认暴露在9234端口。如果是集群部署你还得在Prometheus的scrape_configs里把每个Broker对应的exporter都加进去。像下面这样scrape_configs: - job_name: mosquitto static_configs: - targets: - gw-01:9234 - gw-02:9234 - gw-03:9234到这里你的监控数据就已经进Prometheus了。Grafana里可以导入社区现成的dashboards也可以自己在Explore里先用rate(mosquitto_messages_received_total[5m])这类PromQL验证数据在更新。我见过不少人卡在这一步——图表空白的八成是Grafana的数据源和Dashboard里的job名对不上把jobmosquitto改成你自己的job_name就行。4.1 从部署到报警一次完整的Mosquitto监控落地实战接下来我会带你把整个链路完整过一遍。这个方案我已经在三个项目里复用过基本是复制粘贴就能跑的程度。先假设我们有一台运行Mosquitto的Ubuntu服务器IP是192.168.10.10上面已经通过apt装好了最近的Mosquitto 2.x版本。第一步开启$SYS发布。编辑/etc/mosquitto/conf.d/monitor.conf# 发布$SYS指标的间隔单位是秒 sys_interval 10 # 为了让订阅者能收到也确认一下允许匿名订阅设置 # 记得按实际安全策略调整 allow_anonymous false password_file /etc/mosquitto/passwd然后用mosquitto_passwd创建一个只用于监控的低权限账号sudo mosquitto_passwd -b /etc/mosquitto/passwd monitor Your-Strong-Password重启Mosquitto用订阅命令确认一下指标能收到sudo systemctl restart mosquitto mosquitto_sub -h 127.0.0.1 -u monitor -P Your-Strong-Password -t $SYS/broker/# -v这一步如果输出为空优先检查ACL和用户名密码是否有权限其次检查sys_interval是否被后面的include目录覆盖为0。第二步部署mosquitto_exporter。按上文systemd方式部署完验证一下HTTP端点curl -s http://127.0.0.1:9234/metrics | grep mosquitto如果看到以mosquitto_开头的指标输出说明采集链路已经打通。第三步在Prometheus里添加抓取任务。假设Prometheus也跑在同一台机器上编辑prometheus.ymlscrape_configs: - job_name: mosquitto-broker static_configs: - targets: [127.0.0.1:9234]重载Prometheus在Targets页面确认状态是UP。这一步要特别留神Prometheus默认抓取超时是10秒如果exporter所在网络质量差很容易出现context deadline exceeded这时把scrape_timeout调长一点。第四步配置报警规则。下面这份是我总结出来的黄金告警规则覆盖了Broker最常见的几种故障模式。保存为/etc/prometheus/rules/mosquitto.ymlgroups: - name: mosquitto-alerts rules: # 在线客户端数在5分钟内下降超过50%大概率是网络分区或服务异常断开 - alert: MosquittoClientsDropped expr: | (delta(mosquitto_clients_connected[5m]) 0) and (clamp_min(delta(mosquitto_clients_connected[5m]), 0) / clamp_min(mosquitto_clients_connected, 1) -0.5) for: 2m labels: severity: critical annotations: summary: Mosquitto在线客户端数大幅下降 description: Broker {{ $labels.instance }} 在线客户端数5分钟内下降超过50%当前仅剩{{ $value }}个客户端在线。 # 1分钟窗口消息接收速率为0持续5分钟需要人工确认 - alert: MosquittoNoMessages expr: | sum by (instance) (rate(mosquitto_messages_received_total[5m])) 0 for: 5m labels: severity: warning annotations: summary: Mosquitto消息接收中断 description: Broker {{ $labels.instance }} 最近5分钟没有任何消息接收请检查发布端和网络链路。 # 消息丢弃数持续增长 - alert: MosquittoMessagesDropping expr: | increase(mosquitto_messages_dropped_total[15m]) 0 for: 5m labels: severity: warning annotations: summary: Mosquitto开始丢弃消息 description: Broker {{ $labels.instance }} 在15分钟内出现消息丢弃请检查QoS配置、队列长度和客户端消费能力。这几条规则我都加了for子句用来防止瞬时抖动误报。实际运营中我吃过不少“监控半夜狂报警起来一看啥事没有”的苦头有了for可以过滤掉大部分毛刺。第五步在Grafana里搭看板。这个就比较个人审美了我至少会放三块核心面板在线客户端数趋势、消息收发速率、每Broker的字节吞吐量。PromQL分别是# 在线客户端数 mosquitto_clients_connected{jobmosquitto-broker} # 消息接收/发送速率 rate(mosquitto_messages_received_total{jobmosquitto-broker}[5m]) rate(mosquitto_messages_sent_total{jobmosquitto-broker}[5m]) # 字节吞吐 rate(mosquitto_bytes_received_total{jobmosquitto-broker}[5m]) rate(mosquitto_bytes_sent_total{jobmosquitto-broker}[5m])到这一步你的页面监测体系就已经从“Broker自己不知道在干嘛”变成了“任何异常都有数有据可查”。4.2 日志驱动的异常定位从堆数据到破案监控指标告诉你“出了问题”但“为什么出问题”还得靠日志。这里我整理了三个我实际用过的日志驱动排查手段希望能给你参考。手段一订阅log_dest topic实现实时日志流。Mosquitto支持把日志发布到指定的MQTT主题上这意味着你可以远程实时订阅某个Broker的日志不用每次SSH上去看。在Mosquitto 2.x里这个功能的配置是# 在 mosquitto.conf 里加一行 log_dest topic mosquitto/logs然后在任何一台远程机器上mosquitto_sub -h 192.168.10.10 -u monitor -P password -t mosquitto/logs这样远程也能看到实时日志。但要注意这会把日志内容暴露在MQTT消息总线上生产环境必须用TLS加密和ACL严格限制订阅权限否则等于把敏感信息直播出去。手段二在网关设备上保留一份“最近N条日志”的环形缓冲。嵌入式设备资源有限不可能存很多天的日志。我的做法是用一个轻量脚本后台订阅mosquitto/logs把日志写到内存盘tmpfs里的环形队列重启自动清空但如果宕机前被监控系统抓到了现场通常就够分析原因了。当然更稳妥的做法是让日志通过MQTT消息主动推到集中日志服务器用Loki或Elasticsearch统一存。这个方案在设备量少的时候很灵活设备多了就还是得用Filebeat/Promtail。手段三用日志关键字做告警补充。Prometheus只能监控数值指标但日志里藏着大量数值指标不包含的信息。比如Client X closed its connection反复出现说明某个设备在频繁重连Sending CONNACK后面的错误码可以区分是认证失败还是协议版本不支持Socket error on client则可能泄露网线被拔了这类物理问题。我习惯的做法是在Loki里给Promtail配置一条流水线把日志里的关键token提取出来再用LogQL计算错误频率。比如统计“认证失败”日志在5分钟内出现次数超过阈值就报警sum by (instance) (count_over_time({jobmosquitto} |~ Permission denied|not authorised[5m])) 20有了这条规则恶意扫描、密码错误风暴、甚至员工配错账号密码导致的连锁失败都能及时暴露。5.1 典型问题速查表把这些年运维Mosquitto踩过和见人踩过的坑列成一张表方便你遇到问题时快速对照。现象可能原因排查与解决$SYS主题一直订阅不到sys_interval为0或被ACL拦截插件过滤了$SYS确认sys_interval非0检查动态安全插件是否允许订阅$SYS/#用mosquitto_sub -t $SYS/broker/#验证log_dest file配置后日志文件不生成目录不存在或目录权限不足手动创建目录并chown mosquitto:mosquitto确认log_dest路径与目录一致日志轮转后新文件不产生内容配置了rename方式且未用copytruncate修改logrotate配置为copytruncate观察一周确认文件在持续增长客户端频繁重连日志大量出现Socket error网络不稳、心跳周期短、代理/NAT超时或Broker线程阻塞用tcpdump抓包确认是客户端发RST还是Broker关闭调整keepalive与max_inflight_messages检查CPU和内存是否瓶颈MQTT消息延迟明显网络带宽瓶颈、消息QoS等级过高、Broker持久化策略用上、swap严重看$SYS/broker/load/bytes/received/1min趋势按预期峰值扩容把不需要持久化的topic用QoS 0发Prometheus抓取exporter超时exporter所在网段带宽低或scrape_timeout短调大scrape_timeout到30s把exporter放到和Prometheus同网段用blackbox探针先测网络连通性日志时间与本地时间差8小时容器时区未设置或系统时区为UTC容器添加TZAsia/Shanghai环境变量宿主机timedatectl确认时区落库时统一用UTC时区标记内存缓慢增长几天后OOM订阅树膨胀客户端不按规范退订导致占用堆积retain消息过多分析$SYS/broker/subscriptions/count和retained messages count限制单个client最大订阅数清理无用retain消息Client连接后立即CONNACK返回但随即断开认证插件配置冲突对照log_type error输出检查password_file和ACL文件是否同时配置了冲突规则用mosquitto_pub和mosquitto_sub手工测试5.2 我的排查经验与避坑指南最后聊几个偏“个人向”的经验不一定写在官方文档里但关键时刻真能救命。第一永远别在生产环境开debug日志。有一次我帮朋友排查一个奇怪的客户端断连问题他为了捕获现场直接在配了上千台设备的Broker上开启了log_type debug结果两小时不到磁盘就被刷满Broker自己都写不进日志了。后来我告诉他遇到这种问题正确姿势是先保留error/warning/notice级别的日志然后用tcpdump在Broker网卡上抓包分析具体协议行为这样既不影响业务也能看到像CONNECT报文里的keepalive值这些细节。做运维第一原则永远是“不要为了看清一个问题而制造一个更大的问题”。第二监控数据的采样间隔要和你业务的容忍度匹配。sys_interval默认10秒已经很快了但如果你有那种零点几秒就要感知故障的场景单纯靠Mosquitto的$SYS对不齐的。这种场景应该把健康探测和业务探测分开用一个独立的MQTT客户端周期性发心跳消息并确认收到回执比看任何指标都直接。我做嵌入式网关运维的时候每个网关上的采集程序都会每30秒发一条/healthcheck/gateway01消息并在本地标记发送时间监控端订阅同一个topic一旦超过60秒没收到就说网关挂了。这个方案比单纯看指标响应快得多也更贴近业务真实状态。第三别忘记监控你自己监控系统。听起来像个段子但我确实遇到过Grafana数据源的Prometheus挂了一整天直到用户投诉才知道。所以我现在会在每台Broker上开一条crontab每5分钟检查一下exporter的HTTP端口能否通不行就直接往企业微信/钉钉机器人发告警。监控账套虽然简单但它是所有监控系统的“最后一道防线”。第四日志格式最好提前埋好结构化字段。Mosquitto默认日志是人读的但机器不好读。我的习惯是在logrotate之前加一层Promtail的pipeline把日志里的IP、client id、topic、错误码拆成结构化字段存进Loki。这样你才能在事后用一个query查“某台设备最近一小时的全部行为”而不是靠grep慢慢捞。说实话Mosquitto本身的监控和日志管理在开源Broker里已经算是做得比较友好的了$SYS主题设计得直白日志通道灵活社区工具也不少。但友好的工具也架不住疏忽很多问题其实不是Broker的问题而是我们没在早期把观测体系搭好。我个人这几年最大的体感是监控和日志不是“等出事后才去搭”的事后补救而是任何消息中间件上线第一天就该补好的基础设施。等你经历过一次凌晨三点因为消息堆积找不出原因被叫醒的体验就会明白这句话的含金量。希望这篇文章能帮你把Mosquitto这层“眼睛和记忆”一次性配齐后面少熬夜多省心。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询