ELK 日志分析平台搭建:Elasticsearch + Logstash + Kibana 实战

ELK Stack(Elasticsearch + Logstash + Kibana)是企业日志分析的黄金标准:Elasticsearch 负责存储与全文检索,Logstash 负责过滤、转换和结构化日志,Kibana 负责搜索、可视化和看板,再加上轻量的 Filebeat 做采集端,就组成了一条从"日志产生"到"可视化分析"的完整链路。

什么时候需要 ELK

如果你的日志目前靠 greptail 就能应付,那暂时不需要 ELK。当出现下面任一情况时,值得引入:多个应用或机器上的日志需要集中搜索;需要按错误类型、耗时、来源做聚合统计;业务侧(运维、客服、研发)要自助查日志,而不是每次都找后端要;要基于日志做告警(比如错误日志激增)。

反之,单机、日志量小、"只要看得到就行"的场景,用 服务器日志监控 或 Loki 这类轻方案更划算。ELK 的代价主要在资源:一套最小集群至少需要 4-8GB 内存,日志量上来后 ES 节点还需要独立规划磁盘 IO。

一、架构设计

日志源 → Filebeat → Logstash → Elasticsearch → Kibana
  |         |           |             |            |
  应用日志  轻量采集   过滤/转换     存储/索引   可视化

二、Docker Compose 部署

version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ports:
      - "9200:9200"
    volumes:
      - es-data:/usr/share/elasticsearch/data

  logstash:
    image: logstash:8.12.0
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    depends_on:
      - elasticsearch

  kibana:
    image: kibana:8.12.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      - elasticsearch

volumes:
  es-data:

资源与初始化注意事项

  • 单节点测试环境给 ES 分配 1-2GB 堆内存(ES_JAVA_OPTS),不要超过物理内存一半;
  • Linux 下需要调高 vm.max_map_count,否则 ES 启动会报 max virtual memory areas vm.max_map_count [65530] is too low,执行 sysctl -w vm.max_map_count=262144
  • 首次启动后 ES 会生成安全证书,Kibana 默认连接 http://elasticsearch:9200,若开启安全认证需要在环境变量里配置账号密码。

三、Logstash 配置

input {
  beats {
    port => 5044
  }
}

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

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "logs-%{+YYYY.MM.dd}"
  }
}

四、Filebeat 配置

filebeat.inputs:
- type: log
  paths:
    - /var/log/nginx/access.log
  fields:
    app: nginx
    env: production

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

验证与排错

配置完成后按下面顺序验证整条链路:

  1. 检查 Filebeat 是否在读取文件:filebeat test output,确认能连上 Logstash 的 5044 端口;
  2. 查看 Logstash 日志确认没有 grok 解析报错:docker logs logstash
  3. 确认索引已生成:curl http://localhost:9200/_cat/indices?v,应能看到 logs-2026.xx.xx 之类的索引;
  4. 在 Kibana 里创建 Index Pattern(如 logs-*),到 Discover 里搜一条已知的访问日志验证字段解析是否正确。

常见坑:grok 模式不匹配导致日志进不了 ES(会看到 _grokparsefailure 标签);时间字段没解析对,导致日志按接收时间而非日志时间排序。先在 Logstash 里用一行真实日志调好 grok,再批量接入。

五、关键功能

功能 说明
全文搜索 快速定位日志
聚合分析 统计错误率、响应时间
可视化 仪表盘展示趋势
告警 基于查询的告警规则
权限 RBAC 多租户

一个真实排错案例

某业务线每天接入约 5GB 访问日志,某天凌晨告警系统发现 502 从平时的 0.2% 冲到 8%。值班人员在 Kibana Discover 里用 status:502 锁定 30 分钟窗口,再用 termsupstream_addr 分组,发现 90% 的 502 都集中在同一台后端 IP。进一步看该节点的响应时间曲线,确认是数据库连接池耗尽导致。整个定位过程不到 10 分钟——如果还靠 grep 逐台机器翻日志,光找文件就得花掉半小时。这类"从现象到根因"的检索路径,正是 ELK 相比普通日志文件最大的价值。更进阶的告警与可视化组合见 Prometheus + Grafana 基础监控。

Kibana 使用要点

Kibana 最常用的三个能力是 Discover(全文检索)、Visualize(图表)和 Dashboard(看板)。一个典型场景:凌晨发现 502 变多,在 Discover 里搜 status:502 配合时间范围缩小窗口,再用 terms 聚合按 upstream 分组,就能定位到是哪台后端在出错。更复杂的查询可以切到 KQL,例如 response_time > 3000 and status >= 500

最佳实践

  • 索引按天分片(logs-%{+YYYY.MM.dd}),配合 ILM(索引生命周期管理)自动淘汰过期索引,避免磁盘被日志占满;
  • 日志量大时优先考虑 Filebeat → Kafka → Logstash 的缓冲架构,防止日志洪峰压垮 Logstash;
  • 敏感字段(手机号、身份证号)在 Logstash 里做脱敏或剔除后再入 ES;
  • 保留期按需求定:审计类日志通常留 180 天,普通访问日志 30 天足够。

常见问题

ES 内存到底怎么给? 官方建议堆内存不超过物理内存一半,且不超过 30-31GB(超过后压缩指针失效、收益下降)。日志型负载大堆不如多分片。

Logstash 吃内存严重怎么办? 先确认 pipeline 里有没有 javaruby 过滤器(这两类最耗内存),并适当调大 pipeline.batch.size 换取吞吐。

单节点够用吗? 单节点适合日志量在每日几 GB 以内的场景;超出后建议拆成三节点 ES,并把 Kibana 与 Logstash 独立部署。

和 Loki 怎么选? Loki 以廉价存储换取查询能力,适合"只要搜得到"的场景;ELK 适合需要聚合分析、复杂查询和图表多样的场景。参见 Loki 日志聚合 对比。

日志里有中文乱码怎么办? 检查两处:一是 Filebeat 的 filebeat.inputs 是否声明 encoding: utf-8,二是 Logstash 输出到 ES 前字段编码是否被转换。多数情况是采集端读文件时用了错误的默认编码。

参考:Elastic 官方文档 — https://www.elastic.co/guide/index.html ;Filebeat 参考 — https://www.elastic.co/guide/en/beats/filebeat/current/index.html