前言
几十台机器各自 tail -f 的日子该结束了。集中式日志的价值:一处搜索全部日志、跨服务排障关联、图表化趋势、留存审计。ELK 是这个领域的经典答案。
一、架构与组件分工
应用/中间件
│ 输出日志文件
▼
Filebeat(轻量采集器, 装在每台机器)
│ 汇聚 / 容错缓冲
▼
[可选] Kafka(削峰 / 解耦 / 丢不起的日志)
│
▼
Logstash(解析: grok 拆字段、过滤、富化)
│
▼
Elasticsearch(索引 + 全文检索)
│
▼
Kibana(查询 / 可视化 / 告警)
组件选型说明:
| 组件 | 职责 | 备注 |
|---|---|---|
| Filebeat | 采集 | Go 写的, 内存占用 ~30MB, 几乎无感 |
| Logstash | 解析转换 | JVM 重(1G+内存); 简单场景可用 Filebeat 自带 processor 替代 |
| Elasticsearch | 存储检索 | JVM 大胃王; 单机实验给 2G 堆即可 |
| Kibana | 界面 | 中规中矩 600MB 内存 |
二、快速搭建(单节点实验版)
# docker-compose.yml
services:
es:
image: elasticsearch:8.14.1
environment:
- discovery.type=single-node
- xpack.security.enabled=false # 实验方便, 生产必开!
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports: ["9200:9200"]
volumes: [esdata:/usr/share/elasticsearch/data]
kibana:
image: kibana:8.14.1
environment:
- ELASTICSEARCH_HOSTS=http://es:9200
ports: ["5601:5601"]
depends_on: [es]
volumes:
esdata:
docker compose up -d
# 浏览器打开 http://IP:5601 —— Kibana 就绪
三、Filebeat:装到每台被采集机
curl -L -o filebeat.rpm https://mirrors.tuna.tsinghua.edu.cn/elasticstack/8.x/yum/...
rpm -ivh filebeat.rpm
/etc/filebeat/filebeat.yml 核心配置:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log*
- /var/log/nginx/error.log*
fields:
service: nginx
env: production
fields_under_root: true
output.elasticsearch: # 简单场景: 直连 ES
hosts: ["http://es-node:9200"]
index: "nginx-%{+yyyy.MM.dd}"
# 简单解析不劳 Logstash, Filebeat 自带模块:
filebeat.modules:
- module: nginx
access: {var.paths: ["/var/log/nginx/access.log*"]}
systemctl enable --now filebeat
# Kibana -> Discover 创建 data view: nginx-* 即可检索!
四、结构化解析(Logstash 或 Ingest Pipeline)
Nginx 日志拆成字段才能按状态码/接口统计。推荐 ES Ingest Pipeline(省掉 Logstash):
PUT _ingest/pipeline/nginx-parse
{
"processors": [
{"grok": {
"field": "message",
"patterns": [
"%{IP:client_ip} - \\S+ \\[%{HTTPDATE:ts}\\] \"%{WORD:method} %{URIPATHPARAM:uri} HTTP/%{NUMBER:http_ver}\" %{NUMBER:status:int} %{NUMBER:bytes:int} \"%{DATA:referer}\" \"%{DATA:ua}\" rt=%{NUMBER:rt:float}"
]
}},
{"date": {"field": "ts", "formats": ["dd/MMM/yyyy:HH:mm:ss Z"]}},
{"remove": {"field": ["ts", "message"]}}
]
}
# filebeat.yml 里挂上 pipeline
output.elasticsearch:
hosts: ["http://es:9200"]
pipeline: nginx-parse
检索验证:
GET nginx-*/_search
{
"query": {"match": {"status": 500}},
"sort": [{"rt": "desc"}]
}
五、Kibana 实用操作
Discover 按时间轴 + 条件过滤(KQL): status:500 and service:nginx
uri:/api/* and rt>1
Visualize 画图: 状态码饼图 / 每分钟 5xx 趋势线 / Top10 慢接口(数据表)
Dashboard 拼大盘: 一屏看完服务健康度
Alerting 告警: "5分钟内 status:500 超过 50 次" → 邮件/webhook
高频 KQL:
message: "connection refused" # 全文
status >= 500 # 数值比较
not service: nginx # 排除
service:(nginx OR mysql) # 多值
六、索引生命周期(ILM):日志的生老病死
日志无限增长会撑爆磁盘,ILM 自动分阶段管理:
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {"actions": {}},
"warm": {"min_age": "1d", "actions": {"shrink": {"number_of_shards": 1}}},
"delete": {"min_age": "30d", "actions": {"delete": {}}}
}
}
}
hot(当天,可查询)→ warm(1天后收缩副本降配)→ delete(30天删除)。任何 ELK 上线都必须配 ILM,这是磁盘的保命符。
七、规模化的中间形态
< 10 GB/天: Filebeat → ES 直连(本文方案)
10-100 GB/天: Filebeat → Logstash → ES(解析富化)
> 100 GB/天: Filebeat → Kafka → Logstash 集群 → ES 集群
Kafka 层的价值:削峰(日志洪峰不冲垮 ES)、缓冲(ES 故障时日志不丢)、多消费(同时给实时告警和离线数仓)。
八、替代方案速览
| 方案 | 特点 | 适合 |
|---|---|---|
| ELK | 功能全, 生态最广, 资源吃得多 | 全文检索刚需、复杂分析 |
| Loki + Grafana | 只索引标签不索引全文, 便宜 10 倍 | 日志量随查询少的团队(云原生新宠) |
| ClickHouse | 列存 SQL 分析, 极快 | 结构化日志分析为主 |
| 云托管 | 阿里云 SLS / 腾讯云 CLS | 不想自运维 |
我的建议:中小团队直接 Loki(与 Grafana 监控同一面板),除非你重度依赖全文检索。
九、常见坑
| 现象 | 原因 |
|---|---|
| Filebeat 收不到日志 | 权限(nginx 日属 root);paths 通配写错 |
| ES 起不来 | vm.max_map_count=262144(sysctl) |
| Kibana 无数据 | data view 的 index pattern 没建/时间范围不对 |
| 磁盘水位锁只读 | _disk watermark 触发 → 清索引 + 扩容;先配 ILM 预防 |
| 日志乱序/丢失 | 加 Kafka 层;确认 filebeat registry 正常推进 |
小结
| 层 | 组件 | 核心配置 |
|---|---|---|
| 采集 | Filebeat | inputs.paths + fields |
| 解析 | Ingest/Logstash | grok 拆字段 + date 时间 |
| 存储 | ES | 索引模板 + ILM 生命周期 |
| 使用 | Kibana | Discover KQL + Dashboard + Alerting |
本文是「云原生」系列第 11 篇。