3. MQTT Broker可观测性实战

MQTT Broker是IoT平台的消息中枢,它的可观测性直接决定了平台能否在设备规模增长时保持稳定。与通用Web服务不同,Broker的核心健康状态由三类指标刻画:连接维度(当前连接数、连接速率、认证失败数)、主题维度(主题总数、订阅关系数、通配符订阅占比)、消息维度(发布/接收速率、丢弃数、队列积压)。本节以EMQX 5.x为主、Mosquitto为辅,完成从指标暴露到看板与告警的完整闭环。

一、指标暴露:让Broker“开口说话”

EMQX内置Prometheus指标端点,默认监听在18083端口的/api/v5/prometheus/stats路径(需在emqx.conf中确认prometheus.enable = true)。它暴露的指标以emqx_为前缀,例如emqx_connections_count、emqx_topics_count、emqx_messages_publish、emqx_messages_dropped。Mosquitto则通过mosquitto.conf中的sys_interval 10开启$SYS/#主题,用订阅方式读取$SYS/broker/clients/connected、$SYS/broker/messages/received等值。

两种方式的关键差异在于:EMQX是拉取式(Prometheus主动抓取),Mosquitto是推送式(通过MQTT主题发布)。生产环境推荐EMQX + Prometheus + Grafana组合,因为拉取式天然支持多实例聚合与历史存储。下面是一段可直接使用的Prometheus抓取配置示例:

scrape_configs:
  - job_name: 'emqx'
    metrics_path: '/api/v5/prometheus/stats'
    static_configs:
      - targets: ['10.0.1.21:18083', '10.0.1.22:18083']
    relabel_configs:
      - source_labels: [__address__]
        target_label: instance

注意:EMQX 5.x的Prometheus端点默认需要认证,若开启dashboard.default_username,需在抓取配置中补充basic_auth。抓取间隔建议设为15s,与告警评估周期保持一致,避免因采样过疏导致速率计算失真。

二、看板搭建:三类核心指标的查询与呈现

Grafana看板不必追求指标数量,而应围绕“连接—主题—消息”三条主线组织。以下PromQL可直接用于面板查询(示例基于EMQX指标命名,实际以/metrics输出为准):

  • 当前连接数:sum(emqx_connections_count),用Stat面板显示总量,用Time series显示趋势。
  • 连接速率:sum(rate(emqx_connections_count[5m])),用于识别设备批量上线或重连风暴。
  • 主题总数:sum(emqx_topics_count),配合sum(emqx_subscriptions_count)观察订阅膨胀。
  • 消息发布速率:sum(rate(emqx_messages_publish[5m])),单位msg/s。
  • 消息丢弃速率:sum(rate(emqx_messages_dropped[5m])),这是最容易被忽视但最危险的指标。

看板布局建议:顶部一行放四个Stat(连接数、主题数、发布速率、丢弃速率),中间放连接数与消息速率的双轴时序图,底部放“丢弃原因分布”饼图(按reason标签聚合)。这样一眼就能判断是“量在涨”还是“质在坏”。

MQTT Broker可观测性数据链路与告警闭环 EMQX 5.x /api/v5/prometheus/stats emqx_connections_count Mosquitto $SYS/# 主题 sys_interval 10 Prometheus scrape_interval: 15s TSDB 存储 rate() 计算 Grafana 看板 连接数 / 主题数 消息速率 / 丢弃率 Alertmanager 告警规则评估 邮件 / Webhook 告警规则示例(Prometheus Rule) 连接数突增 rate(emqx_connections_count[5m]) > 500 消息丢弃 rate(emqx_messages_dropped[5m]) > 0 主题膨胀 emqx_topics_count > 100000 评估周期:15s | 持续时间:2m | 严重级别:warning / critical 分级 告警抑制:同一实例5分钟内不重复触发 | 恢复通知:resolved 状态自动发送

三、异常告警:从“看见”到“被通知”

看板解决的是“人找问题”,告警解决的是“问题找人”。在Prometheus中定义规则文件emqx_alerts.yml,核心是三条:

groups:
  - name: emqx_health
    rules:
      - alert: EmqxConnectionSpike
        expr: rate(emqx_connections_count[5m]) > 500
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "连接速率突增 {{ $value }} conn/s"

      - alert: EmqxMessageDropped
        expr: rate(emqx_messages_dropped[5m]) > 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "消息丢弃速率 {{ $value }} msg/s,检查队列与限流"

      - alert: EmqxTopicExplosion
        expr: emqx_topics_count > 100000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "主题数 {{ $value }},疑似通配符订阅或设备ID泄漏"

三条规则的判断逻辑各有侧重:连接速率突增通常意味着设备批量重连或认证失败后重试,需结合emqx_authentication_failure一起看;消息丢弃是critical级别,因为一旦丢弃,业务侧可能永远收不到该消息,必须立即检查max_mqueue_len和max_inflight配置;主题数膨胀则往往是设备端把动态ID写进了主题层级,导致订阅关系爆炸,需要从emqx_subscriptions_count按topic标签下钻定位。

告警阈值不是拍脑袋定的。建议先让系统跑满一个业务周期(如7天),用quantile_over_time(0.95, emqx_connections_count[7d])观察P95值,再以P95的1.5~2倍作为初始阈值,后续根据误报率调整。

四、结果判读与常见陷阱

看板搭好后,如何判断“正常”?一个健康的Broker应满足:连接数曲线平滑、无锯齿状剧烈波动;消息发布速率与订阅速率大致匹配;丢弃速率长期为0;主题数增长与设备数增长呈线性关系。若出现“连接数高但消息速率低”,通常是设备连上后不发数据,需检查设备端心跳与QoS配置;若“主题数持续上涨但设备数不变”,则几乎可以确定是主题命名不规范导致的订阅泄漏。

Mosquitto的$SYS指标粒度较粗,且不支持Prometheus原生抓取。若生产环境使用Mosquitto,建议通过mosquitto_sub -t '$SYS/#'将数据桥接到Telegraf或EMQX Edge,再统一进入Prometheus,否则告警能力会大打折扣。

最后,把告警接入实际通知渠道:Alertmanager配置webhook_configs指向企业微信或钉钉机器人,并在route中按severity分流——critical走电话+群消息,warning只发群消息。这样,Broker的可观测性才真正从“仪表盘”变成了“值班员的耳朵”。