4. 日志收集与集中管理(ELK Stack、Splunk等)

说实话,做故障排查最怕什么?

不是问题多难,而是日志在哪都不知道。我记得早期带团队时,每次线上出问题,大家就各自登录服务器,用 grep 在几十个 log 文件里翻。那效率,简直了。你想想看,几十台机器,每台翻一遍,等找到线索,用户都骂了好几轮了。

后来我下定决心,必须上集中日志管理。今天我们就聊聊这玩意儿到底怎么玩。

集中日志管理的核心价值:
1. 日志统一收集,告别 "ssh 到每台机器" 的原始时代。
2. 建立索引,实现秒级搜索。
3. 可视化展示,趋势一目了然。
4. 告警联动,问题还没爆发就先发现。

4.1 主流方案:ELK vs Splunk

目前业界两大主流方案:ELK Stack(开源)和 Splunk(商业)。我个人偏爱 ELK,主要是灵活,但 Splunk 在某些场景确实省心。

我们先看核心对比:

维度 ELK Stack Splunk
开源/商业 开源(Elasticsearch + Logstash + Kibana) 商业软件
上手难度 中(组件多,需要调优) 低(开箱即用,文档全)
扩展性 极强,水平扩展是原生能力 较强,但受 license 限制
搜索语法 基于 Lucene 的 Query DSL 类 SQL 的 SPL(搜索处理语言)
运维成本 高(ES 集群调优是个坑) 低(Splunk 帮你兜底)
成本 软件免费,运维人力贵 软件许可费贵,运维轻松

怎么选?我的建议是:小团队、预算有限直接上 ELK。大企业、业务敏感度高,Splunk 更省心。我在上一家公司两种方案都用过,后面会细说。

日志收集与集中管理流程图 应用日志 (app.log) 系统日志 (syslog) SDK 日志 (debug) 采集源 (Logstash/Filebeat) 采集源 (Splunk Universal Forwarder) 缓冲层 (Kafka/Redis) 传输层 (TCP/UDP/TLS) 存储检索 (Elasticsearch) 存储检索 (Splunk Indexer) 统一查询入口 Kibana / Splunk Web 可视化 + 告警

4.2 ELK 实战:从零搭一套日志系统

我重点讲讲 ELK。这玩意儿拆开讲就三个组件:

  • Logstash:负责采集、解析、过滤日志。支持各种输入源。
  • Elasticsearch:负责存储和索引,提供 RESTful 查询接口。
  • Kibana:负责展示,画图表、做大盘。

现在的趋势是:用 Filebeat 替代 Logstash 做轻量采集。Filebeat 是 Go 写的,资源占用极低,我现场的系统都是这么配的。

4.2.1 配置示例:Filebeat + Logstash + ES

下面是一个典型的 Filebeat 配置文件,采集 app-debug.log:

# filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/myapp/app-debug.log
  # 加个标签,方便后期区分
  tags: ["myapp-debug"]

output.logstash:
  hosts: ["logstash-server:5044"]

# 还可以加写入 Kafka 做缓冲
# output.kafka:
#   hosts: ["kafka-broker:9092"]
#   topic: "myapp-logs"

Logstash 接收后怎么做解析?举个例子,解析一个多行异常堆栈:

# logstash.conf
input {
  beats {
    port => 5044
  }
}

filter {
  if "myapp-debug" in [tags] {
    multiline {
      pattern => "^\s"
      what => "previous"
      negate => false
    }
    # 用 grok 提取关键字段
    grok {
      match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:level}\] %{GREEDYDATA:msg}" }
    }
    date {
      match => [ "timestamp", "ISO8601" ]
    }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "myapp-debug-%{+yyyy.MM.dd}"
  }
}
避坑经验:我曾经踩过一个坑——Logstash 的 multiline 插件默认会把所有行吞掉,直到遇到下一个匹配行。如果你的堆栈每行开头都带空格,那就必须用 pattern => "^\s" 配合 what => "previous"。否则堆栈会被拆成一条条独立的日志,完全没法看。

4.3 Splunk 使用要点

Splunk 相对省心。它的核心是 SPL(Search Processing Language),说白了就是一种专为搜索日志设计的查询语法。查个接口调用次数:

index=myapp sourcetype=json
| search "api/v1/users"
| stats count by status
| sort - count

Splunk 的好处是:你不需要建索引,数据进来它就自动建好了。这对新手特别友好。但代价是——贵。我在某金融公司部署过 Splunk 集群,光 license 就花了小几十万,不过考虑到业务重要性,这个钱花得值。

4.4 最佳实践与坑点

日志集中管理不是说把日志堆到一起就行。我总结了几个关键点:

  1. 日志标准化:所有团队必须约定日志格式。我们当时统一要求:时间戳 + 日志级别 + 来源模块 + 请求 ID + 消息内容。这样解析起来才方便。
  2. 磁盘与性能规划:ES 集群写入太多会 IO 打满。我建议用 SSD,并且根据日志量提前规划分片数。一般日存量 ≤ 1TB,分片 5-10 个就够了。
  3. 生命周期管理:日志不能无限存。生产环境 debug 日志最多保留 7 天,info 日志 30 天,error 日志 90 天。利用 ES 的 ILM(索引生命周期管理)自动删除。
  4. 安全管控:日志里可能有用户密码、 等敏感信息。在 Logstash 或 Splunk 输入端做 脱敏(mask) 处理,避免数据泄露。
警告:曾经有个团队把所有日志都一股脑丢到 ES 里,包括每秒打印几百条的 DEBUG 日志。结果 ES 集群直接被打死,线上业务都受了影响。
记住:日志采集一定要设置 限流(throttle) 和 采样(sampling)。高频日志可以按比例采集,或者设置每秒最多 1000 条。

4.5 从日志到故障定位

集中管理之后,排查故障就变成了一个 搜索 动作。比如:

  • 用户反馈支付失败?查 requestId=xxx,几十毫秒就能看到完整链路。
  • 系统突然变慢?看 Kibana 大盘,观察 response_time_avg 趋势,找到时间拐点。
  • 某个接口报 500 暴增?直接在 Kibana 里写个 level:ERROR AND api:/users,秒出结果。

我个人习惯把 关键错误 单独设置一个索引,比如 error-*。这样搜起来快,也不怕 debug 日志干扰。真正故障时,每秒钟都要抢,别浪费时间过滤无用的信息。