2、日志采集体系:从标准化到高可用架构
日志采集,听起来好像就是把日志从A点搬到B点。但做过生产环境的人都知道,这里面的坑,一个比一个深。我刚开始搞PaaS平台那会儿,就被日志搞崩过好几次。今天咱们就聊聊,怎么把日志采集这件事,做得既稳当又高效。
2.1 日志标准化设计:别让脏数据毁了你的分析
你想想看,如果每个应用都按自己的喜好写日志,有的用JSON,有的用纯文本,有的时间戳格式还不一样。那后面的日志分析、告警、排障,基本就是一场灾难。
我个人的习惯是,在日志采集的源头就做标准化。 说白了,就是定一套规矩,所有应用都得遵守。
2.1.1 标准字段定义
一个标准的日志条目,至少应该包含这些字段:
| 字段名 | 类型 | 说明 | 示例 |
|---|---|---|---|
| @timestamp | datetime | 日志产生时间,ISO8601格式 | 2025-01-15T10:30:00.123Z |
| level | string | 日志级别 | INFO / WARN / ERROR |
| logger | string | 产生日志的类或模块名 | com.example.UserService |
| message | string | 日志正文 | 用户登录成功,userId=12345 |
| trace_id | string | 分布式链路追踪ID | abc123def456 |
| service | string | 服务名称 | user-service |
| instance | string | 实例ID或IP | 10.0.1.5:8080 |
2.1.2 日志格式规范
我建议统一使用JSON格式。为什么?因为JSON是自描述的,解析起来简单,扩展性也好。举个例子:
{
"@timestamp": "2025-01-15T10:30:00.123Z",
"level": "ERROR",
"logger": "com.example.OrderService",
"message": "订单支付超时",
"trace_id": "abc123def456",
"service": "order-service",
"instance": "10.0.1.10:8080",
"extra": {
"order_id": "ORD20250115001",
"amount": 299.00,
"payment_method": "wechat"
}
}
2.2 Filebeat / Logstash / Fluentd 选型对比
选型这件事,没有绝对的好坏,只有合不合适。我这些年三个工具都用过,说说我的感受。
| 特性 | Filebeat | Logstash | Fluentd |
|---|---|---|---|
| 定位 | 轻量级采集器 | 重量级处理管道 | 统一日志层 |
| 资源占用 | 极低(10MB左右) | 较高(Java,吃内存) | 中等(Ruby/C) |
| 处理能力 | 弱,仅采集和简单转发 | 强,支持复杂过滤和转换 | 中等,插件丰富 |
| 适用场景 | 边缘节点采集 | 中心化处理 | Kubernetes环境 |
| 社区生态 | ELK全家桶,成熟 | ELK全家桶,成熟 | CNCF项目,云原生友好 |
我个人习惯的搭配是:
- 边缘节点用 Filebeat:因为它够轻,几乎不占资源。我在一个2000+节点的集群里,每台机器都部署了Filebeat,CPU和内存占用几乎可以忽略不计。
- 中心处理用 Logstash:当需要对日志做复杂的解析、过滤、脱敏时,Logstash的插件生态是最全的。比如从日志里提取IP、解析User-Agent、做GeoIP地理定位,Logstash一把梭。
- Kubernetes环境用 Fluentd:Fluentd对K8s的支持最好,可以自动采集Pod日志,还能通过标签做路由。如果你在用EFK(Elasticsearch + Fluentd + Kibana)栈,Fluentd是首选。
避坑指南: 我曾经在一个项目里,直接用Logstash做边缘采集。结果呢?每台机器上Logstash吃掉500MB内存,集群规模一大,内存直接爆了。后来全部换成Filebeat,问题迎刃而解。所以记住:边缘采集用轻量级工具,中心处理用重量级工具。
2.3 Kafka在日志链路中的缓冲作用
为什么要在日志链路里加Kafka?说白了,就是为了解耦和削峰。
你想想看,如果日志采集器直接往Elasticsearch写数据,一旦ES集群压力大、写入变慢,采集器就会被阻塞。严重的时候,采集器会挂掉,日志就丢了。
Kafka在这里扮演的角色,就是一个巨大的缓冲池。
2.3.1 典型架构
应用日志 -> Filebeat -> Kafka -> Logstash -> Elasticsearch
这个架构的好处是:
- 解耦:采集端和处理端互不影响。Filebeat只管往Kafka写,Logstash只管从Kafka读。
- 削峰填谷:业务高峰期日志量暴增,Kafka可以扛住百万级TPS的写入。等低谷期,Logstash再慢慢消费。
- 数据持久化:Kafka的消息是持久化到磁盘的。就算Logstash挂了,数据也不会丢。等它恢复后,从上次的offset继续消费就行。
2.3.2 配置示例
Filebeat输出到Kafka的配置:
output.kafka:
hosts: ["kafka1:9092", "kafka2:9092", "kafka3:9092"]
topic: "app-logs"
partition.round_robin:
reachable_only: true
required_acks: 1
compression: gzip
max_message_bytes: 1000000
Logstash从Kafka消费的配置:
input {
kafka {
bootstrap_servers => "kafka1:9092,kafka2:9092,kafka3:9092"
topics => ["app-logs"]
group_id => "logstash-group"
consumer_threads => 4
auto_offset_reset => "latest"
codec => "json"
}
}
2.4 日志采集高可用架构
日志采集的高可用,说白了就是:任何一个组件挂了,日志都不能丢。
我建议采用多级冗余的架构:
2.4.1 采集端高可用
- Filebeat多输出:配置多个Kafka集群作为输出。如果主集群挂了,自动切换到备集群。
- 本地缓存:Filebeat支持将未发送成功的日志缓存到本地磁盘。等网络恢复后,自动重发。
output.kafka:
hosts: ["kafka-primary:9092", "kafka-secondary:9092"]
topic: "app-logs"
# 开启本地缓存
queue.mem.events: 4096
queue.mem.flush.min_events: 512
2.4.2 传输层高可用
- Kafka集群:至少3个Broker,副本因子设为3。这样任何一个Broker挂了,数据都不会丢。
- 多数据中心:如果条件允许,可以跨机房部署Kafka集群。一个机房挂了,另一个机房还能继续服务。
2.4.3 处理端高可用
- Logstash多实例:部署多个Logstash实例,组成消费者组。Kafka会自动做负载均衡。
- ES集群:Elasticsearch本身就有高可用机制,分片和副本可以保证数据不丢。
我曾经踩过的坑: 有一次Kafka集群的磁盘满了,导致所有日志都写不进去。Filebeat重试了几次后,本地缓存也满了,就开始丢日志。后来我加了一个监控:当Kafka的磁盘使用率超过80%时,自动告警并扩容。从那以后,再也没出过类似问题。
2.4.4 整体架构图(文字描述)
应用实例1 -> Filebeat -> Kafka集群 (3节点, 副本3) -> Logstash集群 (4实例) -> ES集群 (3节点)
应用实例2 -> Filebeat -> Kafka集群 (3节点, 副本3) -> Logstash集群 (4实例) -> ES集群 (3节点)
应用实例3 -> Filebeat -> Kafka集群 (3节点, 副本3) -> Logstash集群 (4实例) -> ES集群 (3节点)
|
监控告警 (磁盘、吞吐量、延迟)
这个架构里,任何一个单点挂了,都不会影响整体日志采集。Filebeat有本地缓存,Kafka有副本,Logstash有消费者组,ES有分片副本。嗯,这才是生产级别的日志采集体系。
好了,日志采集这部分就聊到这儿。下一章咱们聊聊日志存储和检索,那又是另一番天地了。
公众号:蓝海资料掘金营,微信deep3321