单体应用排查问题很简单,日志都写在一个文件里,grep一下基本就能定位原因。可当系统被拆分成几十个微服务,部署在上百台机器或容器上时,日志分散在每个节点的本地磁盘中,一次线上故障可能要登录十几台机器才能拼出完整的调用链路。更麻烦的是,容器重启后日志直接丢失,想事后追查都没有数据。这就是分布式集群必须做日志集中收集的原因:把所有节点的日志统一汇聚到一处,提供集中检索、可视化分析和告警能力。本文将从整体架构、方案选型、具体配置和工程实践四个方面展开。

一、日志集中收集的整体架构与数据流转
无论选择哪套技术栈,日志集中管理系统的数据流转基本都遵循同一条链路:采集、传输、存储、索引、展示。理解这条链路是做方案设计的前提。
第一层是采集端。日志的来源通常有三种形态:一是写在本机文件里的文本日志,二是容器标准输出(比如Docker的json-file驱动、Kubernetes的容器日志),三是应用直接通过网络上报。针对文件形态,一般部署轻量级采集器(如Filebeat、Fluent Bit)驻留在每台节点上,监听文件变化并增量读取;针对容器环境,可以用DaemonSet方式在每台宿主机上跑一个采集器,统一收集节点上所有容器的输出。
第二层是传输与缓冲层。日志产生的速度不稳定,高峰期可能瞬间涌入大量数据,如果采集器直连存储集群,很容易把存储打垮。因此在中间引入消息队列(如Kafka、Redis Stream)做削峰填谷,同时起到解耦作用——下游存储短暂宕机时,日志先堆积在队列里,恢复后再继续消费,不丢数据。
第三层是处理、存储与展示。原始日志往往是半结构化文本,需要经过解析、字段提取(比如从Nginx访问日志中拆出状态码、响应耗时)后再写入存储。存储层负责持久化和索引,展示层提供查询界面和图表看板,再配合告警规则实现异常自动通知。
二、ELK与Loki两套主流方案的对比与选型
目前业界最主流的两套方案是ELK体系(Elasticsearch、Logstash、Kibana,现在常叫Elastic Stack)和Grafana Loki体系,两者设计理念差异很大,选型前必须想清楚。
ELK的核心是Elasticsearch的全文倒排索引。它会对日志的每个字段建立索引,因此查询能力极强,支持任意字段的组合过滤、全文检索和聚合分析,Kibana的可视化功能也很成熟。代价是资源消耗大:索引构建占用大量CPU和内存,磁盘膨胀明显,通常需要单独的ES集群并配备较大内存。适合日志量中等、查询需求复杂、需要频繁做多维分析的场景。
Loki走的是另一条路:只对标签(label)建索引,日志正文压缩存储不索引,查询时先按标签缩小范围,再对正文做类似grep的过滤。这样索引体积极小,部署成本低,单机也能跑,与Prometheus的标签体系天然契合,Grafana里可以直接关联指标和日志。缺点是全文检索性能较弱,如果查询时标签维度设计得不好,扫描范围过大,速度会明显下降。适合标签维度清晰(集群、服务、Pod名等)、以运维排障为主、成本敏感的团队。
一个简单的经验判断:日志量每天在几百GB以下、需要复杂的全文检索和业务分析,选ELK更省心;日志量大、主要按服务维度排障、希望控制成本,Loki更合适。两者也可以混用,比如核心业务日志进ES,海量框架日志进Loki。
三、Filebeat采集配置实战
确定了存储方案后,采集端推荐使用Filebeat,它足够轻量,占用的CPU和内存都很低,对业务进程几乎无影响。下面给出一个采集Nginx日志并输出到Kafka的完整配置。
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
fields:
service: nginx
cluster: prod-shanghai
fields_under_root: true
# 多行合并:Java异常堆栈合并成一条日志
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
output.kafka:
hosts: ["kafka1:9092", "kafka2:9092"]
topic: "app-logs"
required_acks: 1
compression: gzip
# 注册文件记录读取位点,重启后从断点继续
registry_file: /var/lib/filebeat/registry
配置里有几个关键点值得展开。paths支持通配符,可以一次采集目录下所有滚动后的日志文件。fields用于打标签,把服务名、集群名附在每条日志上,后续无论是写入ES还是Loki,都靠这些字段区分来源。multiline配置非常重要,Java应用的一条异常往往对应几十行堆栈,不配置多行合并的话,每行都会被当成独立事件,检索时体验极差。
output部分除了Kafka,还支持直接输出到Elasticsearch、Logstash、Redis等。registry_file记录了每个文件已经读取到的偏移量,这是Filebeat不丢不重读取的关键,生产环境要确保这个文件所在目录的磁盘可靠。如果采集容器日志,可以把type换成container,直接监听/var/log/containers目录下的符号链接。
如果需要更复杂的解析逻辑,可以在中间加一层Logstash或轻量的vector,用Grok表达式把文本日志拆成结构化字段,例如从一条访问日志中提取出client_ip、status、response_time等独立字段,供后续按状态码统计错误率、按耗时做性能分析。
四、日志规范化与工程实践要点
工具只是基础,日志体系好不好用,很大程度上取决于规范做得是否到位。以下几条实践建议来自真实踩坑经验。
第一,统一日志格式,强烈建议输出JSON结构化日志。每个团队自己发明格式,采集端的解析规则会越写越乱。JSON格式自带字段名,采集后无需复杂解析就能直接入索引。同时约定必备字段:timestamp用UTC并明确时区、level统一取值(INFO、WARN、ERROR)、trace_id用于串联一次请求在多个服务间的日志。有了trace_id,排障时输入一个ID就能看到整条链路的日志轨迹,这是微服务环境里最有价值的字段。
第二,控制日志级别和采样率。生产环境默认级别建议INFO起步,DEBUG日志在高并发下可能产生数倍于业务数据的量。对于某些必然大量出现但又必须保留的日志(如健康检查访问日志),可以做采样,只记录百分之一。
第三,设置合理的保留周期与磁盘策略。集中存储最大的隐患是磁盘被打满导致整条链路瘫痪。ES可以通过ILM策略按天滚动索引并自动删除过期数据,Loki的compactor也能按retention配置清理。保留周期按合规要求和排障需要定,一般业务日志保留7到30天即可。
第四,把日志和告警联动起来。日志收集起来不只是给人看的,更应该配置自动检测规则,比如五分钟内ERROR日志数量超过阈值就触发告警通知到值班群。Kibana的Watcher、Grafana的告警规则都支持这类配置,让日志体系从被动查询升级为主动发现问题的监控手段。
总结一下,分布式集群的日志集中收集并不是简单装个软件,而是一项包含采集规范、传输可靠性、存储选型和分析能力在内的系统工程。先统一格式,再选对存储方案,最后把告警串起来,这套体系才能真正发挥价值。