第三章 日志采集与处理:日志标准化、Fluentd/Fluent Bit 部署、日志采集 Pipeline 设计

日志这东西,说起来简单,做起来全是坑。我见过太多团队,业务跑得好好的,一出问题就抓瞎——日志散落在各个服务器上,格式五花八门,想查个东西得 ssh 到每台机器上 grep。嗯,这显然不是云原生该有的样子。

这一章,我们就来聊聊怎么把日志这件事做规范、做自动、做可靠。说白了,就是让日志真正成为可观测性的基石,而不是一堆没人看的垃圾文件。

3.1 日志标准化:从源头解决问题

我个人习惯,在搭建日志体系之前,先定标准。为什么?因为日志采集和处理最头疼的问题,就是格式不统一。你想想看,Java 应用打的是 JSON,Nginx 打的是自定义格式,数据库日志又是另一套——采集端要写一堆解析规则,维护成本极高。

标准化的核心原则:

  • 结构化:所有日志必须是 JSON 格式。别再用纯文本了,解析起来太痛苦。
  • 字段统一:时间戳、日志级别、服务名、TraceID、消息体,这些字段每个日志都必须有。
  • 时间戳规范:统一使用 ISO 8601 格式,带时区信息。比如 2025-01-15T10:30:00.123+08:00
  • 级别明确:只允许 DEBUG、INFO、WARN、ERROR、FATAL 这五个级别,别自己发明。

一个标准日志示例:

{
  "timestamp": "2025-01-15T10:30:00.123+08:00",
  "level": "ERROR",
  "service": "order-service",
  "trace_id": "abc123def456",
  "span_id": "span001",
  "message": "数据库连接超时",
  "stack_trace": "com.example.dao.DbException: ...",
  "extra": {
    "user_id": "9527",
    "order_id": "ORD20250115001"
  }
}

我在项目中遇到过,有些团队觉得 JSON 日志太大,占用磁盘空间。其实这是个误区。日志压缩后,JSON 和纯文本的体积差距微乎其微。而且,JSON 带来的解析效率和可读性提升,远远超过那点存储成本。

3.2 Fluentd 与 Fluent Bit:选谁?怎么搭?

说到日志采集器,Fluentd 和 Fluent Bit 是绕不开的两个工具。很多人问我:「到底该用哪个?」我的回答是:看场景。

Fluentd 和 Fluent Bit 的对比:

特性 Fluentd Fluent Bit
语言 Ruby + C C
内存占用 ~60MB ~650KB
插件生态 极其丰富(1000+) 丰富(~150)
吞吐量 中等
适用场景 复杂路由、数据转换 边缘采集、轻量部署

我个人习惯的部署模式是:Fluent Bit 做采集端,Fluentd 做聚合端。说白了,就是让 Fluent Bit 跑在每台机器或每个 Pod 里,负责轻量采集和简单过滤;然后把数据发给中心的 Fluentd 集群,由 Fluentd 做复杂的路由、转换和输出。

部署建议:

  • 在 Kubernetes 中,Fluent Bit 以 DaemonSet 方式部署,每个节点一个 Pod。
  • Fluentd 以 Deployment 方式部署,根据日志量调整副本数。
  • 两者之间用 Forward 协议通信,支持负载均衡和故障转移。

3.3 日志采集 Pipeline 设计

Pipeline 这个词听起来高大上,其实就是「数据流」。日志从产生到存储,中间经过哪些环节,每个环节做什么事,这就是 Pipeline 要解决的问题。

一个典型的日志 Pipeline 包含四个阶段:

  1. 采集(Input):从文件、标准输出、系统日志等源头读取日志。
  2. 解析(Parser):把非结构化日志转成结构化数据。
  3. 过滤(Filter):丢弃无用日志、添加缺失字段、修改日志级别。
  4. 输出(Output):写入 Elasticsearch、Kafka、S3 等目标。

我曾经踩过一个坑:把所有日志一股脑全送到 Elasticsearch,结果磁盘直接爆了。后来才意识到,过滤阶段有多重要。你想想看,DEBUG 日志在开发环境有用,到了生产环境就是噪音。所以,Pipeline 里一定要加过滤规则。

一个完整的 Fluent Bit Pipeline 配置示例:

[SERVICE]
    flush           1
    log_level       info
    parsers_file    parsers.conf

[INPUT]
    name            tail
    path            /var/log/containers/*.log
    tag             kube.*
    parser          docker
    refresh_interval 5

[FILTER]
    name            grep
    match           kube.*
    regex           log ^(?=.*ERROR|.*WARN)

[FILTER]
    name            modify
    match           kube.*
    add             cluster production
    rename          log message

[OUTPUT]
    name            forward
    match           kube.*
    host            fluentd.observability.svc
    port            24224

这个配置做了几件事:

  • 从容器日志文件采集,每 5 秒刷新一次。
  • 只保留 ERROR 和 WARN 级别的日志(生产环境建议这么做)。
  • 添加一个 cluster 字段,方便区分环境。
  • log 字段重命名为 message,统一字段名。
  • 最后发给 Fluentd 集群做进一步处理。

注意: 过滤规则要谨慎。我曾经见过有人把 INFO 日志全丢了,结果排查问题时发现关键信息就在 INFO 里。建议至少保留 WARN 及以上级别,INFO 级别按需保留。

3.4 避坑指南:日志采集的常见问题

做日志采集这么多年,我总结了几条血泪教训:

  • 不要用 hostPath 挂载日志目录:在 Kubernetes 里,用 hostPath 会导致日志采集和 Pod 生命周期耦合。建议用 emptyDir 或者 sidecar 模式。
  • 注意日志轮转:应用自己会做日志轮转,Fluent Bit 也要配置好 rotate_wait,防止文件被删了还在读。
  • 控制日志速率:有些应用在出错时会疯狂打日志,瞬间把采集器打挂。加个 throttle 过滤器,限制每秒最多处理多少条。
  • 监控采集器本身:Fluent Bit 挂了怎么办?它的日志也要采集,形成闭环监控。

嗯,这一章的内容差不多就这些。日志标准化是基础,Fluentd/Fluent Bit 是工具,Pipeline 是架构。三者结合起来,才能搭建一个可靠、高效的日志采集体系。下一章,我们会聊聊日志的存储和检索,到时候再细说 Elasticsearch 的那些坑。