前一阵我们把一套微服务从旧环境迁到云上的单节点 K8s 集群,服务起来了,Pod 也全绿,压测时才发现一个很尴尬的问题:日志散落在几十个 Pod 里,排障只能靠kubectl logs逐个翻,grep 完全失效。那段时间刚好要用 JMeter 做高并发验证,每次定位一个报错都要先花十分钟找日志,比业务问题本身还耽误事。后来我决定把 Fluent-Bit 日志采集正式接进来,目标是开箱即用、不拖性能后腿,这套东西从选型到落地压测跑完,整理出不少值得记录的细节。
如果你也在做微服务日志采集,或者正准备在 K8s 环境里搭一套日志管道,这篇文章应该有参考价值。下面所有配置都是我实际在环境里跑过的,直接搬走改一改就能用。
1. 日志散落各地之后:我才决定给微服务认真配一套采集管道
1.1 微服务日志到底难在哪
很多人觉得日志采集就是把文件读走送进 Elasticsearch,哪有那么复杂。真在微服务环境里跑过的人会明白,坑全藏在细节里。
先说日志来源。K8s 里每个 Pod 的容器标准输出默认会被 kubelet 写到宿主机,路径通常是/var/log/containers/<pod>_<namespace>_<container>-<containerId>.log,同一个 Pod 里如果有多容器,日志会按容器分别落盘。微服务一拆,服务数量轻松上几十个,光是要把这些文件全部识别出来,并且区分好“这条日志属于哪个服务”,就是第一个坎。
再说日志格式。业务团队各自为政,有的服务打 JSON,有的打纯文本,有的居然把异常堆栈一行一条打。日志采集器如果不能在源头做解析和规范化,数据送到 Elasticsearch 之后还得靠 Logstash 二次加工,链路长了,出问题的概率也成倍上升。
然后是性能。压测期间日志产出量是平时的好几倍,采集器如果内存控制不好,直接把被采集的 Pod 拖挂,业务影响就大了。所以日志采集必须轻量,不能在业务节点上占太多资源。
1.2 我想要的开箱即用其实是一组明确需求
这次梳理下来,我对采集管道的要求其实就四条:
- 部署简单,K8s 环境里一套 DaemonSet 就能覆盖全部节点;
- 支持按微服务维度区分日志,索引可以动态切分;
- 能够处理多行日志、JSON 日志、时间戳乱序这些常见脏数据;
- 压测高峰时不能把业务进程的资源挤占掉,内存要控得住。
这四条看着朴素,实际选型时能全部满足的工具并不多。
2. 选型对比:Fluent-Bit 赢了 Filebeat 和 Promtail 的地方
2.1 三个主流采集器的横向对比
我实际对比过 Filebeat、Fluentd、Promtail 和 Fluent-Bit。Fluentd 和 Filebeat 名气大,Promtail 在 Loki 生态里很流行,Fluent-Bit 相对低调,但它的定位非常精准:轻量级日志处理器。
| 对比项 | Fluent-Bit | Filebeat | Fluentd | Promtail |
|---|---|---|---|---|
| 运行时内存 | 10-50MB 左右 | 30-100MB 左右 | 200MB 起,常到 1GB+ | 30-100MB 左右 |
| 核心语言 | C | Go | Ruby | Go |
| 输入插件丰富度 | 覆盖文件、系统、网络、K8s 等 | 文件为主,其余靠 module | 非常丰富 | 面向 Loki/Promtail 生态 |
| 多行日志支持 | 原生 Multiline Parser | 需要配置 multiline 规则 | 支持 | 支持 |
| K8s 元数据自动注入 | 内置 Kubernetes Filter | 需要配置 add_kubernetes_metadata | 需要额外插件 | 原生支持 |
| 输出生态 | ES、Kafka、S3、ClickHouse、HTTP 等 | ES、Logstash、Kafka 等 | 非常丰富 | 主要面向 Loki |
| 配置复杂度 | 低,单一配置文件 | 中 | 高 | 低 |
Filebeat 的问题在于它对多行日志的处理比较笨重,而且和 Elasticsearch 强绑定,想同时往 Kafka 或者 S3 写一份时不太顺手。Fluentd 性能没问题,但内存开销太大,动辄几百兆,放到业务节点上一台一个采集器,资源浪费很明显。Promtail 和 Loki 绑定,如果日志后端不是 Loki,价值打了折扣。
2.2 为什么是 Fluent-Bit
Fluent-Bit 是 Fluentd 生态里的轻量级兄弟,但它不是 Fluentd 的简化版,而是专门为采集端设计的。它用 C 语言写,启动常驻内存普遍在几十兆以内,CPU 占用也很低,这在压测环境里非常关键——不会因为日志采集本身把业务 Pod 拖垮。
另外它的插件生态足够覆盖我们的场景:Tail 读文件、Kubernetes Filter 自动打标签、Elasticsearch Output 批量写入,全程不需要额外部署 Logstash。它还自带 HTTP 监控接口,可以输出 Prometheus 格式指标,方便对接监控告警。对一套要长期维护的微服务环境来说,这种“够用且不臃肿”的特性反而最实用。
我当时的判断是:日志采集端不需要“大而全”,只需要“小而稳”。Fluent-Bit 完美踩在这个需求点上。
3. 部署落地:从 DaemonSet 到离线 RPM 的完整路径
3.1 为什么用 DaemonSet 而不是 Sidecar
日志采集在 K8s 里有两种主流部署方式,一种是每个业务 Pod 旁边塞一个 Sidecar 容器专门收日志,另一种是每个节点上跑一个 DaemonSet 采集器统一收宿主机上的容器日志文件。
Sidecar 的方式隔离性好,但资源开销太大——每多一个应用副本就多一个采集器,几十个服务几百个副本,光采集器就吃掉大量内存。DaemonSet 的方式是每台节点只跑一个 Fluent-Bit,所有容器日志统一收,资源利用率最高,运维也简单。
我们在单节点 K8s 环境里就是直接一个 DaemonSet 搞定,业务 Pod 完全不需要感知日志采集的存在。
3.2 核心部署配置
Fluent-Bit 官方提供了 Helm Chart,但我建议新手先别急着用 Helm,手写一遍 DaemonSet 配置能帮你理解每个挂载点是干什么的。下面是我实际用的精简版:
apiVersion: apps/v1 kind: DaemonSet metadata: name: fluent-bit namespace: logging spec: selector: matchLabels: app: fluent-bit template: metadata: labels: app: fluent-bit spec: serviceAccountName: fluent-bit containers: - name: fluent-bit image: fluent/fluent-bit:2.1.10 imagePullPolicy: IfNotPresent resources: requests: memory: 50Mi cpu: 100m limits: memory: 200Mi cpu: 500m volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true - name: fluent-bit-config mountPath: /fluent-bit/etc/ ports: - name: metrics containerPort: 2020 volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers - name: fluent-bit-config configMap: name: fluent-bit-config几个关键点需要注意:
varlog挂载整宿主机/var/log,主要是为了读/var/log/containers下 kubelet 生成的容器日志软链接;varlibdockercontainers挂载 Docker 的实际日志目录,因为软链接最终指向这里,Flunet-Bit 需要同时能看到真实路径才能正确 record 文件位置。
资源限制我给的是 200Mi 上限,日常跑下来实际占用大概在 50-80Mi 左右,压测高峰也没有超过 150Mi,这个量级对业务节点压力很小。
ServiceAccount 需要有读取 Pod 信息权限,因为 Kubernetes Filter 要靠 API 获取 Pod 的 labels、annotations 来给日志打标:
apiVersion: v1 kind: ServiceAccount metadata: name: fluent-bit namespace: logging --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: fluent-bit-read rules: - apiGroups: [""] resources: - pods verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: fluent-bit-read roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: fluent-bit-read subjects: - kind: ServiceAccount name: fluent-bit namespace: logging3.3 离线环境下的安装办法
我这次碰到的环境里有一台 Kylin Linux Advanced Server V10 ARM64 服务器,属于内网环境,没法直接访问外网拉取 RPM 包。Fluent-Bit 官网虽然没有直接提供 Kylin 专属源,但提供了通用的 Linux 二进制包和通过dnf install td-agent-bit的方式安装。对于完全离线的 ARM64 环境,我推荐一个最稳的办法:
找一台和目标机器相同 CPU 架构、相同操作系统版本、并且能联网的机器,用包管理器把 Fluent-Bit 及其依赖全部下载下来:
# 在能联网的同架构机器上执行 sudo dnf install -y dnf-plugins-core sudo dnf config-manager --add-repo https://packages.fluentbit.io/fluentbit/repo/centos/7/aarch64/ sudo dnf install -y --downloadonly --destdir=/tmp/fluentbit-packages fluent-bit # 将 /tmp/fluentbit-packages 打包拷贝到内网机器 tar czvf fluentbit-packages.tar.gz -C /tmp fluentbit-packages # 在内网目标机器上执行离线安装 tar xzvf fluentbit-packages.tar.gz sudo rpm -Uvh /tmp/fluentbit-packages/*.rpm注意 RPM 安装时要用rpm -Uvh而不是rpm -ivh,因为如果目标系统已经有部分依赖库的低版本,-U会做升级处理,-i可能报 already installed 或版本冲突。
我在 ARM64 机器上实际装完发现,Fluent-Bit 对 glibc 版本比较敏感,如果目标机器系统太老,安装后执行fluent-bit -V会报versionGLIBC_2.28' not found` 这类错误。解决办法不是强行换发行版,而是从源代码在目标机器上重新编译,或者找与该系统匹配的旧版本 Fluent-Bit RPM 包。这个坑一般的安装文档不会写,离线部署时很容易卡住。
3.4 部署后的健康检查
装完之后先别急着配输出,用命令行验证一下采集是否正常:
fluent-bit -i dummy -o stdout -f 1能正常打印 dummy 日志说明进程本身没毛病。正式启动后看容器的启动日志:
kubectl -n logging logs -l app=fluent-bit --tail=50看到类似[info] [output:es:es.0] elasticsearch server is up这条,说明到 Elasticsearch 的连接也通了。如果报 TLS 或者认证错误,优先检查输出端的凭证配置,别一上来就怀疑网络。
4. 开箱即用并不存在:核心配置逐段拆解
4.1 SERVICE 段的几个容易被忽略的参数
Fluent-Bit 的主配置是/fluent-bit/etc/fluent-bit.conf或者我们挂载的 ConfigMap,它主要由[SERVICE]、[INPUT]、[FILTER]、[OUTPUT]四种段落组成。先看我最常用的 SERVICE 段:
[SERVICE] Flush 5 Daemon Off Log_Level info Parsers_File parsers.conf HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 Health_Check OnFlush的含义不是“5 秒刷一次日志”,而是“每隔 5 秒检查一次是否有可以刷出的数据”,实际上 elasticsearch output 自己有批量聚合,内部会按time_span和字节数双重维度决定什么时候真正发数据。这个参数不要设太小,否则 CPU 换不回来多少实时性;设太大又会增加日志从产生到可搜索的时间,压测时你可以从监控里对比延迟。
HTTP_Server On和HTTP_Port 2020是必开项,有了它才能通过curl http://localhost:2020/api/v1/metrics/prometheus看到采集器的内部指标,后面调优全靠它。
4.2 tail 输入段:尾部文件读取的核心
微服务日志主要来自容器标准输出文件,用tail插件来读。它和 Linux 的tail -f类似,但多了文件位置记录、文件轮转追踪、断点续读这些能力。
[INPUT] Name tail Path /var/log/containers/*.log Path_Key filepath Tag kube.* Refresh_Interval 10 Mem_Buf_Limit 5MB Skip_Long_Lines On DB /var/log/flb_kube.db Buffer_Chunk_Size 256KB Buffer_Max_Size 1MBPath匹配所有容器日志文件,Tag统一设置成kube.*前缀,配合 Kubernetes Filter 使用。Refresh_Interval 10表示每 10 秒扫一次文件系统,发现新文件或文件轮转。Mem_Buf_Limit 5MB控制每个文件读取的内存缓冲上限,超过这个值 Fluent-Bit 会暂停读取,避免内存被大文件日志拖爆,它不直接丢数据,但你要知道日志可能因此延迟。
Skip_Long_Lines On很实用,有些业务日志会有单行超过 1MB 的情况,默认 tail 会跳过超长行不做处理,防止内存被打满。
DB参数一定要配置,最好放到宿主机持久化路径上。没有它,Fluent-Bit 重启后会重新读取所有日志文件,造成大量重复数据。有它在,重启后能直接从上次读取的位置续传。
4.3 parser:多行日志和 JSON 日志解析
数据进到 Fluent-Bit 后只是原始字符串,要在解析层把它转换成结构化的字段。Fluent-Bit 的 Parsers 文件默认路径是/fluent-bit/etc/parsers.conf,里面可以定义多套解析规则。
JSON 日志最省事,直接用内置的jsonparser:
[PARSER] Name json Format jsonJava 异常堆栈这种多行日志,用普通的单行 parser 会把一条异常拆成几十条,严重污染日志检索。Fluent-Bit 1.8 以上版本支持多行解析,在 parsers.conf 里定义:
[MULTILINE_PARSER] name multiline-java type regex flush_timeout 1000 rules | start_state /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/ start_state /^\[ERROR\]/ cont_state /^(\s+at .*)|^(\s+\.\.\. \d+ more)$/规则的核心逻辑是:当某一行匹配start_state规则时,开启一条多行日志的积累;后续行只要匹配cont_state规则,就继续追加到当前这条日志里;当flush_timeout时间到了还没等到下一行,就把积攒的日志作为一个整体记录输出。
这个配置是我踩了多次坑才调对的。一开始只写了时间戳作为起始规则,结果Caused by:这一行没有带时间戳,被当成新一条日志拆开了。后来把^\[ERROR\]也加进起始规则,才把完整异常栈收拢成一条。
4.4 Kubernetes Filter:自动打标签
在 K8s 环境里部署 Fluent-Bit,Kubernetes Filter 几乎是必配项。它的作用是解析 Tail 读到的文件名,提取出 Pod 名称、容器名、命名空间、labels 等信息,然后附加到每条日志记录里。
[FILTER] Name kubernetes Match kube.* Kube_URL https://kubernetes.default.svc.cluster.local:443 Kube_Tag_Prefix kube.var.log.containers. Merge_Log On Merge_Log_Key log_processed K8S-Logging.Parser On K8S-Logging.Exclude On Labels On Annotations OffKube_Tag_Prefix要从 tag 里剥离掉kube.var.log.containers.前缀,因为容器日志文件的 tag 格式是kube.var.log.containers.<pod>_<namespace>_<container>-<containerId>.log,去掉前缀后才能正确解析出 Pod 名。
Merge_Log On很关键——它会把原本是 JSON 的日志内容合并成结构化字段,比如一条业务日志本身就是{"user_id": 123, "action": "login"},开启后会自动展开成独立的user_id和action字段,而不是整条塞进 log 字段里。Merge_Log_Key log_processed意味着解析出来的字段会放在log_processed子对象下,避免和已有的字段冲突。
Annotations Off我故意关掉,因为大部分情况不需要 annotations,关掉能少写不少冗余数据,ES 存储也能省一点。
4.5 Output 输出到 Elasticsearch:动态索引
最后是输出端。我们的日志后端是 Elasticsearch,Output 段如下:
[OUTPUT] Name es Match * Host elasticsearch-master.logging.svc.cluster.local Port 9200 Index fluent-bit-${HOSTNAME} Logstash_Format On Logstash_Prefix ms-logs Logstash_DateFormat %Y.%m.%d Type _doc Time_Key @timestamp Time_Key_Nanos Off Retry_Limit False Bulk_Max_Size 4MLogstash_Format On配合Logstash_Prefix ms-logs和Logstash_DateFormat %Y.%m.%d,生成的索引名实际是ms-logs-2024.01.15。Time_Key @timestamp告诉 Fluent-Bit 把时间字段写到@timestamp里,这样 Kibana 能直接识别成时间字段。
Retry_Limit False表示无限重试,不丢数据优先。这里要权衡,如果 ES 宕机,Fluent-Bit 会一直积压等待,所以对宿主机磁盘要有容量保护,否则重试期间磁盘会被缓存日志塞满。
Bulk_Max_Size 4M是批量写入阈值,达到 4MB 就发一批。压测场景下日志产出快,这个值设小一点能让数据更快到 ES,设太大则延迟变长。我实测 4M 是延迟和吞吐的较好平衡点。
5. 多服务日志的“身份识别”:Tag、Label 与 record_modifier 的组合
5.1 先想清楚日志的“服务名”从哪来
在一套微服务链路里,同一个命名空间可能跑着 gateway、user-service、order-service、payment-service 四个服务。日志采集时最核心的问题是:一条日志进来,我怎么知道它来自哪个服务?
Fluent-Bit 的 Kubernetes Filter 会从 Pod 自动读取 labels,其中最常见的就是app标签。如果微服务的 Deployment 里打了app: user-service,那么每条用户服务的日志都会自动带上kubernetes.labels.app = user-service这个字段。
但这里有个团队协作问题:很多微服务项目的 labels 打得很随意,有的叫app,有的叫app.kubernetes.io/name,有的直接用name。在部署 Fluent-Bit 之前,建议先统一规范:所有服务 Deployment 必须包含app: <服务名>这个 label。这个规范定好之后,日志识别和 ES 索引切分都会顺畅很多。
5.2 用 record_modifier 给日志补充业务标识
光靠 K8s 的 label 还是不够的。我们微服务里有的服务自己会打印requestId,有的服务会打印userId,但这些业务字段只存在于日志正文里。为了方便后续检索和告警,我会用 record_modifier 过滤器把一些常用字段提到日志顶层:
[FILTER] Name record_modifier Match * Record service_name ${kubernetes['labels']['app']} Record node_name ${HOSTNAME} Remove_key caas_port${kubernetes['labels']['app']}这种变量会动态取当前日志记录上的字段值。加完这条,每条日志都会带service_name,即使日志正文格式变了,检索也能统一根据 service_name 来过滤。
Remove_key caas_port用来清理一些完全不需要的字段。日志数据里很多字段是采集器带出来的运行时信息,如果对业务检索没用,建议在源头删掉,ES 存储和查询性能都能受益。
5.3 按服务拆分索引的好处
如果所有微服务日志都写进同一个索引,随着服务数量增长,索引会迅速膨胀,Kibana 检索性能和 ES 分片管理都会变差。我建议按服务拆分索引,Fluent-Bit 的 ES Output 支持用变量动态生成索引名:
[OUTPUT] Name es Match * Host elasticsearch-master.logging.svc.cluster.local Port 9200 Index ms-logs-${service_name}-%Y-%m-%d当 record_modifier 给日志打上service_name之后,user-service 的日志就写进ms-logs-user-service-2024-01-15,order-service 的日志写进ms-logs-order-service-2024-01-15。这样做索引生命周期管理(ILM)非常方便,某些不重要的服务日志保留 7 天,核心交易日志保留 30 天,可以直接对索引前缀设策略。
6. 从压测现场挖出的三个坑
6.1 Java 异常堆栈被拆成几十条
压测刚开始,我们让开发在测试环境手动触发一次异常,结果 Kibana 里一查,一条异常变成了三四十条记录,每条只有一行。排查过程是这样的:先看原始日志文件,tail -f显示文件里明明是一个完整堆栈;再看 Fluent-Bit 解析后的记录,发现问题出在解析规则。
我最初的多行 parser 只写了时间戳作为起始规则,而 Java 异常堆栈的Caused by:和at com.xxx.xxx这些行不带时间戳,Fluent-Bit 就把它们当成新的独立日志行处理了。
修复方案是调整 Parser 的起始规则,让at xxx这类栈帧行不进新组。最后我用了三组规则:以时间戳开头算新日志,以[ERROR]开头算新日志,以Caused by:开头算新日志,其余缩进行全部归入当前多行日志。配置改完后,一条异常就是一个完整记录了。
6.2 时间戳错乱:日志“迟到”其实是时区问题
压测到一半,测试在 Kibana 里反馈:日志时间比实际时间慢了 8 小时。查遍 Fluent-Bit 配置没发现时区设置,最后才发现问题出在容器日志的原始时间戳上。
容器标准输出日志的每一行都会由 Docket 加前缀,类似2024-01-15T10:30:00.123456789Z,这部分被 Parser 解析成采集时间没问题。但问题是我输出的日志索引按%Y-%m-%d切分,而Logstash_DateFormat用的是 UTC 时间。压测时是北京时间下午 14 点,UTC 还是早上 6 点,所以当天前半天的日志全被写进前一天的索引里。
解决方式:在 Output 端设置Time_Key的同时,通过记录处理把本地时区换算加进去,或者直接在 Elasticsearch 的 ILM 里把索引名的时间容忍度放宽。更简单的做法是,让 Fluent-Bit 在解析日志时使用你希望展示的时区来生成时间字段,解析规则里支持Time_Format和时区偏移,我最终在 parser 里加了time_offset +08:00解决。
6.3 流量高峰时日志延迟暴涨
JMeter 压到高并发时,我们监控 Elasticsearch 写入延迟明显上升,部分索引出现黄色健康状态。一开始怀疑 ES 不行,后来看 Fluent-Bit 的 HTTP 指标发现,tail插件的内存缓冲已经堆满,Fluent-Bit 自动暂停读取容器日志文件,日志产出和采集之间出现了一条看不见的“蓄水池水闸”降下。
这个坑的本质是Mem_Buf_Limit设太小了。我原来给每个文件设了 5MB,单体量小时没问题,高并发时所有服务日志同时激增,单文件缓冲 5MB 根本装不下,导致暂停读取和频繁重读。调参思路:
- 把
Mem_Buf_Limit从 5MB 提到 10MB; - 给 [SERVICE] 段开启
storage.path和storage.total_limit_size,让溢出数据落盘而不是直接丢; - 优化 ES 端的
Bulk_Max_Size,从 4M 调到 8M,减少批量次数。
这个坑给我们的教训是:一切参数都要按峰值流量来设,按平均流量设参数在高并发场景基本都会翻车。
7. 性能预估与瓶颈调节:多少日志量该分多少个采集器
7.1 先算清楚你的日志量级
日志采集系统设计不能靠感觉。我建议上线前先做一个容量预估,公式其实很简单:
单日日志总量 = 单服务平均每秒日志字节数 × 服务实例数 × 86400 秒
假设 user-service 有 3 个实例,每个实例每秒产生约 20KB 日志,那么单服务一天的日志量就是:
20KB × 3 × 86400 ≈ 5.18GB
几十个服务全部加起来,一天几百 GB 很常见。如果按 500GB/天算,平均写入速率约 5.8MB/s,峰值通常是平均的 3-5 倍,也就是 17-29MB/s。这个速率就是设计采集管道和 ES 写入能力的基础。
7.2 用监控指标判断瓶颈
Fluent-Bit 本身不慢,真正卡脖子的是下游。我压测时主要盯这几类指标:
fluentbit_input_bytes_total:累计读入字节数,看增速是否和日志产出匹配;fluentbit_input_records_total:累计记录条数,配合日志格式判断单条日志大小;fluentbit_output_proc_records_total:实际成功发往 ES 的记录数;fluentbit_tail_files_rotated_total:文件轮转次数,轮转太频繁说明容器日志落盘太快。
如果 input 的字节数在涨,但 output 的 proc 数不涨,那说明瓶颈在输出端或者 ES 端。如果 input 的字节数都不涨,那要检查是不是 Mem_Buf_Limit 把采集暂停了。
7.3 调优后的实际参数
压测结束前,我把 Fluent-Bit 整套参数稳定在这套组合,实测能支撑单节点每天约 300GB 日志量,CPU 占用不到 0.5 核,内存控制在 150Mi 内:
[SERVICE] Flush 5 Daemon Off Log_Level info Parsers_File parsers.conf HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 storage.path /var/log/flb-storage/ storage.total_limit_size 2G storage.sync normal storage.backlog.mem_limit 100M [INPUT] Name tail Path /var/log/containers/*.log Tag kube.* Refresh_Interval 10 Mem_Buf_Limit 10MB Skip_Long_Lines On DB /var/log/flb_kube.db Buffer_Chunk_Size 512KB Buffer_Max_Size 2MB [OUTPUT] Name es Match * Host elasticsearch-master.logging.svc.cluster.local Port 9200 Index ms-logs-${service_name}-%Y-%m-%d Logstash_Format Off Time_Key @timestamp Time_Key_Nanos Off Retry_Limit False Bulk_Max_Size 8Mstorage 相关的几个参数是 Fluent-Bit 1.8+ 才支持的,它能把内存放不下的缓冲数据写到磁盘持久化,有点像“给日志采集上了个 swap”,可以有效防止内存被打穿。
8. 还可以往哪走:日志管道的一鱼多吃
Flunet-Bit 这套管道搭完之后,只用来接 Elasticsearch 有点浪费。它本身支持同时配多个 Output,一份日志不落地就能分别发到 Kafka、ClickHouse、S3 或者对象存储。
我们后续把审计类日志单独开了一条输出接 Kafka,由下游实时计算服务消费,做风控和实时告警;普通业务日志仍然进 Elasticsearch 供 Kibana 检索;冷数据同学再做 S3 归档。三份数据互不干扰,配置上就是把 OUTPUT 段复制一份改下匹配规则而已。
从微服务可观测性的角度,日志只是其中一环。现在很多团队把 Metrics、Traces、Logs 三条路径统一用 Fluent-Bit 家族来打通。Fluent Bit 不只能接日志,还能采集节点指标、通过 OpenTelemetry 通道接 Trace,一套 DaemonSet 同时承担三类数据采集,对单节点 K8s 或者小规模集群是非常省心的方案。
以我这次压测的实际体验,日志采集这类基础设施不要追求功能多,稳定和可控才是第一位的。Fluent-Bit 的配置看起来简单,但每个参数背后都对应一种生产环境的真实风险,比如文件轮转、内存积压、时间戳时区、多行日志合并。把这些点逐个确认好,一套开箱即用的日志采集管道才真正算搭完。