关于监控工具的一些经验
关于监控工具的一些经验
背景:为什么需要监控?
我做运维和平台开发很多年了,从最早的小型创业团队到后来的中大型企业服务系统,经历过无数次的故障排查、性能瓶颈分析、业务异常预警。其中给我印象最深的,是三年前我们公司的一次大促上线事故。
那次项目是面向全国用户的一次营销活动,预期流量比平时高出几十倍,整个技术团队提前一个月就开始压测、优化、准备容灾方案。但就在活动当天凌晨,我们的订单系统突然开始大面积超时,响应时间从200ms飙到了几秒,甚至出现部分接口直接503不可用的情况。
问题发生时,我们能做的第一件事就是看日志,但日志量太大,根本没法快速定位。然后想到看监控,结果发现……监控居然没报警!原来,报警规则设置的是“接口平均延迟超过1秒”,而由于数据聚合方式的问题,当时的平均值并没有明显变化——大量超时请求被正常请求“平均”掉了。
这起事件后,我们彻底重构了整个监控体系。也是从那时起,我对监控这件事有了更深刻的理解:监控不是为了展示好看的数据大盘,而是要在关键时刻帮我们发现问题、解决问题。
这篇文章,我想结合这几年的经历,聊聊在实际工作中如何选择和使用监控工具,以及踩过的一些坑和收获的经验。
问题描述:我们遇到了什么挑战?
回到那个大促事故的案例。当时我们使用的监控方案主要包括:
- Prometheus + Grafana 做基础指标采集与可视化
- ELK 做日志收集和检索
- 自研的一个告警系统(基于Prometheus Alertmanager扩展)
但这次出问题的地方并不在于某一个工具本身坏了,而是在于我们对监控的认知存在偏差。有几个关键点:
- 指标聚合不合理:只关注了“平均延迟”,没有看 P95 或 P99 指标。
- 缺少上下文信息:监控只是看服务器层面的 CPU 内存,没有追踪具体接口、调用链路。
- 告警阈值设定不科学:没有根据业务高峰期历史数据动态调整阈值。
- 缺乏服务依赖关系图谱:当 A 服务出现问题,影响的是 B、C、D 等多个下游系统,但我们根本不知道这些依赖关系,只能靠人工逐个排查。
- 日志和监控分离:问题发生时要跳来跳去,效率极低。
这些问题其实非常典型,很多中小型团队都会遇到。
解决方案:我们是怎么做的?
为了解决上述问题,我们在接下来的半年里做了几个大的改动:
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分钟以上,则触发一个“警告”级别的告警。

使用 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()

// 创建 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