2、运维数据采集:日志采集(Filebeat/Logstash)、指标采集(Prometheus)、链路追踪(Jaeger)
聊到智能运维,我第一个想到的就是数据。没有数据,你连系统出了什么问题都不知道,更别提什么预警了。说白了,运维的本质就是跟数据打交道。今天咱们就聊聊数据采集这三大件:日志、指标和链路追踪。
这三者各有各的用处。日志告诉你发生了什么,指标告诉你系统状态怎么样,链路追踪告诉你请求到底卡在哪了。缺一不可。我在项目中见过太多团队只盯着指标,结果线上出问题,日志一查全是错误,链路一追发现是某个服务超时。嗯,这就是典型的「数据孤岛」问题。
2.1 日志采集:Filebeat 与 Logstash
日志这东西,说简单也简单,说复杂也复杂。我见过不少团队,日志随便打打,出了问题才后悔。你想想看,线上出了故障,你连日志都找不到,那得多被动?
我个人习惯用 Filebeat 做轻量级采集,Logstash 做集中处理。为什么这么搭?Filebeat 够轻,占资源少,适合部署在每台机器上。Logstash 功能强,能做各种过滤、转换、格式化。
来看一个典型的 Filebeat 配置:
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
output.logstash:
hosts: ["logstash.example.com:5044"]
这里有个坑,我必须要说。多行日志的处理,很多人会忽略。比如 Java 的异常堆栈,它跨多行,如果你不配置 multiline,那一条异常会被拆成好几条日志,查起来简直要命。我曾经因为这个排查了一个下午,最后发现是 multiline 没配好。
Logstash 这边,我一般会做几件事:
- 解析日志格式(grok 正则)
- 添加时间戳、服务名等元数据
- 过滤掉健康检查等无用日志
- 输出到 Elasticsearch
# logstash.conf
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
}
date {
match => [ "timestamp", "ISO8601" ]
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}
2.2 指标采集:Prometheus
指标采集,说白了就是看系统的「体检报告」。CPU 高不高?内存够不够?请求量怎么样?这些都需要指标来说话。
Prometheus 是我最常用的指标采集工具。它采用拉模式,主动去抓取目标暴露的指标。为什么选它?因为它生态好,社区活跃,而且 PromQL 查询语言非常强大。
我建议的架构是这样的:
- Exporter:部署在各服务上,暴露指标端点
- Prometheus Server:定期拉取指标,存储到本地时序数据库
- Alertmanager:根据规则触发告警
- Grafana:可视化展示
来看一个 Prometheus 配置示例:
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
- job_name: 'app'
metrics_path: '/metrics'
static_configs:
- targets: ['app1:8080', 'app2:8080']
这里有个细节,scrape_interval 设置多久拉一次。我个人习惯设 15 秒,太频繁会增加系统负担,太稀疏又可能错过异常。你想想看,如果 1 分钟拉一次,那中间出问题你可能要等 1 分钟才能发现。
PromQL 查询也很重要。比如你想看过去 5 分钟的平均 CPU 使用率:
avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100
嗯,这里要注意,PromQL 的语法跟 SQL 完全不一样,刚开始可能会不习惯。我建议多练练,把常用的查询写成模板,方便复用。
2.3 链路追踪:Jaeger
链路追踪,这是微服务架构下的必备工具。为什么?因为一个请求可能经过十几个服务,你光看日志和指标,根本不知道请求到底卡在哪了。
Jaeger 是 CNCF 的毕业项目,跟 Prometheus 一样,都是云原生生态的标配。它的核心概念有三个:Trace(追踪)、Span(跨度)、Context(上下文)。
我建议的接入方式是这样的:
- 在代码中埋点,生成 Span
- 通过 Agent 或 SDK 上报到 Collector
- Collector 存储到后端(Elasticsearch 或 Cassandra)
- 通过 UI 查询和展示
来看一个 Go 语言的埋点示例:
import (
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
)
func main() {
tracer, closer := jaeger.NewTracer("my-service",
jaeger.NewConstSampler(true),
jaeger.NewReporter(...))
defer closer.Close()
span := tracer.StartSpan("handle-request")
defer span.Finish()
// 业务逻辑
doSomething(span)
}
链路追踪的价值在于,你能看到完整的调用链。比如一个请求慢,你可以看到是哪个服务慢,是数据库查询慢,还是网络延迟高。这些信息,日志和指标都给不了你。
2.4 三者如何协同
日志、指标、链路追踪,不是各自为战。我建议把它们关联起来:
| 维度 | 工具 | 关联方式 |
|---|---|---|
| 日志 | Filebeat + Logstash + ES | 在日志中注入 Trace ID |
| 指标 | Prometheus + Grafana | 在指标中打标签,关联服务名 |
| 链路 | Jaeger | 通过 Trace ID 关联日志 |
举个例子,你在 Grafana 上看到某个服务的错误率飙升。点进去,看到具体的错误日志,再通过 Trace ID 去 Jaeger 里查完整的调用链。这样一套组合拳下来,问题定位就快多了。
好了,数据采集这块就聊这么多。记住,数据是智能运维的基石,采集不好,后面的一切都是空中楼阁。下一章咱们聊聊数据存储和清洗,到时候再细说。