ELK 生态
问题
什么是 ELK Stack?Logstash、Kibana、Beats 分别起什么作用?如何构建完整的日志收集与分析系统?
答案
ELK Stack 概述
ELK 是 Elasticsearch + Logstash + Kibana 的缩写,后来加入 Beats 后又称为 Elastic Stack。
| 组件 | 角色 | 功能 |
|---|---|---|
| Beats | 轻量采集器 | 在目标机器上采集数据,资源占用低 |
| Logstash | 数据处理管道 | 接收、过滤、转换、丰富数据并输出到 ES |
| Elasticsearch | 存储与搜索 | 索引数据、全文搜索、聚合分析 |
| Kibana | 可视化与管理 | 数据探索、Dashboard、告警、APM |
Logstash
Logstash 是服务端数据处理管道,使用 Input → Filter → Output 三阶段架构。
三阶段架构
# logstash.conf
input {
# 从 Beats 接收数据
beats {
port => 5044
}
# 从 Kafka 消费
kafka {
bootstrap_servers => "kafka:9092"
topics => ["app-logs"]
group_id => "logstash-consumer"
codec => json
}
}
filter {
# Grok 解析非结构化日志
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:content}"
}
}
# 解析日期
date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
# GeoIP 地理信息丰富
geoip {
source => "client_ip"
}
# 移除不需要的字段
mutate {
remove_field => ["agent", "ecs", "host"]
}
# 条件过滤
if [level] == "DEBUG" {
drop {}
}
}
output {
# 输出到 Elasticsearch
elasticsearch {
hosts => ["http://es:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
# 使用 ILM 策略
ilm_enabled => true
ilm_rollover_alias => "app-logs"
ilm_policy => "logs-policy"
}
# 错误日志同时发到告警
if [level] == "ERROR" {
http {
url => "https://webhook.example.com/alert"
http_method => "post"
format => "json"
}
}
}
常用 Filter 插件
| 插件 | 用途 | 示例 |
|---|---|---|
| grok | 正则解析非结构化文本 | 解析 Nginx/Apache 日志 |
| json | 解析 JSON 字符串 | 解析应用日志 |
| date | 解析日期字符串 | 统一时间戳 |
| geoip | IP → 地理位置 | 来源地分析 |
| mutate | 字段操作 | 重命名、删除、类型转换 |
| dissect | 分隔符解析(比 grok 快) | 固定格式日志 |
| ruby | 自定义 Ruby 代码 | 复杂逻辑处理 |
Logstash vs Ingest Pipeline
- Logstash:独立进程,功能强大,适合复杂处理、多 Input/Output
- Ingest Pipeline:ES 内置,无需额外部署,适合简单转换
简单日志场景可以用 Beats → ES(Ingest Pipeline),省去 Logstash 的资源消耗。
Beats 家族
Beats 是轻量级数据采集器,用 Go 语言编写,资源占用极低。
| Beat | 采集对象 | 典型场景 |
|---|---|---|
| Filebeat | 日志文件 | 应用日志、系统日志 |
| Metricbeat | 系统/服务指标 | CPU、内存、Docker、MySQL 等 |
| Packetbeat | 网络数据包 | HTTP、MySQL、DNS 协议分析 |
| Heartbeat | 服务健康状态 | Uptime 监控、HTTP/TCP 探测 |
| Auditbeat | 审计数据 | 文件完整性、系统审计日志 |
| Winlogbeat | Windows 事件 | Windows 安全/系统日志 |
Filebeat 配置
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
# 多行合并(Java 异常堆栈)
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
# 添加标签
tags: ["app", "production"]
fields:
env: production
service: user-service
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_kubernetes_metadata: ~
# 输出到 Logstash
output.logstash:
hosts: ["logstash:5044"]
# 或直接输出到 ES(简单场景)
# output.elasticsearch:
# hosts: ["es:9200"]
# pipeline: "app-log-pipeline" # 使用 Ingest Pipeline
Filebeat 工作原理
- Harvester:每个文件一个 goroutine,逐行读取
- Registry:记录每个文件的读取偏移量,重启后从上次位置继续
- 背压处理:当 Output 目标不可用时,自动减慢读取速度
Kibana
Kibana 是 ES 的可视化前端,提供数据探索、Dashboard、告警等功能。
核心功能
| 功能 | 说明 |
|---|---|
| Discover | 日志搜索、过滤、时间范围选择 |
| Dashboard | 可视化看板,组合多个图表 |
| Lens | 拖拽式可视化创建 |
| Canvas | 像素级自定义 Dashboard |
| Alerting | 基于条件的告警规则 |
| APM | 应用性能监控 |
| Maps | 地理信息可视化 |
| Dev Tools | ES Query Console |
| Stack Monitoring | ES 集群监控 |
| Index Management | 索引生命周期管理 |
KQL(Kibana Query Language)
# 基本搜索
level: "ERROR"
# AND 组合
level: "ERROR" and service: "order-service"
# OR 组合
level: "ERROR" or level: "WARN"
# 通配符
message: *timeout*
# 范围
response_time > 1000
# NOT
not level: "DEBUG"
# 嵌套字段
request.method: "POST" and response.status >= 500
索引生命周期管理(ILM)
ILM 自动管理索引的创建、优化和删除。
// 创建 ILM 策略
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50gb",
"max_age": "1d"
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"forcemerge": { "max_num_segments": 1 },
"shrink": { "number_of_shards": 1 }
}
},
"cold": {
"min_age": "30d",
"actions": {
"freeze": {}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
完整日志系统架构
为什么加 Kafka 缓冲层?
| 直接推送 | 经过 Kafka |
|---|---|
| 架构简单 | 削峰填谷,应对日志突增 |
| Logstash 挂了日志丢失 | Kafka 持久化,不丢数据 |
| 无法重放 | 支持消费重放 |
| 单一消费 | 多消费者(ES + Flink 等) |
ES vs 同类方案对比
| 对比项 | Elasticsearch | Splunk | Loki |
|---|---|---|---|
| 开源 | ✅(BSL 许可) | ❌ 商业 | ✅ Apache 2.0 |
| 全文索引 | ✅ 倒排索引 | ✅ 倒排索引 | ❌ 仅标签索引 |
| 存储成本 | 中等 | 高 | 低(不索引日志内容) |
| 查询能力 | 强(Query DSL) | 强(SPL) | 中(LogQL) |
| 适合场景 | 通用搜索与分析 | 企业安全分析 | 云原生日志 |
| 与 K8s 集成 | 一般 | 一般 | 优秀(和 Grafana 一体) |
Loki 的设计理念
Grafana Loki 不对日志内容建索引,只索引标签(label)。查询时通过标签过滤 + grep 搜索内容。存储成本只有 ES 的 1/10,但搜索大量日志时性能较差。
选型建议:
- 需要复杂搜索和分析 → ES/ELK
- 云原生 + 已用 Grafana + 成本敏感 → Loki
- 企业级安全合规 → Splunk
常见面试问题
Q1: ELK 各组件的作用?
答案:
- Elasticsearch:分布式搜索与分析引擎,负责存储、索引和搜索日志数据
- Logstash:服务端数据处理管道,负责数据接收(Input)、转换过滤(Filter)、输出(Output)
- Kibana:可视化界面,提供数据搜索、Dashboard、告警等功能
- Beats:轻量级数据采集器,部署在目标机器上收集各类数据(Filebeat 收集日志、Metricbeat 收集指标等)
Q2: 为什么日志系统中通常在 Beats 和 Logstash 之间加 Kafka?
答案:
- 削峰填谷:日志量有波峰波谷,Kafka 作为缓冲层吸收峰值流量
- 解耦:采集端和处理端解耦,Logstash 挂了不影响日志采集
- 持久化:Kafka 持久化消息,不会因为 Logstash 重启而丢失日志
- 重放能力:可以重新消费历史日志(如修改处理逻辑后重新入 ES)
- 多消费者:日志可以同时给 ES、Flink、数据仓库等多个系统消费
Q3: Filebeat 如何保证日志不丢失和不重复?
答案:
- 不丢失:Filebeat 使用 Registry 文件记录每个日志文件的读取偏移量(offset),重启后从上次位置继续读取。同时支持背压(backpressure),当下游不可用时减慢读取速度
- 不重复:正常情况不会重复。但如果 Filebeat 在发送确认前崩溃,重启后会从上次记录的 offset 重新发送,可能产生少量重复(at-least-once 语义)。需要在 ES 端通过文档 ID 去重实现幂等写入
Q4: 如何管理 ES 中的日志索引?
答案:
使用 ILM(Index Lifecycle Management) 自动管理:
- Hot Phase:写入新数据,使用高性能 SSD,按大小或时间自动 rollover
- Warm Phase:不再写入,force merge 减少 Segment,迁移到普通磁盘
- Cold Phase:低频查询,冻结索引减少内存
- Delete Phase:过期自动删除
配合 Index Template 和 Rollover Alias 实现全自动化管理。
Q5: ES + Loki + Splunk 如何选型?
答案:
| 场景 | 推荐方案 |
|---|---|
| 全文搜索需求强 | Elasticsearch |
| 已有 Grafana 生态 | Loki |
| 成本敏感 | Loki(不索引内容,存储成本低) |
| 企业安全合规 | Splunk |
| 少量日志 + 简单查询 | Loki |
| 大规模日志 + 复杂分析 | Elasticsearch |
| APM + 日志一体 | Elastic APM |