日志管理:集中式日志架构(ELK/EFK)、日志采集与传输(Filebeat/Logstash)、日志分析与检索技巧

日志这东西,平时没人搭理它,一出事它就是唯一的救命稻草。我见过太多团队,系统崩了连日志都找不到,或者找到了打不开,打开了看不懂。说白了,日志管理不是锦上添花,是雪中送炭。

这一章,咱们聊聊集中式日志架构怎么搭,采集传输怎么搞,以及检索分析有哪些实用技巧。嗯,都是我在生产环境里摸爬滚打总结出来的。

集中式日志架构:ELK 还是 EFK?

先说说架构选型。ELK 是 Elasticsearch、Logstash、Kibana 三件套。EFK 就是把 Logstash 换成 Fluentd。我个人习惯用 EFK,原因很简单——Fluentd 更轻量,资源占用少,而且天然支持 Kubernetes。

但这不是绝对的。我在项目中遇到过 Logstash 处理复杂数据转换的场景,它的 Filter 插件生态确实比 Fluentd 丰富。你想想看,如果你的日志格式特别奇葩,需要大量正则解析和字段提取,Logstash 会更顺手。

下面是一个典型的 ELK 架构图(文字版):

应用服务器 → Filebeat → Logstash → Elasticsearch → Kibana
                ↓
            (缓存层: Redis/Kafka)

为什么要加缓存层?我曾经踩过这个坑。有一次业务高峰期,日志量突然暴涨,Logstash 处理不过来,直接把 Elasticsearch 打挂了。从那以后,我都在 Logstash 前面加一层 Kafka 或者 Redis 做缓冲。说白了,就是给系统加个「泄洪闸」。

注意: 不加缓存层,日志洪峰来临时,你的 ES 集群很可能直接 OOM。这不是危言耸听,我亲眼见过。

日志采集与传输:Filebeat vs Logstash

很多人搞不清楚 Filebeat 和 Logstash 的区别。我简单说:Filebeat 是「搬运工」,Logstash 是「加工厂」。

Filebeat 只负责读日志文件、发出去。它轻量、稳定、不占资源。Logstash 则能做解析、过滤、转换、丰富数据。但 Logstash 吃内存,Java 写的嘛,你懂的。

我的建议是:采集用 Filebeat,处理用 Logstash。分工明确,各司其职。

来看一个 Filebeat 的配置示例:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
    - /var/log/nginx/error.log
  fields:
    service: nginx
    env: production

output.logstash:
  hosts: ["192.168.1.100:5044"]
  loadbalance: true

这里有个细节:loadbalance: true。我建议开启,这样 Filebeat 会轮询多个 Logstash 节点,避免单点故障。嗯,这个配置我是在一次 Logstash 宕机事故后加上的。

再看 Logstash 的配置:

input {
  beats {
    port => 5044
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
  date {
    match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
  }
  mutate {
    remove_field => ["message"]
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "nginx-logs-%{+YYYY.MM.dd}"
  }
}
技巧: Grok 调试是个体力活。我建议先在 Kibana 的 Grok Debugger 里测试正则,确认无误再写到配置里。不然你会在「日志解析失败」的坑里反复横跳。

日志分析与检索技巧

日志都存进去了,怎么查?很多人只会用 Kibana 的搜索框输入关键词,然后翻页翻到怀疑人生。其实 Elasticsearch 的查询语法很强大,掌握几个核心技巧就够了。

1. 精确匹配 vs 全文搜索

默认情况下,Kibana 的搜索是全文搜索。比如你搜 error,它会匹配所有包含 error 的字段。但如果你只想搜 level: error,就得用字段查询:

level: "error"

或者你想搜某个 IP 的访问记录:

client_ip: "192.168.1.1"

我刚开始用的时候,经常搜出一堆无关结果。后来养成习惯,先看字段名,再写查询语句。效率提升不止一倍。

2. 范围查询

查时间范围,别用鼠标点日历。直接写:

@timestamp: [now-1h TO now]

查响应时间超过 5 秒的请求:

response_time: > 5000

这个在排查慢接口时特别好用。我记得有一次线上告警说接口超时,我直接用这个查询把 TOP 10 慢请求揪出来了。

3. 布尔查询

组合条件用 AND、OR、NOT:

level: "error" AND service: "payment"

排除某些干扰项:

level: "error" NOT message: "healthcheck"

为什么要排除 healthcheck?因为健康检查的日志太多了,不排除的话,真正的错误会被淹没。这个坑我踩过,后来学乖了。

4. 聚合分析

Kibana 的 Visualize 功能可以帮你做聚合。比如统计每个服务的错误数:

{
  "size": 0,
  "aggs": {
    "by_service": {
      "terms": {
        "field": "service.keyword",
        "size": 10
      }
    }
  }
}

这个查询返回的是每个服务的错误数量排名。我经常用它来做日报,看看哪个服务今天「表现最差」。

核心要点:
  • 采集用 Filebeat,处理用 Logstash,存储检索用 Elasticsearch,可视化用 Kibana
  • 一定要加缓存层(Kafka/Redis),防止日志洪峰打垮 ES
  • Grok 正则先调试再上线,避免解析失败
  • 检索时多用字段查询和布尔组合,少用全文搜索
  • 聚合分析是排查问题的利器,别只停留在搜索层面

最后说一句:日志系统建好了,不是一劳永逸的。你得定期检查索引大小、清理过期数据、优化查询性能。我每个月都会做一次 ES 集群的健康检查,看看有没有分片分配不均、查询慢、磁盘快满的情况。说白了,运维就是个持续优化的活。

下一章咱们聊聊监控告警,那又是另一片天地了。