日志收集方法与工具(Syslog、Fluentd、Logstash)

日志收集是整个威胁狩猎和 IOC 提取的“水源”。水源不干净,后面分析得再好也是白搭。我自己早期做应急响应时,最头疼的就是客户说“日志我们有,但不知道在哪台机器上”,或者“日志格式太乱,根本没法用”。说白了,收集这一步没做好,后面全是坑。

这一章我们重点聊三个最常用的日志收集手段:Syslog、Fluentd 和 Logstash。它们代表了三种不同的设计思路,也对应着不同的业务场景。

Syslog:最老牌的日志传输协议

Syslog 的历史可以追溯到 80 年代,但到今天它仍然是网络设备、Linux 服务器的标配。为什么?因为它足够轻、足够简单。

Syslog 其实是一套协议规范(RFC 5424),它定义了日志的格式、严重等级和设施。你想想看,一台思科路由器、一台 Fortinet 防火墙、一台 Linux 服务器,它们都能往外扔 Syslog 消息。

核心数据流:日志生产者 → Syslog 发送端(UDP 514 / TCP 514) → Syslog 接收端(集中收集器)

我记得有一次帮某金融客户做日志审计,他们的核心交换机每天产生几千万条 Syslog 消息,全用 UDP 发到一台老旧的 Rsyslog 服务器上。结果丢包率高达 15%。嗯,这里要注意:Syslog 默认用 UDP,不保证可靠传输。如果你对完整性有要求,就得切到 TCP 或者加 RELP。

下面是一个标准的 Rsyslog 配置片段,把远程日志写入本地文件:

# /etc/rsyslog.conf 片段
# 开启 TCP 接收
$ModLoad imtcp
$InputTCPServerRun 514

# 按来源 IP 分类存储
$template RemoteLogs,"/var/log/remote/%FROMHOST-IP%/%PROGRAMNAME%.log"
*.* ?RemoteLogs

我在项目中遇到过,很多人直接用默认的 UDP 收 Syslog,结果索引不全导致事件溯源失败。所以我的建议是:如果日志量小于 1 万 EPS(每秒事件数),用 TCP 没问题;超过这个量,考虑用 Fluentd 或者 Logstash 加缓冲层。

特性 Syslog Fluentd Logstash
协议 UDP/TCP/RELP HTTP/Thrift/Syslog HTTP/TCP/Syslog/Beats
缓冲机制 无内置缓冲 内存+文件缓冲 内存+持久化队列
配置复杂度 低 中 高
资源消耗 极低 低 中高
典型场景 网络设备、Linux 系统 容器日志、微服务 ELK 栈、复杂数据处理

Fluentd:统一日志层

Fluentd 是 CNCF 毕业项目,它的设计哲学是“统一日志层”。什么意思呢?就是说不管你的日志来源是什么格式、什么协议,Fluentd 都能用插件把它吃进来,再吐到 Elasticsearch、S3、Kafka 等目标。

我个人非常喜欢 Fluentd 的内存和文件缓冲机制。有一次线上业务日志突然暴增,后端 Elasticsearch 集群撑不住开始丢索引。Fluentd 的文件缓冲把日志稳稳地写在了磁盘上,等集群恢复后又自动重放。要是换成 Logstash 默认配置,可能直接内存溢出导致丢数据了。

来看一个 Fluentd 配置的典型例子,收集容器标准输出并打标签:

# fluentd.conf

  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-containers.log.pos
  tag kubernetes.*
  
    @type json
  



  @type elasticsearch
  host elasticsearch-prod
  port 9200
  logstash_format true
  buffer_chunk_limit 8M
  flush_interval 10s

避坑指南:我曾经因为没配 buffer_type file,导致一次短暂的 ES 不可用就丢了一整分钟的日志。切记 — 生产环境一定开启文件缓冲。

小技巧:Fluentd 的 label 功能可以让你把数据流路由到不同的输出端。比如把安全日志打到 ES 做实时分析,把性能日志打到 S3 做长期归档。

Logstash:ELK 的管道核心

Logstash 是 Elastic 家族的一员,它最大的特点是插件丰富 — 超过 200 个输入/过滤/输出插件。你可以用它做复杂的日志解析、数据清洗、字段提取。

但 Logstash 有个硬伤:它跑在 JRuby 上,内存开销大。我见过很多团队为了省成本,用一台 4G 内存的虚机跑 Logstash 压 5000 EPS,结果 OOM 频繁。其实 Logstash 更适合做“预处理管道”,不建议做高吞吐的传输代理。

下面是一个从 Syslog 输入到 ES 输出的典型 Logstash 配置:

# logstash.conf
input {
  syslog {
    port => 514
    type => "syslog"
  }
}

filter {
  grok {
    match => { "message" => "%{SYSLOGTIMESTAMP:timestamp} %{SYSLOGHOST:hostname} %{WORD:program}: %{GREEDYDATA:log_message}" }
  }
  date {
    match => [ "timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "syslog-%{+YYYY.MM.dd}"
  }
}

你可能注意到 Logstash 的配置语法和 Fluentd 不太一样 — 它是 Ruby 风格的 DSL。我个人觉得 Logstash 的 filter 是三个工具里最强的,尤其 grok 正则匹配,配合自定义模式,几乎能解析任何非结构化文本。但代价就是学习曲线陡一点,而且运行稳定性受插件版本影响大。

注意:Logstash 的持久化队列(queue.type: persisted)能提供崩溃恢复能力,但会显著增加磁盘 I/O。我建议只在需要严格数据不丢的场景开启,比如金融支付日志。

工具对比与选型建议

三个工具不是互斥的,实际生产环境经常混合使用。我总结了一个选型参考:

  • 网络设备/传统架构 → 优先用 Syslog 收集到 Rsyslog 或 Syslog-ng 做初级聚合,再转发给 Logstash 或 Fluentd 做二次处理。
  • Kubernetes / 微服务 → 推荐 Fluentd。它原生支持 DaemonSet 部署,资源占用低,插件社区活跃。
  • 大数据量、复杂 ETL → 用 Logstash 做 filter 层,但前面最好加一层轻量收集器(Filebeat / Fluent Bit)减少内存压力。

下面这张图展示了我在一个实际项目中的混合部署架构:

日志收集混合部署架构(Syslog + Fluentd + Logstash) Linux 服务器 网络设备 容器/K8s Rsyslog / Syslog-ng UDP/TCP 514 Fluentd 内存/文件缓冲 Logstash grok 解析 + 持久化队列 Elasticsearch Kafka / S3 文件归档 说明:实线代表原生日志流,虚线代表可选的转发/聚合路径。 生产环境中常见做法是 Syslog → Fluentd/Logstash → ES/Kafka。

最后说一句实在话:没有银弹。我在不同项目里尝试过多种组合,最终沉淀下来的经验就是——按场景选工具,按稳定性做冗余。Syslog 负责轻量传输,Fluentd 负责缓冲和路由,Logstash 负责深度解析。三者配合,基本能覆盖 80% 的安全日志收集需求。