关于监控工具的一些经验

奇妙之法师
2025-06-28 03:32
阅读 592

关于监控工具的一些经验

背景:为什么需要监控?

我做运维和平台开发很多年了,从最早的小型创业团队到后来的中大型企业服务系统,经历过无数次的故障排查、性能瓶颈分析、业务异常预警。其中给我印象最深的,是三年前我们公司的一次大促上线事故。

那次项目是面向全国用户的一次营销活动,预期流量比平时高出几十倍,整个技术团队提前一个月就开始压测、优化、准备容灾方案。但就在活动当天凌晨,我们的订单系统突然开始大面积超时,响应时间从200ms飙到了几秒,甚至出现部分接口直接503不可用的情况。

问题发生时,我们能做的第一件事就是看日志,但日志量太大,根本没法快速定位。然后想到看监控,结果发现……监控居然没报警!原来,报警规则设置的是“接口平均延迟超过1秒”,而由于数据聚合方式的问题,当时的平均值并没有明显变化——大量超时请求被正常请求“平均”掉了。

这起事件后,我们彻底重构了整个监控体系。也是从那时起,我对监控这件事有了更深刻的理解:监控不是为了展示好看的数据大盘,而是要在关键时刻帮我们发现问题、解决问题

这篇文章,我想结合这几年的经历,聊聊在实际工作中如何选择和使用监控工具,以及踩过的一些坑和收获的经验。


问题描述:我们遇到了什么挑战?

回到那个大促事故的案例。当时我们使用的监控方案主要包括:

  • Prometheus + Grafana 做基础指标采集与可视化
  • ELK 做日志收集和检索
  • 自研的一个告警系统(基于Prometheus Alertmanager扩展)

但这次出问题的地方并不在于某一个工具本身坏了,而是在于我们对监控的认知存在偏差。有几个关键点:

  1. 指标聚合不合理:只关注了“平均延迟”,没有看 P95 或 P99 指标。
  2. 缺少上下文信息:监控只是看服务器层面的 CPU 内存,没有追踪具体接口、调用链路。
  3. 告警阈值设定不科学:没有根据业务高峰期历史数据动态调整阈值。
  4. 缺乏服务依赖关系图谱:当 A 服务出现问题,影响的是 B、C、D 等多个下游系统,但我们根本不知道这些依赖关系,只能靠人工逐个排查。
  5. 日志和监控分离:问题发生时要跳来跳去,效率极低。

这些问题其实非常典型,很多中小型团队都会遇到。


解决方案:我们是怎么做的?

为了解决上述问题,我们在接下来的半年里做了几个大的改动:

1. 引入 APM 工具(SkyWalking)

最初我们是用 OpenTracing + Jaeger 来做全链路追踪,但在实际使用过程中发现 Jaeger 的 UI 不够友好,集成成本也高。最终选择了 SkyWalking,因为:

  • 支持 Java、Go、Node.js 多语言
  • 提供开箱即用的服务拓扑图
  • 对 Dubbo 和 Spring Cloud 微服务框架支持良好
  • 社区活跃,文档丰富

通过引入 SkyWalking,我们可以清晰地看到接口调用耗时分布、慢 SQL、上下游依赖等信息,极大地提升了排障效率。

2. 优化 Prometheus 报警策略

原来的报警只关注“均值”,这是大忌。现在我们会同时监控以下几个维度:

  • P99 响应时间
  • 错误率(如 5xx、4xx)
  • 请求吞吐量波动
  • 单机负载均衡一致性(是否有热点机器)

我们还接入了 Promtail + Loki 来实现日志告警联动,比如当某个接口错误数激增的同时,Loki 也会触发对应的日志级别告警。

3. 实现多维监控视图

以前我们只有主机级别的监控仪表盘,后来我们做了三类 Dashboard:

  • 基础设施层(CPU、内存、磁盘IO、网络带宽)
  • 应用层(JVM状态、线程数、GC情况)
  • 业务层(接口成功率、QPS、P99延迟)

每一层之间可以通过链接跳转,也可以在 Grafana 中设置 Panel-Level 的关联过滤,比如点击某台机器就可以自动筛选出该机器上所有应用的指标。

4. 构建服务依赖拓扑图

我们基于 SkyWalking + Consul 注册中心的数据,构建了一个简单的服务依赖图谱,可以实时看到服务之间的调用关系。一旦某个核心服务异常,可以直接定位受影响的下游系统,大大缩短了应急响应时间。

5. 告警收敛机制优化

之前的告警通知机制很简单粗暴:一旦触发就发钉钉群、企业微信、短信。这导致了一个问题——告警风暴。特别是在系统级故障下,几十条告警一起炸,反而掩盖了真正严重的问题。

后来我们采用如下策略:

  • 利用 Alertmanager 分组机制:把同一类错误归为一组,合并通知
  • 设置静默规则:某些定时任务失败不会频繁打扰值班人员
  • 推送优先级分级:核心服务异常推高级别通知(电话通知),非核心服务用文字通知即可

此外,我们也搭建了自己的“告警知识库”,每次处理完一个告警类型,就把解决方案写进去,并和监控指标绑定起来,下次再遇到类似问题可以直接参考。


代码实践:一些关键配置和代码片段

Prometheus 报警规则示例(基于 P99):
groups:
- name: http-latency-warning
  rules:
  - alert: HighHttpP99Latency
    expr: histogram_quantile(0.99, sum(rate(http_server_request_latency_seconds_bucket[5m])) by (le, service))
      > 1.0
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "High latency detected for {{ $labels.service }}"
      description: "{{ $labels.service }} has p99 latency above 1s (current value: {{ $value }}s)"

这段配置的意思是:如果某个服务在过去5分钟内的 HTTP 请求 P99 延迟超过了1秒,并且持续2分钟以上,则触发一个“警告”级别的告警。

版本控制工具使用-2

使用 SkyWalking Agent 接入 Go 服务

SkyWalking 支持多种语言,对于 Go 服务,我们使用的是 go2sky(Apache SkyWalking Go Agent):

package main

import (
    "github.com/SkyAPM/go2sky"
    "github.com/SkyAPM/go2sky/reporter/grpc"
)

func main() {
    // 初始化 Reporter,连接 SkyWalking OAP
    reporter, err := grpc.NewReporter("oap-host:11800")
    if err != nil {
        log.Fatalf("failed to create reporter: %v", err)
    }
    
    defer reporter.Close()


![开发环境配置界面-1](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025062803/1ca5d75a-12a8-4add-9289-7ca6d7b15ef6.jpg)


    // 创建 Tracer
    tracer, err := go2sky.NewTracer("your-service-name", go2sky.WithReporter(reporter))
    if err != nil {
        log.Fatalf("failed to create tracer: %v", err)
    }

    // 后面就可以在处理请求的时候打 Span 了
}

这个 Tracer 可以与 Gin、Gorilla Mux、gRPC 等各种框架集成,自动生成 Trace ID 和调用链路。

日志告警联动(Promtail + Loki 示例)

Promtail 配置:

server:
  http_listen_port: 9080

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki.example.com:3100/loki/api/v1/push

scrape_configs:
  - job_name: system
    static_configs:
      - targets: [localhost]
        labels:
          job: varlogs
          __path__: /var/log/*.log

Loki 查询语句示例(匹配错误日志并报警):

{job="varlogs"} |~ "ERROR" 
| json
| level = "error"

踩坑经验分享

下面是一些在实际实施过程中踩过的坑,希望能帮助你少走弯路。

1. Prometheus 存储压力过大

刚开始我们把所有指标都一股脑往 Prometheus 上塞,结果几个月下来存储暴涨,查询效率急剧下降。后来我们做了几点优化:

  • 分拆实例:核心服务、边缘服务、基础设施工具分别部署不同的 Prometheus 实例
  • 远程存储:将长期数据迁移到 VictoriaMetrics 或 Thanos
  • 降采样处理:某些非核心指标保留3天即可
  • 指标白名单控制:不是所有指标都要暴露出来,有些统计粒度太细反而拖慢性能
2. SkyWalking Agent 启动慢

我们在 Java 服务中使用 SkyWalking Agent,启动速度明显变慢。排查发现是因为默认启用了 JVM 指标自动采集,占用了很多资源。最后通过以下方式优化:

  • agent/config/agent.config 中关闭不需要的模块:
agent.ignore_suffix=.jar,.war,.class
agent.sample=5000 # 控制采样率
agent.trace.ignore_suffix=.jpg,.css,.js,.gif,.png
  • 限制采集的线程数和埋点深度
3. 告警太多没人管

之前我们设置了一个统一的 Slack 机器人推送所有告警,结果一有问题大家就不看了。后来改成了两个机制:

  • 按业务归属划分告警接收人:比如支付系统的告警推给对应小组,不再搞全员轰炸
  • 设置静默时段和节假日规则:一些不影响用户体验的小问题可以在白天修复

效果总结:我们的收益是什么?

经过这一轮监控体系的改造后,我们得到了非常明显的效果提升:

  • 故障响应时间缩短了70%:得益于 APM 的调用链分析能力
  • 误报警率降低 90%:新的告警策略和抑制规则起了很大作用
  • 运维同学满意度大幅提升:终于不用天天翻日志找问题了
  • 新同事上手更快:有了完整的监控视图和服务拓扑图,理解系统结构不再难

更重要的是,我们建立了统一的监控规范和标准流程,后续新项目只需要按照模板部署,就能快速接入监控系统。


经验分享:给你的建议

如果你正在或者准备搭建自己的监控体系,下面是我这些年总结出来的几点建议,希望能帮到你:

✅ 明确目标:监控是为了发现什么问题?

不要为了监控而监控。你需要先想清楚:你要监控的是稳定性?性能瓶颈?还是业务异常?不同目标对应的监控策略完全不同。

✅ 从基础做起,逐步演进

没必要一开始就整一套完美的系统。先从基础设施监控开始(CPU、内存、磁盘),再加应用层(线程、GC、JVM),最后再考虑业务指标(成功率、转化率、延时等)。

✅ 重视“上下文”的可视化

一个好的监控体系应该是“可钻取”的。比如看到某个服务有问题,你可以一步步深入到底层节点、接口、SQL,甚至日志。

✅ 告警要有上下限和收敛机制

一定要设置合理的阈值,避免“狼来了”效应。同时注意分类分级,让真正重要的告警脱颖而出。

✅ 监控是基础设施的一部分,要自动化部署

监控组件也要纳入 CI/CD 流程中。每个服务上线时都应该自动注入必要的探针或监控Agent。

✅ 给研发提供自助监控能力

有时候研发自己也能发现性能问题。我们可以提供一套轻量级的“自助看板”系统,让开发者可以快速查看自己负责模块的指标。


写在最后

监控从来不是一个冷冰冰的数字看板,它是整个系统的眼睛。它不仅告诉我们什么时候出了问题,还能告诉我们系统是如何运行的、哪些地方可以优化。

这几年我在监控这件事上走了不少弯路,也犯过不少错误。但我始终相信一句话:“看不到的东西,是最危险的。

如果你也在做监控相关的事情,希望这篇文章能给你带来一点点启发,哪怕只是让你少踩一个坑,那我就心满意足了。

最后附一句小彩蛋:我们团队现在有一个内部文化叫做「No Data No Bug」——没有监控数据支撑的故障汇报,在我们看来都不够完整。你也可以试着建立一个属于你们团队的监控文化 😄


如有其他问题欢迎留言讨论!

评论 0

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