监控工具不是“看得见”的事,而是“摸得着”的保障

一个会部署的人
2025-06-25 06:20
阅读 690

作为一名有着五年工作经验的开发工具工程师,我几乎每天都和监控工具打交道。不管是服务器资源使用、服务运行状态,还是用户行为数据和异常报警机制,监控贯穿了整个系统生命周期。但我真正意识到“监控”重要性,是在一次线上故障之后。

故事从一个凌晨说起

故事从一个凌晨说起

那是我在一家中型互联网公司负责平台稳定性期间,我们正在支撑一款面向中小企业的 SaaS 产品。系统采用的是微服务架构,部署在 AWS 上,用 Kubernetes 做容器编排。整体服务看似稳定,但随着业务增长,系统的复杂度也在不断上升。

某天凌晨两点,我在睡梦中被钉钉消息叫醒。运维组发来一条紧急通知:“订单处理延迟严重,部分队列堆积,请求超时率飙升。” 我赶紧打开电脑连接到线上环境,却发现除了日志里一堆 ERROR 和慢查询之外,并没有直观的数据告诉我问题出在哪里:是数据库瓶颈?Kafka消费慢?Redis缓存击穿?服务节点挂掉?

那个时候我们虽然有基础的监控——主要是 Zabbix 做的主机监控和简单的 JVM 指标采集,但面对分布式系统中的链路追踪、多维度聚合指标、调用延时分析等需求,完全捉襟见肘。

我们需要更细粒度、更智能的监控方案

我们需要更细粒度、更智能的监控方案

第二天我们开了个会,讨论如何构建一套真正能“看到”系统的监控体系。目标很明确:

  • 实现服务端全链路追踪(调用链)
  • 支持自定义指标采集与可视化
  • 高效支持报警规则配置
  • 轻量级、可扩展性强、适配现有的微服务架构

我们的第一个技术选型就是引入 Prometheus + Grafana 作为指标监控和展示层,搭配 OpenTelemetry 做应用层指标埋点和链路追踪。之所以没选择像 Datadog 这样的商业解决方案,是因为当时我们团队规模不大,预算有限,更倾向于开源可控的技术栈。

技术选型的几点权衡考虑

技术选型的几点权衡考虑

  1. Prometheus 的拉取模型 vs Zabbix 的推送模型
    Prometheus 是通过主动拉取目标节点的指标接口(通常是 /metrics)获取数据,这在动态服务发现场景下非常灵活;而 Zabbix 则需要客户端主动上报,配置相对繁琐,尤其在服务频繁扩缩容时表现不佳。

  2. 指标与日志分离 vs 合一
    我们没有一开始就上 ELK(Elasticsearch、Logstash、Kibana),因为日志分析虽然重要,但在初期阶段更关注服务的性能指标和调用链。直到后来上了 Loki 来做轻量日志收集,才把日志纳入统一观察体系。

  3. 链路追踪的选择:Jaeger or Zipkin
    最后我们选用了 Jaeger,因为它对 OpenTelemetry 的兼容性更好,且社区活跃度高。Zipkin 在早期我们也做过 PoC(Proof of Concept),但在服务依赖关系图谱的展示方面略逊一筹。

  4. 报警机制:Alertmanager 为主,Grafana 为辅
    Alertmanager 更擅长管理报警路由、静默规则和分级通知,而 Grafana 的报警功能更适合小团队和个人项目,在团队协作场景下稍显单薄。

第一版落地过程:边干边踩坑

我们在测试环境中快速搭建起 Prometheus + Grafana + Node Exporter + OpenTelemetry Collector 的结构,然后开始将服务接入。以下是几个关键步骤:

步骤一:在 Java 微服务中集成 OpenTelemetry SDK

我们的服务基本都是 Spring Boot 项目,OpenTelemetry 提供了自动 Instrumentation Agent,只需要在启动参数中加入:

-javaagent:/path/to/opentelemetry-javaagent-all.jar \
-Dotel.service.name=order-service \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317

这样就可以自动收集 HTTP 请求、JVM 状态、Spring MVC 方法调用时间、SQL 查询耗时等信息。

步骤二:手动埋点补充关键指标

有些指标是框架无法自动识别的,比如订单状态变更次数、异步任务执行情况等。我们就用 OpenTelemetry SDK 自己编写了指标埋点代码,以增加上下文信息和自定义计数器:

Meter meter = GlobalOpenTelemetry.getMeter("order-service");

Counter<Long> orderProcessedCounter = meter.counterBuilder("orders.processed")
        .setDescription("Counts the number of processed orders.")
        .setUnit("1")
        .build();

// somewhere in the code
orderProcessedCounter.add(1, Attributes.of(AttributeKey.stringKey("type"), "paid"));

这部分代码可以让我们在 Grafana 上根据类型过滤展示不同类型的订单处理情况。

步骤三:配置 Prometheus 数据源

Grafana 接入 Prometheus 相当简单,只要添加 Prometheus 数据源即可,URL 填写 http://prometheus-server:9090 就可以了。

Prometheus 的核心配置文件 prometheus.yml 如下所示:

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'order-service'
    metrics_path: '/actuator/prometheus' # Spring Boot 对接 Micrometer 的路径
    static_configs:
      - targets: ['order-service:8080']

对于 Spring Boot 项目,默认已经集成了 Micrometer,可以直接暴露 Prometheus 格式的指标。

坑来了,而且不止一个

刚开始实施这套系统的时候,我们遇到了不少挑战。

问题一:指标重复采集 & 冲突命名

一开始多个服务使用了不同的指标命名方式,例如有的用 orders.count.success,有的用 order_processed_total,还有人用了驼峰式 orderCountSuccess,导致聚合分析困难。

解决方法:制定指标命名规范

我们最终定下来几条基本原则:

  • 使用蛇形命名法(snake_case)
  • 全局前缀统一,如 app_<service_name>_
  • 以动作或对象名开头,表示语义清晰,例如 http_requests_latency_seconds, task_execution_count
  • 加注单位说明,如 _count, _seconds, _bytes

问题二:Grafana Panel 数据显示不稳定

有时候图表看起来数据不连续或者丢失了历史记录,一度怀疑是采集丢了数据。

解决思路:排查数据保留策略和采样频率

最终发现是因为 Prometheus 默认只保留两周的数据,而且采样间隔设置为60秒。我们在 prometheus.yml 中调整了配置:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

storage:
  tsdb:
    retention.time: 30d

这样既能提升实时响应速度,又延长了历史数据的保存周期。

问题三:报警太多反而麻木

我们最开始配置了十几个报警规则,每天动不动就有微信、短信甚至电话提醒,结果反而是运维同事都懒得看了。

对策:分优先级、加静默策略、减少误报

  • 给报警打标签,分为 critical、warning、info 三个级别
  • 关键报警发送到企业微信群,非紧急的走邮件
  • 重要节假日或发布窗口设置静默时间
  • 优化报警规则,比如“CPU>90%持续5分钟”比“即时报警”更有意义

结果超出预期

整套系统上线两个月后,我们明显感受到变化:

  • 定位问题快了至少十倍:以前遇到延迟问题要靠看日志、查线程、反复重启才能发现线索,现在直接进 Grafana 查 CPU、线程池积压、链路调用耗时,几分钟就能判断是哪个服务的问题。
  • 报警准确率提高:合理配置的报警规则让团队信任度大大增强,不再轻易忽略通知。
  • 业务方也受益:运营部门也开始用 Grafana 查每日交易量波动趋势,协助他们分析市场变化。

有一次我们还用 Jaeger 成功发现了某个服务在高峰期出现了“长尾请求”——原本平均耗时 200ms 的请求,偶发会有超过 5s 的延迟。最终查出是数据库死锁导致线程阻塞,而这之前根本没人注意到这个问题。

如果让我重来一遍……

这几年用过各种监控工具,从最初的 Nagios 到 Zabbix,再到 Prometheus、Datadog、New Relic、SkyWalking……我觉得最重要的是:

1. 监控应该是“无感”的,而不是“附加”的

理想的监控是对业务代码几乎没有侵入性,最好是通过 Sidecar 或者 Service Mesh 注入的方式完成监控数据采集。现在的 OpenTelemetry Collector 配合 Istio 就能做到这点,未来我会尝试更多云原生监控方案。

2. 监控不只是开发的事

应该建立一个跨职能的观测小组(Observability Team),包括后端、前端、SRE、产品和 QA。大家共同参与仪表盘设计、告警规则评审和复盘会议。

3. 监控要有“业务视角”

别只盯着系统指标,比如我们曾经花了大量时间关注 JVM 内存,却忽略了“支付失败率”这个业务层面的重要指标。后来我们专门建立了“核心指标清单”,由产品、运营和工程共同维护。

4. 保持轻量化,避免过度工程

监控系统本身如果太复杂,反而会成为负担。比如我们曾试图用 Thanos 实现全局存储,结果维护成本极高,后来改为按业务单元拆分 Prometheus 实例,更加灵活易维护。

一些实用建议给读者

代码质量检测-1

  • 先做最小可用监控(Minimum Viable Monitoring):不是所有服务都要立刻接入全部模块,可以从基础设施监控开始,再逐步添加应用指标和链路追踪。
  • 统一工具链很重要:如果你已经在用 Prometheus,就尽量围绕它选生态组件,比如 Loki 日志、Tempo 分布式追踪,它们之间可以天然集成。
  • 监控即文档:好的监控面板本身就是一份系统状态说明书,定期整理和更新 Dashboard 非常有必要。
  • 不要迷信数字:数值只是参考,背后逻辑才是重点。比如 QPS 突然下降不一定是坏事,可能是新版本接口效率提高了。

监控的意义在于“看见”

写到这里,我想说,监控工具不是让你去“看报表”,而是帮你“看清真相”。当你能随时知道系统在干嘛、哪里卡住了、为什么变慢了,你的安全感和掌控力就会完全不同。

作为一个开发者,我对监控的理解早已超越“看看 CPU 占了多少”那么简单。它更像是你和系统之间的对话方式——你在问:“你还好吗?”系统答:“有点累了,要不要扩容一下?” 你接着问:“是不是哪里不舒服?” 它说:“嗯,最近 DB 连接池压力大。”

这种默契,只有长期相处、不断调试、不断改进监控系统的人才能体会到。希望这篇文章能给你一点启发,愿我们都能打造出更“透明”的系统,让每一个 bug 都无所遁形。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝