2、运维数据采集:日志采集(Filebeat/Logstash)、指标采集(Prometheus)、链路追踪(Jaeger)

聊到智能运维,我第一个想到的就是数据。没有数据,你连系统出了什么问题都不知道,更别提什么预警了。说白了,运维的本质就是跟数据打交道。今天咱们就聊聊数据采集这三大件:日志、指标和链路追踪。

这三者各有各的用处。日志告诉你发生了什么,指标告诉你系统状态怎么样,链路追踪告诉你请求到底卡在哪了。缺一不可。我在项目中见过太多团队只盯着指标,结果线上出问题,日志一查全是错误,链路一追发现是某个服务超时。嗯,这就是典型的「数据孤岛」问题。

核心观点: 日志、指标、链路追踪,三者必须协同工作,才能构建完整的可观测性体系。
运维数据采集三大支柱 日志采集 Filebeat / Logstash 指标采集 Prometheus 链路追踪 Jaeger 数据汇聚层 存储与分析(ES / 时序数据库 / 对象存储) 三者协同,构建完整可观测性体系

2.1 日志采集:Filebeat 与 Logstash

日志这东西,说简单也简单,说复杂也复杂。我见过不少团队,日志随便打打,出了问题才后悔。你想想看,线上出了故障,你连日志都找不到,那得多被动?

我个人习惯用 Filebeat 做轻量级采集,Logstash 做集中处理。为什么这么搭?Filebeat 够轻,占资源少,适合部署在每台机器上。Logstash 功能强,能做各种过滤、转换、格式化。

我的经验: 千万别把 Logstash 直接部署在业务服务器上。它吃内存厉害,我见过有人把 Logstash 和 Java 应用放一起,结果 OOM 了。Filebeat 才是边车采集的正确选择。

来看一个典型的 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}"
  }
}
注意: 日志采集一定要考虑磁盘空间。我见过有人把日志打到磁盘爆满,导致系统崩溃。建议配置日志轮转,保留最近7天的日志就够了。

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)
}
避坑指南: 我曾经在项目中遇到采样率设置过高的问题。每个请求都采样,结果 Jaeger 的存储直接爆了。建议生产环境采样率设 1%-10%,或者用自适应采样。

链路追踪的价值在于,你能看到完整的调用链。比如一个请求慢,你可以看到是哪个服务慢,是数据库查询慢,还是网络延迟高。这些信息,日志和指标都给不了你。

2.4 三者如何协同

日志、指标、链路追踪,不是各自为战。我建议把它们关联起来:

维度 工具 关联方式
日志 Filebeat + Logstash + ES 在日志中注入 Trace ID
指标 Prometheus + Grafana 在指标中打标签,关联服务名
链路 Jaeger 通过 Trace ID 关联日志

举个例子,你在 Grafana 上看到某个服务的错误率飙升。点进去,看到具体的错误日志,再通过 Trace ID 去 Jaeger 里查完整的调用链。这样一套组合拳下来,问题定位就快多了。

我的建议: 在代码中统一打印 Trace ID 到日志里。这样出了问题,你从指标告警到日志,再到链路追踪,一路追下去,效率翻倍。

好了,数据采集这块就聊这么多。记住,数据是智能运维的基石,采集不好,后面的一切都是空中楼阁。下一章咱们聊聊数据存储和清洗,到时候再细说。


专注资料整理