一、Pulsar监控为什么重要,以及整体思路

消息中间件在企业里用得多,Pulsar因为架构灵活、性能不错,很多团队选了它。但消息队列这东西,一旦出问题,可能整个业务链路都会卡住——消息堆积、消费者掉线、Broker节点挂掉,这些情况如果不及时发现,造成的损失可能远比你想象的大。所以搭建一套靠谱的监控体系,不是锦上添花,而是雪中送炭。

Pulsar本身已经内置了指标暴露能力,它在每个Broker和BookKeeper节点上都会吐出各种Prometheus格式的指标。你不需要自己写采集代码,只需要把Prometheus配上正确的采集规则,就能把这些数据拉回来。然后Grafana负责把这些数据可视化展示,Alertmanager负责在异常发生时发告警通知。整套技术栈就是:Apache Pulsar + Prometheus + Alertmanager + Grafana,下面详细拆解每一步怎么做。

二、核心监控指标梳理

在动手配之前,得先搞清楚Pulsar有哪些值得关注的指标。这些指标大致可以分为几类,搞清楚分类之后,配置起来不会混乱。

2.1 Broker层指标

Broker是Pulsar消息处理的"中转站",它的工作状态直接决定了消息能不能正常流转。关键指标包括:

  • pulsar_broker_in_messages_total:Broker收到的消息总数,反映入口流量。
  • pulsar_broker_out_messages_total:Broker发出的消息总数,反映出口流量。
  • pulsar_broker_storage_buffer_usage:内存中的存储缓冲区使用比例,超过阈值意味着内存压力大。
  • pulsar_broker_num_consumers:当前活跃的消费者数量,如果这个数字骤降到0,说明消费者全挂了。
  • pulsar_broker_backlog_size_total:积压的消息总大小,这个数字持续增长说明消费跟不上生产。

2.2 BookKeeper层指标

BookKeeper是Pulsar的底层存储引擎,它负责把消息持久化。关键指标包括:

  • bookie_disk_usage_ratio:磁盘使用率,这个指标很重要,磁盘满了BookKeeper直接罢工。
  • bookie_enhance_ensemble_size:集群中可用的写入节点数量,这个值变小说明集群节点在掉。
  • bookie_ledgers_num:当前活跃的Ledger数量,反映写入负载。

2.3 网络与连接指标

  • pulsar_nar_server_connections:服务端当前连接数。
  • pulsar_nar_server_in_bytes_total:服务端接收的字节数。
  • pulsar_broker_network_receives_per_second:每秒接收的网络包数。

2.4 订阅与消费指标

  • pulsar_broker_subscription_delay:订阅延迟,从消息写入到被订阅消费之间的时间差。
  • pulsar_broker_consumer_latency_ms:消费者处理延迟,单位毫秒。

这些指标覆盖了消息从生产到消费的整个生命周期。在实际监控中,你不需要把所有指标都拉进来,重点盯住能反映"消息是否在正常流动"和"系统是否健康"的那几个核心指标就够了。

三、Prometheus采集配置

Prometheus的工作模式是主动拉取,它会按照你配置的时间间隔,去目标节点的metrics端点抓取数据。Pulsar的Broker默认在8080端口暴露metrics,BookKeeper默认在8000端口。你需要在Prometheus的配置文件中把这些端点加上。

3.1 Prometheus配置文件

技术栈:Apache Pulsar + Prometheus + Alertmanager + Grafana

# ========================================
# Prometheus 主配置文件 prometheus.yml
# ========================================
# 全局设置:决定了抓取间隔、数据保留时间等基础参数
global:
  scrape_interval: 15s        # 每隔15秒去目标节点抓一次数据
  evaluation_interval: 15s    # 告警规则每15秒评估一次
  scrape_timeout: 10s         # 单次抓取的超时时间,超过这个时间就放弃
  external_labels:            # 外部标签,用来区分不同环境的Prometheus实例
    environment: production
    cluster_name: pulsar-prod

# ========================================
# 告警管理配置
# ========================================
alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "alertmanager:9093"  # Alertmanager服务地址和端口

# ========================================
# 规则文件引用
# ========================================
rule_files:
  - "rules/pulsar_alerts.yml"    # Pulsar告警规则文件路径

# ========================================
# 数据源抓取配置(核心部分)
# ========================================
scrape_configs:
  # ---------- 抓取 Prometheus 自身指标 ----------
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # ---------- 抓取 Pulsar Broker 指标 ----------
  # Pulsar Broker 默认在 8080 端口的 /metrics 路径暴露指标
  - job_name: 'pulsar-broker'
    metrics_path: '/metrics'
    static_configs:
      - targets:
          - 'pulsar-broker-0:8080'
          - 'pulsar-broker-1:8080'
          - 'pulsar-broker-2:8080'
    labels:
      cluster: 'pulsar-prod'    # 给这一组目标打上环境标签
      component: 'broker'       # 标记组件类型为 Broker

  # ---------- 抓取 BookKeeper 指标 ----------
  # BookKeeper 默认在 8000 端口暴露 JMX 指标
  # 需要先配置 JMX Exporter 把 JMX 指标转换为 Prometheus 格式
  - job_name: 'bookkeeper'
    metrics_path: '/metrics'
    static_configs:
      - targets:
          - 'bk-0:8000'
          - 'bk-1:8000'
          - 'bk-2:8000'
    labels:
      component: 'bookkeeper'

  # ---------- 抓取 ZooKeeper 指标(用于元数据同步监控)----------
  - job_name: 'zookeeper'
    metrics_path: '/metrics'
    static_configs:
      - targets:
          - 'zookeeper-0:8000'
          - 'zookeeper-1:8000'
          - 'zookeeper-2:8000'

配置文件的几个关键点需要注意:scrape_interval不要设得太短,5秒以内的间隔对Prometheus自身也是不小的压力,15到30秒是比较合理的范围。labels部分一定要加,后面在Grafana里做查询和区分集群的时候,这些标签就是关键。

3.2 Pulsar Broker指标端点验证

配置好之后,第一步不是急着启动Prometheus,而是先确认Pulsar Broker的指标端点能不能正常返回数据。可以直接用curl命令去验证:

# ========================================
# 验证 Pulsar Broker 指标端点是否正常
# ========================================

# 第一步:直接访问 Broker 的 metrics 端点
# 如果返回了类似下面格式的文本,说明端点正常工作
curl -s http://pulsar-broker-0:8080/metrics

# 第二步:只看特定指标,用 grep 过滤
# 比如查看当前消息积压总量
curl -s http://pulsar-broker-0:8080/metrics | grep "pulsar_broker_backlog"

# 第三步:查看 Broker 的存储缓冲区使用情况
curl -s http://pulsar-broker-0:8080/metrics | grep "storage_buffer_usage"

# 第四步:检查 Broker 是否有消费者连接
curl -s http://pulsar-broker-0:8080/metrics | grep "num_consumers"

# 第五步:查看 BookKeeper 磁盘使用率(如果 BK 也暴露了 HTTP 端点)
curl -s http://bk-0:8000/metrics | grep "disk_usage_ratio"

如果curl命令返回了一堆类似pulsar_broker_in_messages_total{...} 123456这样的文本,说明Pulsar的指标暴露配置没问题。如果返回404或者连接超时,就得去检查Pulsar的broker.conf里metrics相关的配置是否开启。

3.3 Pulsar Broker指标暴露配置

有些Pulsar的发行版本默认没有开启所有指标暴露,需要手动在配置文件中确认。编辑Pulsar的Broker配置文件:

# ========================================
# Pulsar Broker 配置文件 broker.conf
# ========================================
# 开启指标暴露
metrics_provider_classes=pulsar.metrics.prometheus.PrometheusMetricsProvider

# 指定 metrics 端口
prometheus_port=8080

# 开启消息级别的指标追踪(这个配置会让每个 topic 都有独立的指标)
topic_metrics_retention_minutes=10080  # 保留10080分钟(7天)的 topic 级指标

# 开启连接级别的指标
connection_metrics_enabled=true

# 开启消费者延迟指标
subscription_delay_metrics_enabled=true

# 开启网络指标
network_metrics_enabled=true

BookKeeper的指标暴露稍微复杂一点,因为BookKeeper原生用的是JMX(Java Management Extensions)协议。你需要在BookKeeper前面加一层JMX Exporter,把JMX指标转换成Prometheus能识别的格式。

四、告警规则配置

有了数据采集,下一步就是告诉系统什么情况下该报警。告警规则写的是PromQL查询语句,当查询结果满足条件时,Alertmanager就会触发告警。

4.1 告警规则文件

# ========================================
# Pulsar 告警规则文件 rules/pulsar_alerts.yml
# ========================================
# 规则分组:按组件类型分成三组,方便管理和排查

groups:
  # ---------- 第一组:Broker 层告警规则 ----------
  - name: pulsar_broker_alerts
    interval: 30s  # 这组规则每30秒评估一次
    rules:
      # 规则1:Broker 消息积压告警
      # 当积压超过10万条消息且持续5分钟以上时触发
      - alert: BrokerMessageBacklogHigh
        expr: pulsar_broker_backlog_size_total > 100000
        for: 5m
        labels:
          severity: critical       # 严重级别:严重
          team: message-platform   # 负责团队标签
        annotations:
          summary: "Broker消息积压严重"
          description: "Broker {{ $labels.host }} 当前积压消息 {{ $value }} 条,已超过10万条阈值,请立即排查消费端是否正常。"
          runbook: "https://wiki.internal/runbook/broker-backlog"

      # 规则2:Broker 存储缓冲区使用率过高
      # 缓冲区超过80%意味着内存快被写满了
      - alert: BrokerStorageBufferHigh
        expr: pulsar_broker_storage_buffer_usage > 0.80
        for: 3m
        labels:
          severity: warning
          team: message-platform
        annotations:
          summary: "Broker存储缓冲区使用率过高"
          description: "Broker {{ $labels.host }} 存储缓冲区使用率达到 {{ $value | humanizePercentage }},超过80%阈值。可能导致消息写入延迟或丢失。"

      # 规则3:Broker 消费者数量异常归零
      # 所有消费者突然断开,这是非常危险的情况
      - alert: BrokerNoConsumers
        expr: pulsar_broker_num_consumers == 0
        for: 2m
        labels:
          severity: critical
          team: message-platform
        annotations:
          summary: "Broker上无活跃消费者"
          description: "Broker {{ $labels.host }} 上活跃消费者数量为0,持续2分钟。消息可能正在大量堆积,请立即检查消费者应用状态。"

      # 规则4:Broker 消息处理延迟告警
      # 单个消息处理时间超过5秒,说明处理性能有问题
      - alert: BrokerMessageLatencyHigh
        expr: rate(pulsar_broker_out_messages_total[5m]) < 100
        for: 10m
        labels:
          severity: warning
          team: message-platform
        annotations:
          summary: "Broker消息吞吐量过低"
          description: "Broker {{ $labels.host }} 最近5分钟的消息吞吐量低于100条/秒,可能存在性能瓶颈。"

  # ---------- 第二组:BookKeeper 层告警规则 ----------
  - name: bookkeeper_alerts
    interval: 30s
    rules:
      # 规则5:BookKeeper 磁盘使用率告警
      # 磁盘超过85%需要关注,超过90%必须立刻处理
      - alert: BookKeeperDiskUsageHigh
        expr: bookie_disk_usage_ratio > 0.85
        for: 5m
        labels:
          severity: warning
          team: storage
        annotations:
          summary: "BookKeeper磁盘使用率偏高"
          description: "BookKeeper节点 {{ $labels.host }} 磁盘使用率达到 {{ $value | humanizePercentage }},请考虑扩容或清理过期数据。"

      - alert: BookKeeperDiskCritical
        expr: bookie_disk_usage_ratio > 0.90
        for: 2m
        labels:
          severity: critical
          team: storage
        annotations:
          summary: "BookKeeper磁盘空间严重不足"
          description: "BookKeeper节点 {{ $labels.host }} 磁盘使用率达到 {{ $value | humanizePercentage }},已超过90%阈值。存在数据丢失风险,请立即处理。"

      # 规则6:BookKeeper 写入节点数量不足
      # 集群中可用的写入节点少于3个,意味着写入可靠性下降
      - alert: BookKeeperEnsembleTooSmall
        expr: bookie_enhance_ensemble_size < 3
        for: 5m
        labels:
          severity: critical
          team: storage
        annotations:
          summary: "BookKeeper可用写入节点不足"
          description: "BookKeeper集群可用写入节点数量仅为 {{ $value }},低于安全阈值3个。写入可靠性无法保证。"

  # ---------- 第三组:整体健康检查告警 ----------
  - name: health_check_alerts
    interval: 30s
    rules:
      # 规则7:Prometheus 抓取失败告警
      # 当Pulsar的指标采集连续3次失败时触发
      - alert: PrometheusScrapeFailure
        expr: up{job=~"pulsar-broker|bookkeeper"} == 0
        for: 1m
        labels:
          severity: warning
          team: sre
        annotations:
          summary: "Pulsar指标采集失败"
          description: "Prometheus无法从目标 {{ $labels.instance }} (job={{ $labels.job }}) 抓取指标,持续1分钟。请检查目标节点网络和Pulsar服务状态。"

      # 规则8:Pulsar集群消息端到端延迟过高
      - alert: EndToEndLatencyHigh
        expr: pulsar_broker_subscription_delay > 5000
        for: 5m
        labels:
          severity: critical
          team: message-platform
        annotations:
          summary: "消息端到端延迟过高"
          description: "Topic {{ $labels.topic }} 的消息端到端延迟为 {{ $value | humanizeDuration }},超过5秒阈值。业务可能受到影响。"

告警规则写得多的时候,分组非常重要。上面把规则按Broker、BookKeeper、健康检查分成了三组,每组独立配置评估间隔。这样做的好处是:当Broker的规则评估频率需要调整时,不会影响BookKeeper规则的评估。另外,每个规则里的for参数不要设得太短,比如1分钟以内,否则很容易因为网络抖动产生误报。3到5分钟是比较合理的设置。

4.2 Alertmanager配置

Alertmanager负责接收Prometheus发来的告警,然后根据规则进行路由、去重、静默。配置文件如下:

# ========================================
# Alertmanager 配置文件 alertmanager.yml
# ========================================
# 全局设置
global:
  smtp_smarthost: 'smtp.example.com:587'   # 邮件发送服务器地址
  smtp_from: 'alert@example.com'            # 发件人邮箱
  smtp_auth_username: 'alert@example.com'   # SMTP 认证用户名
  smtp_auth_password: 'your_password_here'  # SMTP 认证密码
  smtp_require_tls: true                    # 要求使用TLS加密传输

# 路由规则:决定告警发到哪个通知渠道
route:
  receiver: 'default-receiver'   # 默认告警接收方
  group_by:
    - alertname      # 按告警名称分组
    - severity       # 按严重级别分组
    - team           # 按负责团队分组
  group_wait: 30s          # 分组等待时间,收到第一条告警后等30秒看有没有同类告警
  group_interval: 5m       # 同一分组内,两次通知之间的最小间隔
  repeat_interval: 4h      # 如果告警一直没恢复,每4小时重复通知一次

  # 路由树:根据标签把告警分发到不同的接收方
  routes:
    # 严重级别为 critical 的告警,立即发送到紧急通知渠道
    - match:
        severity: critical
      receiver: 'critical-notifications'
      group_wait: 10s       # 严重告警的等待时间缩短到10秒
      repeat_interval: 1h   # 严重告警每小时重复一次

    # 负责团队为 storage 的告警,发到存储团队渠道
    - match:
        team: storage
      receiver: 'storage-team'

    # 负责团队为 message-platform 的告警,发到消息平台团队渠道
    - match:
        team: message-platform
      receiver: 'message-platform-team'

    # 负责团队为 sre 的告警,发到SRE团队渠道
    - match:
        team: sre
      receiver: 'sre-team'

# 接收方定义:每个接收方对应一种或多种通知渠道
receivers:
  # 默认接收方,如果告警没有匹配到任何路由规则,就发到这里
  - name: 'default-receiver'
    email_configs:
      - to: 'oncall@example.com'
        send_resolved: true    # 告警恢复时也发通知

  # 严重告警接收方:邮件 + 钉钉/企微/Slack 多渠道通知
  - name: 'critical-notifications'
    email_configs:
      - to: 'oncall@example.com'
        send_resolved: true
    webhook_configs:
      # 这里可以对接钉钉机器人或企业微信机器人
      - url: 'http://dingtalk-webhook:5001/dingtalk/default/send'
        send_resolved: true
        # 自定义消息模板(可选)
        # http_config:
        #   tls_config:
        #     insecure_skip_verify: false

  # 存储团队接收方
  - name: 'storage-team'
    email_configs:
      - to: 'storage-team@example.com'
        send_resolved: true

  # 消息平台团队接收方
  - name: 'message-platform-team'
    email_configs:
      - to: 'message-platform@example.com'
        send_resolved: true

  # SRE团队接收方
  - name: 'sre-team'
    email_configs:
      - to: 'sre-team@example.com'
        send_resolved: true

# 静默规则:在维护期间可以暂时屏蔽某些告警
silences:
  # 示例:在周六凌晨维护期间,屏蔽 BookKeeper 磁盘告警
  # 这个配置通常通过 Alertmanager API 动态添加,不写死在配置文件里
  # - matcher:
  #     alertname: BookKeeperDiskUsageHigh
  #   startsAt: '2024-01-01T00:00:00Z'
  #   endsAt:   '2024-01-01T06:00:00Z'
  #   createdBy: 'admin@example.com'
  #   comment: '周六凌晨维护窗口,临时静默磁盘告警'

Alertmanager的group_by配置很关键。它决定了什么样的告警会被归为一组发出去。比如两个Broker同时报了消息积压告警,如果它们的severity都是critical,那就会被归到同一个组里,只发一条通知,里面包含两个Broker的信息。这样既不会漏掉问题,也不会让值班人员被消息轰炸。

五、Grafana看板搭建

指标采集和告警规则配好了,光能发告警还不够,你需要一个直观的面板来随时查看集群状态。Grafana在这方面做得很好,可以直接导入Pulsar的社区看板,也可以自己定制。

5.1 Grafana数据源配置

先把Prometheus作为数据源添加到Grafana里。这个步骤通常在Grafana的界面上操作:Data Sources -> Add Data Source -> Prometheus -> 填入Prometheus地址。如果用配置文件来管理(比如用了Grafana Operator),可以这样写:

{
  "apiVersion": 1,
  "datasources": [
    {
      "name": "Prometheus-Pulsar",
      "type": "prometheus",
      "url": "http://prometheus:9090",
      "access": "proxy",
      "isDefault": true,
      "jsonData": {
        "httpMethod": "POST",
        "manageAlerts": false
      },
      "readOnly": true
    },
    {
      "name": "Prometheus-BookKeeper",
      "type": "prometheus",
      "url": "http://prometheus:9090",
      "access": "proxy",
      "isDefault": false,
      "jsonData": {
        "httpMethod": "POST"
      },
      "readOnly": true
    }
  ]
}

Grafana的Dashboard可以用JSON格式导出和导入。下面是一个Pulsar集群概览面板的JSON定义示例,展示了核心面板的查询配置:

{
  "title": "Pulsar集群监控总览",
  "uid": "pulsar-overview-001",
  "tags": ["pulsar", "messaging", "infrastructure"],
  "timezone": "browser",
  "refresh": "30s",
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "panels": [
    {
      "title": "消息吞吐量(每秒消息数)",
      "type": "timeseries",
      "gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
      "datasource": "Prometheus-Pulsar",
      "targets": [
        {
          "expr": "sum(rate(pulsar_broker_in_messages_total[5m]))",
          "legendFormat": "接收消息速率",
          "refId": "A"
        },
        {
          "expr": "sum(rate(pulsar_broker_out_messages_total[5m]))",
          "legendFormat": "发出消息速率",
          "refId": "B"
        }
      ],
      "fieldConfig": {
        "defaults": {
          "unit": "mps",
          "custom": {
            "fillOpacity": 20,
            "lineWidth": 2,
            "showPoints": "never"
          }
        }
      }
    },
    {
      "title": "消息积压总量",
      "type": "timeseries",
      "gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
      "datasource": "Prometheus-Pulsar",
      "targets": [
        {
          "expr": "sum(pulsar_broker_backlog_size_total)",
          "legendFormat": "总积压量(条)",
          "refId": "A"
        }
      ],
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "fillOpacity": 30,
            "lineWidth": 3,
            "pointRadius": 3
          }
        }
      },
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {"color": "green", "value": null},
          {"color": "yellow", "value": 50000},
          {"color": "red", "value": 100000}
        ]
      }
    },
    {
      "title": "存储缓冲区使用率",
      "type": "gauge",
      "gridPos": {"h": 8, "w": 6, "x": 0, "y": 8},
      "datasource": "Prometheus-Pulsar",
      "targets": [
        {
          "expr": "avg(pulsar_broker_storage_buffer_usage)",
          "refId": "A"
        }
      ],
      "fieldConfig": {
        "defaults": {
          "unit": "percentunit",
          "min": 0,
          "max": 1,
          "mappings": [],
          "thresholds": {
            "steps": [
              {"color": "green", "value": null},
              {"color": "yellow", "value": 0.6},
              {"color": "red", "value": 0.8}
            ]
          }
        }
      }
    },
    {
      "title": "BookKeeper磁盘使用率",
      "type": "stat",
      "gridPos": {"h": 8, "w": 6, "x": 6, "y": 8},
      "datasource": "Prometheus-Pulsar",
      "targets": [
        {
          "expr": "max(bookie_disk_usage_ratio)",
          "refId": "A"
        }
      ],
      "fieldConfig": {
        "defaults": {
          "unit": "percentunit",
          "mappings": [],
          "thresholds": {
            "steps": [
              {"color": "green", "value": null},
              {"color": "yellow", "value": 0.7},
              {"color": "red", "value": 0.85}
            ]
          }
        }
      }
    },
    {
      "title": "各Broker节点消费者数量",
      "type": "table",
      "gridPos": {"h": 8, "w": 12, "x": 12, "y": 8},
      "datasource": "Prometheus-Pulsar",
      "targets": [
        {
          "expr": "pulsar_broker_num_consumers{job=\"pulsar-broker\"}",
          "format": "table",
          "instant": true,
          "refId": "A"
        }
      ]
    }
  ]
}

这个面板JSON定义了5个核心面板:消息吞吐量的时序图、消息积压量的时序图(带阈值着色)、存储缓冲区使用率的仪表盘、BookKeeper磁盘使用率的统计图、以及各Broker消费者数量的表格。在实际使用时,你可以根据团队习惯把这些面板组合成不同的Grafana Dashboard页面。

5.2 PromQL查询语句常用技巧

在Grafana里写查询语句时,掌握几个常用的PromQL函数组合会让查询更灵活:

# ========================================
# PromQL 常用查询语句示例
# ========================================

# 1. 查看每个Broker的消息接收速率
# rate() 函数计算时间序列的每秒变化率
sum by (instance) (rate(pulsar_broker_in_messages_total[5m]))

# 2. 查看每个Topic的消息积压量
# 按 topic 标签分组,找出积压最严重的 Topic
topk(10, pulsar_broker_backlog_size_total by (topic))

# 3. 查看过去1小时内消息积压量的变化趋势
# 对比当前值和1小时前的值,判断积压是在增加还是在减少
pulsar_broker_backlog_size_total - pulsar_broker_backlog_size_total offset 1h

# 4. 查看BookKeeper磁盘使用率的平均值
# avg() 取所有节点的平均值
avg(bookie_disk_usage_ratio)

# 5. 查看单个Broker的内存缓冲区使用率,排除已经下线的节点
pulsar_broker_storage_buffer_usage{instance!="down"}

# 6. 计算消息端到端延迟的95分位数
# quantile() 函数计算指定分位数的值
quantile(0.95, pulsar_broker_subscription_delay)

# 7. 查看每个命名空间的Topic数量
# count() 函数统计标签值的数量
count(pulsar_broker_topics_count by (namespace))

PromQL的offset关键词特别有用,它可以让你查询"过去某个时间点"的数据,方便做趋势对比。topk()函数在排查积压问题时也很实用,一下子就能看出哪些Topic最严重。

六、应用场景分析

这套监控体系适用于不同的Pulsar部署场景,不同场景下关注的重点会有所不同。

6.1 消息队列日常运维场景

这是最基础的用法。每天值班人员打开Grafana面板,扫一眼消息吞吐量、积压量、存储缓冲区使用率、磁盘使用率这几个核心指标。只要这些指标在正常范围内,说明集群运行健康。如果有指标超出阈值,Grafana面板上会用颜色变化直观提示,同时Alertmanager也会发出告警通知到值班人员的手机或邮件。

6.2 大促或流量高峰期

大促期间消息量可能平时增长几倍甚至十几倍,这时候监控体系的价值就更大了。需要提前调整告警阈值,比如把消息积压阈值从10万条提到50万条,避免大促期间频繁误报。同时要在Grafana上重点关注消息吞吐量的时序图,观察流量是否平稳,有没有突刺。如果吞吐量突刺之后持续不回落,可能意味着消费者已经过载。

6.3 故障排查场景

当业务方反馈消息处理延迟的时候,值班人员可以按顺序检查:首先看Broker的消息吞吐量是否下降,如果吞吐量正常,说明生产端没问题;然后看积压量是否在增加,如果积压在增加,说明消费端有问题;再看BookKeeper的磁盘使用率和写入延迟,如果磁盘快满了,说明存储层有瓶颈;最后看网络指标和消费者数量,确认消费者是否正常连接。整个排查过程,所有需要的数据在Grafana面板上都能直接查到,不需要登录到各个节点上手动执行命令。

6.4 容量规划场景

长期来看,监控系统积累的历史数据对容量规划非常有价值。通过查看过去几周的吞吐量趋势和磁盘增长曲线,可以估算出未来需要扩容的时机。比如BookKeeper磁盘使用率每周增长2%,当前磁盘剩余空间够用3个月,那就可以提前安排扩容计划,避免突然磁盘写满导致服务不可用。

七、技术优缺点对比

7.1 Prometheus方案的优点

这套Prometheus + Grafana + Alertmanager的方案之所以被广泛采用,有几个核心优势。首先是生态成熟,Pulsar社区官方就推荐了这套方案,文档和看板模板都很齐全,上手成本低。其次是Prometheus的标签模型非常灵活,通过标签的任意组合就能实现多维度查询,不需要提前定义指标维度。第三是Grafana的可视化能力强大,从时序图到仪表盘到表格到拓扑图,几乎什么类型的可视化都能实现。第四是Alertmanager的告警管理能力完善,支持分组、去重、静默、路由,能有效减少告警风暴。

7.2 方案的局限与不足

当然,这套方案也不是完美的。Prometheus是单机部署的,数据存储在本地磁盘中,数据量大了之后会有性能问题。如果集群规模很大,Pulsar的指标数量可能达到数万级别,Prometheus的本地存储压力和查询延迟都会明显增加。这时候需要考虑引入Thanos或者Cortex来扩展。另外,BookKeeper的指标获取需要JMX Exporter做一层转换,这增加了一些配置复杂度。还有,Pulsar的一些内部指标(比如每个连接的具体状态)默认没有暴露,需要修改代码或者用Pulsar的Admin API来补充采集。

7.3 与其他方案的对比

另一种常见的方案是用Pulsar自带的Pulsar Manager加上自定义的监控脚本。这种方式的好处是轻量,不需要部署Prometheus,坏处是可视化能力有限、告警功能需要自己实现、历史数据查询不方便。再一种是基于Zabbix或者Datadog这类商业监控平台的方案,它们的优势是开箱即用、界面友好,但代价是需要付费授权,而且自定义指标的能力不如Prometheus灵活。

八、注意事项

8.1 指标粒度与存储成本

Pulsar的指标按Topic级别暴露,一个生产环境中可能有成千上万个Topic。每个Topic的指标都会带上topic标签,这意味着Prometheus里存储的数据量会非常庞大。建议在生产环境中开启topic_metrics_retention_minutes参数来限制Topic级别指标的保留时间,或者只把关键Topic的指标纳入监控范围。

8.2 告警规则调优

告警规则不是配一次就完事了,上线之后需要持续观察和调整。常见的调优操作包括:根据实际运行情况调整阈值(比如发现10万条积压的阈值太敏感,经常误报,就调到50万条);调整for参数来过滤瞬时抖动;对重复告警增加静默规则;对非工作时间的告警降低通知频率。

8.3 多环境隔离

如果生产环境、测试环境、开发环境都部署了Pulsar集群,一定要在Prometheus的配置里用标签做隔离。比如给生产环境的抓取配置加上environment: production标签,给测试环境加上environment: test标签。在Grafana查询语句里用{environment="production"}来过滤,确保不同环境的数据不会混淆。

8.4 监控本身的高可用

监控系统本身也需要保障高可用。Prometheus建议部署两个实例做主从切换,或者使用Thanos的Sidecar模式来实现多副本。Alertmanager支持集群模式,部署多个Alertmanager实例可以互相通信和去重。Grafana的Dashboard配置应该纳入Git版本管理,用Grafana Operator或类似的工具来实现自动化部署。

8.5 安全考虑

Pulsar的metrics端点默认没有认证,任何能访问该端口的人都可以看到指标数据。在生产环境中,建议对metrics端点加上网络层面的访问控制,只允许Prometheus所在的IP段访问。另外,Grafana和Alertmanager的Web界面也应该开启认证,防止未授权访问。

九、总结

搭建Pulsar集群监控体系的核心工作可以归纳为三步:第一步,确认Pulsar的指标暴露配置正确,能正常输出Prometheus格式的指标数据;第二步,配置Prometheus的抓取规则和Alertmanager的告警规则,把关键指标纳入监控范围;第三步,用Grafana搭建可视化看板,让运维人员能直观了解集群状态。整个过程不需要开发任何自定义代码,Pulsar和社区工具链已经提供了足够完善的监控能力。

真正让监控体系发挥价值的关键不在于配了多少告警规则、画了多少面板,而在于团队是否建立了"看监控、查告警、定阈值"的日常习惯。监控面板上的数字如果没人看,那就只是一个摆设。建议团队定期回顾告警记录,删除无意义的告警规则,优化有改进空间的阈值,让监控体系越用越好用。