ELK 与 Filebeat
组件职责
ELK 由 Elasticsearch、Logstash 和 Kibana 组成。加入 Filebeat 后常写作 ELFK,但工程中仍经常统称 ELK。
| 组件 | 职责 | 不适合承担的职责 |
|---|---|---|
| Filebeat | 在主机或容器边缘读取日志、保存读取状态、批量转发 | 复杂事件关联和重计算 |
| Logstash | 接收、解析、转换、过滤和路由事件 | 长期消息保留 |
| Elasticsearch | 保存可检索日志并执行全文搜索、过滤和聚合 | 事务型业务主库 |
| Kibana | 查询、可视化、Dashboard 和平台管理 | 日志采集与持久化 |
如果日志已经符合统一 Schema、无需复杂处理,Filebeat 也可以直接写 Elasticsearch;需要脱敏、字段转换、多目标路由或复杂解析时,再经过 Logstash。
Filebeat 与 Logback Socket
Logback SocketAppender 把应用进程直接放进远程日志链路。Filebeat 则让应用先写本地文件,由独立 Agent 异步采集。
| 维度 | Logback Socket 直连 | Logback 文件 + Filebeat |
|---|---|---|
| 应用耦合 | 应用依赖远端地址、协议和序列化 | 应用只负责写本地日志 |
| 下游故障 | 可能阻塞、丢弃或占用应用队列 | Filebeat 背压,应用与网络故障隔离更清晰 |
| 读取进度 | 通常由应用内存队列管理 | Registry 持久化文件读取位置 |
| 重启恢复 | 取决于 Appender 实现和配置 | 从已确认位置继续采集 |
| 多语言 | 每种语言分别接入 | 只要能写文件或标准输出即可统一采集 |
| 运维升级 | 随应用依赖和版本发布 | Agent 可独立配置和升级 |
因此 Filebeat 通常更适合作为主机日志采集器。它提供的是至少一次投递:未收到下游确认会重试,所以可能产生重复事件;若日志轮转和删除速度超过采集速度,仍可能丢失。业务侧应控制磁盘保留窗口,下游需要接受幂等或少量重复。
SocketAppender 并非完全不能使用。对低延迟、可接受丢失且不方便落盘的特殊事件,可以配合异步队列使用,但不应让普通业务请求线程直接承受日志平台故障。
应用日志格式
推荐每行一个 JSON 对象,避免用 Grok 猜测自由文本:
{"@timestamp":"2026-08-23T10:30:00.123+08:00","log.level":"INFO","service.name":"order-service","trace.id":"4bf92f3577b34da6a3ce929d0e0e4736","message":"order created","order.id":"A1001"}基础字段至少包括:
@timestamp:事件发生时间,明确时区。log.level、message:日志级别和消息。service.name、service.version、deployment.environment:服务上下文。trace.id、span.id:与链路追踪关联。event.dataset:日志数据集,用于路由和生命周期策略。error.type、error.message、error.stack_trace:异常信息。
密码、Token、身份证号等敏感信息应在进入日志前避免输出;采集侧脱敏只能作为补充防线。
Filebeat 最小配置
使用 filestream 读取 JSON Lines,并发给 Logstash:
filebeat.inputs:
- type: filestream
id: order-service
enabled: true
paths:
- /var/log/apps/order-service/*.json
parsers:
- ndjson:
target: ""
add_error_key: true
overwrite_keys: false
fields_under_root: true
fields:
service.name: order-service
event.dataset: order-service.application
queue.disk:
max_size: 2GB
output.logstash:
hosts: ["logstash-1:5044", "logstash-2:5044"]
loadbalance: true
ssl.enabled: true
ssl.certificate_authorities: ["/etc/filebeat/certs/ca.crt"]磁盘队列增强 Agent 重启和短时下游故障时的缓冲能力,但不能替代容量规划。队列满后仍会向输入传播背压,应保证日志文件不会在恢复前被轮转删除。
Logstash 最小 Pipeline
input {
beats {
port => 5044
ssl_enabled => true
ssl_certificate => "/etc/logstash/certs/server.crt"
ssl_key => "/etc/logstash/certs/server.pkcs8.key"
}
}
filter {
if ![service][name] {
mutate { add_tag => ["missing_service_name"] }
}
mutate { remove_field => ["agent", "ecs", "host"] }
}
output {
if "missing_service_name" in [tags] {
file { path => "/var/lib/logstash/dead-letter/missing-service.json" codec => json_lines }
} else {
elasticsearch {
hosts => ["https://es-1:9200", "https://es-2:9200"]
api_key => "${ELASTIC_API_KEY}"
ssl_enabled => true
ssl_certificate_authorities => ["/etc/logstash/certs/ca.crt"]
data_stream => "true"
data_stream_type => "logs"
data_stream_dataset => "%{[event][dataset]}"
data_stream_namespace => "prod"
}
}
}Logstash 的 Persistent Queue 默认不开启,可在 logstash.yml 中启用:
queue.type: persisted
path.queue: /var/lib/logstash/queue
queue.max_bytes: 8gbPersistent Queue 能吸收短时突发并在 Logstash 异常退出后恢复在途事件,但它位于单个 Logstash 实例,不提供 Kafka 那样的多消费者、集中保留和任意回放能力。
多行异常
Java Stack Trace 必须在采集端合并,否则每一行会成为独立事件。使用 JSON Encoder 将堆栈写进单个 JSON 字段最稳定;处理传统文本时,在 Filebeat filestream 的 parser 中配置 multiline。不要在中心 Logstash 才合并来自多台主机的行,事件交错后已无法可靠还原。
索引与保留策略
日志优先写入 Data Stream,而不是由日期硬编码大量索引。Data Stream 要求事件包含 @timestamp,其后端索引由 Rollover 和生命周期策略管理。
- 按服务或数据集区分 Dataset,不要按 Pod 或实例创建索引。
- 为字段建立受控 Mapping,防止动态字段爆炸。
- 根据检索窗口设置热、温、冷层和删除时间。
- 为高流量与低流量 Dataset 分配不同 Rollover 策略。
- 副本解决节点故障,Snapshot 才用于独立备份与灾难恢复。
可靠性边界
这些机制解决的问题不同,不能相互替代。端到端通常是至少一次而不是恰好一次,监控应覆盖采集延迟、队列占用、解析失败、Logstash 重试与 Elasticsearch 写入拒绝。