饮墨

子安饮墨馀三斗,留与卿儿作赋来

Fluent Bit 替代 Fluentd:轻量级日志采集 Pipeline 生产部署与调优

痛点

在 Kubernetes 集群规模超过 50 节点后,Fluentd 作为 DaemonSet 部署的日志采集器开始暴露出明显短板:

  • 内存占用高:每个 Fluentd Pod 动辄 300-500MB RSS,在节点资源紧张时与业务容器争抢内存
  • Ruby GC 延迟:Fluentd 基于 Ruby 实现,GC pause 导致日志投递出现毫秒级抖动,高吞吐场景下 backpressure 频繁触发
  • 插件依赖复杂:gem 依赖冲突、版本不兼容问题在升级时频繁出现
  • 冷启动慢:Pod 重启后需要 10-20 秒才能开始正常采集,期间日志丢失

如果你的日志 Pipeline 也面临类似问题,Fluent Bit 是一个值得认真考虑的替代方案。

方案

Fluent Bit 是 CNCF 毕业项目,C 语言编写的轻量级日志处理器。核心优势:

对比项 Fluentd Fluent Bit
语言 Ruby + C 纯 C
内存占用 300-500MB 20-50MB
启动时间 10-20s <1s
吞吐量 ~5000 events/s ~20000 events/s
插件生态 800+ 100+(覆盖主流场景)
适用角色 Aggregator Edge Collector / Aggregator

架构定位:Fluent Bit 作为节点级 Collector(DaemonSet),负责采集、过滤、路由;如果需要复杂聚合逻辑,可以保留 Fluentd 作为中心 Aggregator,形成 Fluent Bit → Fluentd → 后端存储 的分层架构。

实操步骤

第一步:Helm 部署 Fluent Bit DaemonSet

# 添加 Fluent Bit Helm repo
helm repo add fluent https://fluent.github.io/helm-charts
helm repo update

# 安装到 logging namespace
kubectl create namespace logging

helm install fluent-bit fluent/fluent-bit \
  --namespace logging \
  --set resources.requests.cpu=100m \
  --set resources.requests.memory=64Mi \
  --set resources.limits.cpu=200m \
  --set resources.limits.memory=128Mi

第二步:配置 Pipeline(采集 → 过滤 → 输出)

创建自定义 values.yaml

# values-production.yaml
config:
  inputs: |
    [INPUT]
        Name              tail
        Tag               kube.*
        Path              /var/log/containers/*.log
        Parser            cri
        DB                /var/log/fluent-bit/flb_kube.db
        Mem_Buf_Limit     10MB
        Skip_Long_Lines   On
        Refresh_Interval  5

  filters: |
    [FILTER]
        Name                kubernetes
        Match               kube.*
        Kube_Tag_Prefix     kube.var.log.containers.
        Merge_Log           On
        Merge_Log_Key       log_processed
        K8S-Logging.Parser  On
        K8S-Logging.Exclude On
        Buffer_Size         32k

    [FILTER]
        Name    grep
        Match   kube.*
        Exclude log ^$

    [FILTER]
        Name          nest
        Match         kube.*
        Operation     lift
        Nested_under  kubernetes
        Add_prefix    k8s_

  outputs: |
    [OUTPUT]
        Name            es
        Match           kube.*
        Host            elasticsearch.logging.svc.cluster.local
        Port            9200
        Logstash_Format On
        Logstash_Prefix k8s-logs
        Retry_Limit     3
        tls             On
        tls.verify      Off
        Suppress_Type_Name On

    [OUTPUT]
        Name            stdout
        Match           fluent-bit.*
        Format          json_lines

应用配置:

helm upgrade fluent-bit fluent/fluent-bit \
  --namespace logging \
  -f values-production.yaml

第三步:配置 Backpressure 和持久化缓冲

生产环境必须配置 filesystem buffer,防止下游故障时日志丢失:

[SERVICE]
    Flush           1
    Log_Level       info
    Daemon          Off
    Parsers_File    parsers.conf
    HTTP_Server     On
    HTTP_Listen     0.0.0.0
    HTTP_Port       2020
    storage.path    /var/log/fluent-bit/buffer/
    storage.sync    normal
    storage.checksum Off
    storage.max_chunks_up 128

[INPUT]
    Name              tail
    Tag               kube.*
    Path              /var/log/containers/*.log
    Parser            cri
    DB                /var/log/fluent-bit/flb_kube.db
    Mem_Buf_Limit     10MB
    storage.type      filesystem
    Skip_Long_Lines   On

对应 DaemonSet 需要挂载 hostPath 卷:

# 在 Helm values 中添加
extraVolumes:
  - name: fluent-bit-buffer
    hostPath:
      path: /var/log/fluent-bit/buffer
      type: DirectoryOrCreate

extraVolumeMounts:
  - name: fluent-bit-buffer
    mountPath: /var/log/fluent-bit/buffer

第四步:监控 Fluent Bit 自身健康

Fluent Bit 内置 Prometheus metrics endpoint:

# 验证 metrics 暴露
kubectl port-forward -n logging ds/fluent-bit 2020:2020
curl http://localhost:2020/api/v1/metrics/prometheus

关键监控指标:

# Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: fluent-bit
  namespace: logging
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: fluent-bit
  endpoints:
    - port: http
      path: /api/v1/metrics/prometheus
      interval: 15s

核心 PromQL 告警规则:

groups:
  - name: fluent-bit
    rules:
      # 输出重试次数激增 - 说明下游有问题
      - alert: FluentBitOutputRetries
        expr: rate(fluentbit_output_retries_total[5m]) > 10
        for: 5m
        annotations:
          summary: "Fluent Bit output retries high on {{ $labels.pod }}"

      # 输入记录 vs 输出记录差异 - 检测数据丢失
      - alert: FluentBitDataLoss
        expr: >
          (sum(rate(fluentbit_input_records_total[5m])) -
           sum(rate(fluentbit_output_proc_records_total[5m])))
          / sum(rate(fluentbit_input_records_total[5m])) > 0.05
        for: 10m
        annotations:
          summary: "Fluent Bit potential data loss > 5%"

      # 内存缓冲使用率
      - alert: FluentBitMemoryHigh
        expr: fluentbit_input_memchunks{} > 100
        for: 5m
        annotations:
          summary: "Fluent Bit memory chunks high on {{ $labels.pod }}"

避坑

1. Multiline 日志解析丢失(Java Stack Trace)

问题:Java 应用的异常堆栈被拆成多条独立日志。

解决:使用 multiline parser:

[MULTILINE_PARSER]
    Name          java-multiline
    Type          regex
    Flush_timeout 1000
    Rule          "start_state" "/^\d{4}-\d{2}-\d{2}/" "cont"
    Rule          "cont"        "/^\s+at\s|^\s+\.{3}\s|^\s*Caused by:/" "cont"

[INPUT]
    Name              tail
    Tag               kube.*
    Path              /var/log/containers/*java*.log
    multiline.parser  java-multiline

2. 高吞吐下 Mem_Buf_Limit 触发 Pause

问题Mem_Buf_Limit 设置过低(如 5MB),在日志突增时 Input 被暂停,恢复后出现采集间隙。

解决: - 生产环境 Mem_Buf_Limit 建议设为 10MB-50MB - 配合 storage.type filesystem 使用,超出内存限制时落盘而非丢弃 - 同时调整 storage.max_chunks_up 控制内存中活跃 chunk 数量

3. Kubernetes Filter 导致 API Server 压力

问题:大规模集群中,Fluent Bit 的 Kubernetes filter 频繁调用 API Server 获取 Pod metadata,造成 API Server 负载升高。

解决

[FILTER]
    Name                kubernetes
    Match               kube.*
    Kube_URL            https://kubernetes.default.svc:443
    Kube_CA_File        /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    Kube_Token_File     /var/run/secrets/kubernetes.io/serviceaccount/token
    Kube_Meta_Cache_TTL 300s
    Use_Kubelet         On
    Kubelet_Port        10250
    # 关键:启用 Kubelet 本地 API 替代集中式 API Server 查询

设置 Use_Kubelet On 让 Fluent Bit 从本节点 Kubelet 获取 Pod metadata,大幅降低 API Server 压力。Kube_Meta_Cache_TTL 控制缓存时间,300 秒足够覆盖大部分场景。

总结

迁移收益量化(基于 80 节点 K8s 集群实测):

  • 内存占用:从 400MB/节点 → 40MB/节点,整个集群节省 ~28GB 内存
  • CPU 开销:降低 60%,GC pause 消除
  • 日志投递延迟:P99 从 800ms 降至 120ms
  • 冷启动时间:从 15s 降至 <1s

迁移建议

  1. 渐进式替换:先在非生产集群验证,用 stdout output 对比 Fluentd 输出确认数据一致性
  2. 保留 Fluentd 做 Aggregator:如果有复杂路由/聚合需求(如多租户日志分流),可以用 Fluent Bit 采集 + Fluentd 聚合的混合架构
  3. 监控先行:部署前先配好 Prometheus + Grafana Dashboard,上线后对比日志完整性
  4. Buffer 策略:生产环境必须开 filesystem buffer,Mem_Buf_Limit + storage.type filesystem 组合使用

Fluent Bit 已经是 CNCF 毕业项目,被 AWS(FireLens)、Azure、Google Cloud 等作为默认日志采集方案,成熟度不用担心。对于大多数 Kubernetes 日志采集场景,它是 Fluentd 的最佳替代选择。

您还没有登录,请登录后发表评论。