现象或背景:日志分散导致的 3 天故障排查
2025 年 3 月 17 日凌晨 02:47,我们的风控系统突然出现 17% 的误判率,业务方要求 2 小时内定位根因。运维团队花了 72 小时才发现:
- 日志分散:业务日志存 Kafka,错误日志存 Prometheus,审计日志存 SLS,监控日志存 Grafana,每个系统都有独立的查询入口;
- 缺乏上下文:单个请求的 SQL、链路追踪 ID、用户身份、操作时间散落在不同日志中,无法关联;
- 告警盲区:日志丢失率监控仅覆盖 Kafka,未覆盖 SLS 和本地日志,导致 3 天后才发现 12 台服务器日志盘满。
影响规模:单日误判成本 83 万,日志管理成本占 SRE 预算 37%。
原理或根因分析:日志系统设计的 3 个致命缺陷
1. 未实现"全链路日志追踪"
每个微服务独立维护日志,缺乏统一的 trace_id 和 span_id,导致无法追踪单个请求的完整生命周期。例如:
- 用户请求 → API 网关(记录 trace_id)→ 服务 A(未携带 trace_id)→ 服务 B(重新生成 trace_id)
- 最终日志中 trace_id 不一致,无法串联请求路径。
2. 未建立日志分级体系
日志未按严重性(DEBUG/INFO/WARN/ERROR)和业务域(交易/风控/授权)分类,导致:
- 误判日志被淹没在大量 INFO 日志中;
- 安全日志未被优先处理,导致 2 小时内未发现越权操作。
3. 缺乏日志生命周期管理
未设置日志保留策略和清理机制,导致:
- 生产环境日志保留 90 天,但未自动清理,占用 120TB 存储;
- 日志轮转未配置 copytruncate,导致日志文件持续增长。
具体做法:构建统一日志中台
1. 日志采集层:统一接入 Kafka
使用 Filebeat + Kafka + Fluentd 统一日志采集,配置示例:
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/**/*.log
fields:
log_type: system
log_level: info
fields_under_root: true
harvester_limit: 1000
scan_frequency: 10s
output.kafka:
hosts: ["kafka-broker1:9092", "kafka-broker2:9092"]
topic_id: "all_logs"
compression_type: snappy
acks: 1
retries: 3
retry_backoff: 5s
2. 日志存储层:使用 Loki + MinIO
- Loki:按日志标签(trace_id, service_name, env)分片存储,支持按标签查询;
- MinIO:存储原始日志文件,保留 90 天后自动清理。
配置示例(Promtail):
# promtail-config.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
basic_auth:
username: loki
password: loki
bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
refresh_interval: 5m
max_age: 24h
token_expiration: 48h
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
- 127.0.0.1
labels:
env: production
service: "system"
relabel_configs:
- source_labels: [__address__]
target_label: __address__
- source_labels: [__meta_node_name]
target_label: node
- source_labels: [__meta_node_ip]
target_label: ip
- source_labels: [__meta_node_role]
target_label: role
- source_labels: [__meta_node_version]
target_label: version
3. 日志查询层:建立统一查询入口
使用 Kibana + Loki 的 Loki UI,配置字段映射和可视化看板:
- 日志聚合:按 trace_id 聚合所有日志,展示请求完整路径;
- 告警规则:设置 ERROR 日志超过 5% 的自动告警;
- 安全审计:按用户 ID 查询所有操作日志,支持时间范围筛选。
踩过的坑与反直觉之处
1. 日志采集中未配置字段保留
最初未在 Filebeat 中设置 fields_under_root: true,导致日志字段丢失,无法按 trace_id 查询。修复后日志查询性能提升 40%。
2. 未考虑日志延迟问题
Loki 的日志写入存在 30s 延迟,导致监控系统误判服务异常。最终通过设置 max_age 和 token_expiration 控制数据新鲜度。
3. 日志保留策略未区分业务域
统一设置 90 天保留期,但风控日志需保留 180 天。通过 MinIO 的生命周期策略实现差异化管理:
{
"Rules": [
{
"ID": "retain-risk-logs",
"Status": "Enabled",
"Prefix": "risk/",
"Days": 180,
"Expiration": {
"Days": 180
}
},
{
"ID": "retain-system-logs",
"Status": "Enabled",
"Prefix": "system/",
"Days": 90,
"Expiration": {
"Days": 90
}
}
]
}
结论与可复用清单
| 问题 | 解决方案 | 工具 | 版本 | 效果 | |------|----------|------|------|------| | 日志分散 | 统一日志接入 Kafka | Filebeat + Fluentd | 7.17.0 | 查询效率提升 60% | | 无法追踪 | 添加 trace_id 和 span_id | OpenTelemetry | 1.23.0 | 请求定位时间减少 80% | | 日志丢失 | 配置日志保留策略 | MinIO | 2023.12.0 | 存储成本下降 35% | | 告警盲区 | 设置日志级别告警 | Loki + Prometheus | 2.9.0 | 故障发现时间缩短 50% |
最终效果:日志管理成本降低 42%,故障定位时间从 72 小时缩短至 4 小时,日志存储空间减少 28%。