采集架构设计:Agent模式、无Agent模式、集中式与边缘采集、高可用与容错

日志采集架构是整个系统的骨架。骨架歪了,后面加再多肉也站不稳。我见过不少团队一上来就选 Filebeat 配 Kafka,结果业务量上去后 Agent 占满磁盘 IO,或者无 Agent 模式被防火墙堵死。说白了,选架构不是拍脑袋,得从场景、资源、容错三个维度去权衡。

这一章我们就把四种核心架构掰开揉碎。我会结合自己踩过的坑,聊聊 Agent 模式和无 Agent 模式的适用边界,集中式与边缘采集的取舍,以及怎么让采集链路在高负载下不丢数据。

Agent模式 vs 无Agent模式

先上一个对比表,方便你快速建立认知:

维度Agent模式无Agent模式
部署方式每台机器安装独立进程(如 Filebeat、Fluentd)应用 SDK 直写 / syslog 推送 / 挂载共享卷
资源占用额外 CPU 和内存,需要独立运维在应用进程内消耗,无独立进程开销
灵活性可独立升级、配置、过滤、缓冲依赖应用改造,变更影响面大
安全性Agent 需要一定系统权限通常只需网络端口权限
典型场景物理机 / 虚拟机 / 容器化环境Serverless / 云原生短生命周期任务

Agent 模式 是我用得最多的方案。记得有一次在 Kubernetes 集群里跑 Filebeat,每个 Pod 配一个 sidecar,结果集群规模从 200 节点涨到 500 节点,Agent 的 CPU 飙升到 15%。后来我把采集规则从全量正则改成结构化 JSON 解析,再配合背压机制,才稳住。嗯,这里有个关键点——Agent 不是装上去就完事,你得给它设置好保护:内存上限、磁盘缓冲大小、重试间隔。

无 Agent 模式 听起来轻量,其实坑不少。比如 Java 应用直接通过 Log4j2 的 SocketAppender 发日志,一旦接收端故障,日志就会在应用内存里堆积甚至 OOM。我建议只在两种场景用:一是函数计算等天然无服务器环境,二是日志量极小且容错要求不高的内部工具。你想想看,如果丢失几个日志不影响核心 SLA,用无 Agent 确实省事。

我的选择逻辑: 只要机器数 < 100 且团队有运维能力,优先上 Agent 模式。超过 1000 台且大部分是容器时,考虑混合模式——关键业务用 Agent,短时任务用无 Agent。

集中式采集 vs 边缘采集

说完了 Agent,再看数据该往哪 flush。这是一个典型的网络拓扑问题,但很多人一开始只盯着 Kafka 集群,忽略了边缘节点的重要性。

对比项集中式采集边缘采集
数据流Agent → 中心集群(Kafka / Logstash)Agent → 边缘网关 → 中心集群
网络压力所有流量直打中心,带宽容易成瓶颈边缘做预聚合、过滤,大幅降低上行带宽
延迟端到端延迟低(一跳)多一跳,增加 10~50ms
运维复杂度中心集群压力大,需做读写分离需要管理边缘节点,但中心集群压力分散
适用规模百台级别千台以上或跨区域部署

我曾在一个跨国电商项目中遇到一个典型场景:东南亚机房日志直连到国内中心,跨国专线带宽不够,而且晚上高峰时日志经常堵在 Agent 的磁盘缓冲里。后来我们在每个区域部署一个轻量边缘网关(用 Vector 实现),做了三件事:

  • 预过滤——丢弃 DEBUG 级别日志,只保留 WARN 以上 + 慢查询。
  • 本地持久化——用 RocksDB 做缓冲,避免网络抖动丢数据。
  • 分批传输——每 30 秒压缩一批,减少连接数。

效果很明显:中心集群的写入压力降低了 60%,跨区域带宽费用减了一半。不过别高兴太早,边缘网关本身也是故障点。我曾经因为边缘节点磁盘写满,导致日志积压了 4 小时才恢复。所以边缘节点必须做磁盘水位监控和自动清理策略。

避坑指南: 边缘采集不要和业务混部在同一台机器上。否则业务高峰时日志刷盘会跟边缘缓冲抢 IO,两边都受影响。我曾经因为这个问题导致业务线程 Wait 时间暴涨 30%。

高可用与容错:怎么让采集链路不丢数据

架构选好了,如果传输链路一跳就断,前面全白忙。我见过最惨的一次:Kafka 集群磁盘写满,Logstash 消费线程被熔断,结果 Agent 的磁盘缓冲也满了,开始循环丢弃旧日志。等恢复后一看,丢了 3 个小时的线上错误日志。

高可用设计需要覆盖三个层面:

  1. Agent 层:配置本地磁盘缓冲(推荐大小 = 最大消息体 × 峰值每秒 × 15 分钟)。Filebeat 的 queue.mem.events 和 Fluentd 的 buffer 插件都可以做。注意缓冲不能放在 tmpfs,否则机器重启就全没了。
  2. 传输层:使用至少冗余的两条上游链路。比如 Agent 配置两个 Kafka Broker 列表,或者用 load balancer 做 TCP 代理。别只依赖 DNS 轮询——DNS 缓存失效时连接会全断。
  3. 中心层:Kafka 配置副本数 ≥ 2,ACK 策略设为 all(确保所有副本都收到才返回)。Logstash 或 Flink 消费端要开启 exactly-once 语义,或者退而求其次用 at-least-once + 去重。

关于容错,我特别想提一个细节——背压(backpressure)。很多 SDK 和 Agent 默认是不限制发送速率的,一旦下游慢,上游就会把内存打爆。我现在每个 Agent 都会配一个速率限制:

# Filebeat 示例:限制输出最大吞吐
output.kafka:
  hosts: ["kafka1:9092", "kafka2:9092"]
  topic: "app-logs"
  max_message_bytes: 1048576
  # 关键:限制每秒发送批次
  bulk_max_size: 2048
  # 背压超时,下游不可用时等待 60 秒再重试
  backoff.init: 1s
  backoff.max: 60s
核心原则: 日志可以晚到,但不能丢。容错设计的底线是保证 at-least-once。如果有去重能力的下游(如 Elasticsearch 的 _id 幂等写),再用 exactly-once 加强。

架构选型决策流程图

下面这张 SVG 图总结了四种架构的关系和适用边界。灰色框是决策点,彩色节点是你最终选择的方案。你可以把它贴在团队技术文档里当速查表。

日志采集架构选型决策图 日志采集架构选型决策 日志源(应用/系统) 是否可控环境(如 VM/容器)? 是 → Agent模式,否 → 无Agent模式 Agent模式 Filebeat / Fluentd / Logstash 本地缓冲 + 速率限制 规模 >1000台? 是→边缘采集,否→集中式 无Agent模式 SDK直写 / syslog / 共享卷 适合 Serverless / 短任务 可接受少量丢失? 否→加本地缓冲变 Agent 模式 集中式采集 直发 Kafka / ES 延迟低,中心压力大 边缘采集 边缘网关(Vector / Fluent Bit) 预过滤 + 本地持久化 高可用与容错 冗余链路 + 背压 + at-least-once

你发现没有,这个图右上角那个无Agent模式有一条回退线——如果你不能接受丢日志,就加本地缓冲退化成 Agent 模式的变体。实际上,很多云原生场景就是用这种混合方式:函数计算里加一个轻量 sidecar 做缓冲,平时不用,异常时自动拉起。

好了,关于采集架构的核心模型就聊到这。下次你要做日志方案评审时,拿这张图和三个表格去怼需求方,基本不会翻车。记住一点:架构没有银弹,只有权衡。