4. 数据采集层:实时数据源接入与日志采集

数据采集层是整个实时OLAP系统的「水源地」。你想想看,如果源头的水质不行,下游再怎么折腾也白搭。我这些年见过太多团队,花大把精力优化查询引擎,结果数据采集端丢数据、延迟高,最后整个系统都不可信。

这一章,咱们就聊聊实时数据源怎么接、日志怎么采、数据库变更怎么抓,以及数据格式怎么选。都是我在实战中踩过的坑,希望能帮你少走弯路。

4.1 消息队列选型:Kafka vs Pulsar

消息队列是实时数据采集的「高速公路」。选对了,后续扩展很顺畅;选错了,改起来成本极高。

核心观点:我个人习惯,如果团队Kafka经验丰富、业务场景以高吞吐日志采集为主,优先选Kafka。如果有多租户隔离、跨地域复制、队列模型等复杂需求,Pulsar更合适。

特性 Kafka Pulsar
存储模型 分区日志,依赖磁盘顺序读写 分层存储:BookKeeper + 计算节点
消息模型 仅支持发布-订阅 支持发布-订阅 + 队列模型
多租户 通过Topic命名空间模拟 原生支持,资源隔离更彻底
延迟消息 需自行实现 内置支持
运维复杂度 中等,社区成熟 较高,组件多
吞吐量 极高(百万级/秒) 高(十万级/秒)

我在项目中遇到过一个问题:用Kafka做日志采集,业务量突然翻倍,分区数不够导致消费端积压。后来我们提前做了分区预评估,按峰值流量的1.5倍预留分区,才稳住了。

避坑指南:Kafka的分区数一旦确定,后续扩容需要重新分配数据,成本很高。建议初始分区数 = 预期峰值分区数 × 1.5,并开启自动Leader再平衡。

4.2 日志采集方案:Filebeat vs Fluentd

日志采集是实时数据源接入的「最后一公里」。选Filebeat还是Fluentd?我直接说结论:

  • Filebeat:轻量、简单、资源占用低。适合「采集→发送」这种单一场景。
  • Fluentd:插件丰富、路由灵活。适合需要复杂数据处理的场景。

我曾经在一个金融项目中,用Filebeat采集应用日志,结果发现日志格式不统一,下游解析很痛苦。后来我们在Filebeat前面加了一层Logstash做格式标准化,虽然多了一个组件,但整体稳定性提升不少。

注意:Filebeat默认的背压机制比较弱。如果Kafka写入变慢,Filebeat会不断重试,可能导致内存飙升。建议配置 queue.mem.events 限制内存队列大小。

# Filebeat 配置示例
filebeat.inputs:
- type: log
  paths:
    - /var/log/app/*.log
  fields:
    app: my-service
    env: production

output.kafka:
  hosts: ["kafka1:9092", "kafka2:9092"]
  topic: "app-logs"
  compression: gzip
  max_message_bytes: 1048576

# 内存队列限制
queue.mem:
  events: 4096
  flush.min_events: 512
  flush.timeout: 1s

4.3 CDC技术:Debezium vs Canal

CDC(Change Data Capture)是实时数据采集的「核武器」。它能捕捉数据库的每一次变更,然后实时同步到消息队列。说白了,就是让数据库也能「说话」。

我对比一下两个主流方案:

特性 Debezium Canal
支持数据库 MySQL、PostgreSQL、MongoDB、Oracle等 仅MySQL(阿里系)
部署方式 Kafka Connect插件 独立服务
数据格式 Avro/JSON(Schema Registry) JSON/Protobuf
社区活跃度 高(Red Hat维护) 中(阿里开源)
运维复杂度 依赖Kafka Connect 独立部署,相对简单

我记得有一次,用Debezium同步MySQL数据到Kafka,结果发现Binlog格式没设置成ROW模式,导致数据变更捕获不全。嗯,这里要注意:Debezium要求MySQL的Binlog格式必须是ROW,且开启GTID。

关键配置:

-- MySQL 必须开启
binlog_format = ROW
binlog_row_image = FULL
gtid_mode = ON
enforce_gtid_consistency = ON

4.4 数据格式与序列化:Avro vs Protobuf

数据格式选得好,后续处理省一半的力。我见过太多团队用JSON做实时数据格式,结果序列化/反序列化开销大,Schema变更还容易出问题。

我个人推荐:Avro 用于日志采集场景,Protobuf 用于CDC场景。为什么?

  • Avro:天生支持Schema演化,配合Schema Registry,可以做到向前/向后兼容。日志字段经常增减,Avro很合适。
  • Protobuf:序列化后体积更小,解析速度更快。CDC数据字段相对稳定,Protobuf更高效。

实战经验:我在一个电商项目中,用Avro做日志采集的序列化格式。刚开始觉得多维护一个Schema Registry很麻烦,但后来业务方频繁加字段,Avro的兼容性帮了大忙。如果当时用JSON,每次加字段都要改下游所有消费端。

// Avro Schema 示例
{
  "type": "record",
  "name": "OrderEvent",
  "namespace": "com.example",
  "fields": [
    {"name": "order_id", "type": "string"},
    {"name": "user_id", "type": "int"},
    {"name": "amount", "type": "double"},
    {"name": "status", "type": {"type": "enum", "name": "OrderStatus", "symbols": ["CREATED", "PAID", "SHIPPED"]}},
    {"name": "created_at", "type": "long", "logicalType": "timestamp-millis"}
  ]
}

4.5 整体架构图

下面这张图,是我在实际项目中用过的数据采集层架构。你可以看到,从日志、数据库、业务API三个源头,经过采集、传输、序列化,最终进入消息队列,供下游实时计算引擎消费。

实时数据采集层架构图 实时数据采集层架构 数据源 应用日志 MySQL Binlog 业务API 采集层 Filebeat Debezium Fluentd 序列化层 Avro + Schema Registry Protobuf 消息队列 Kafka / Pulsar 说明 日志采集:Filebeat → Kafka CDC采集:Debezium → Kafka API采集:Fluentd → Kafka

4.6 避坑总结

最后,我把这些年踩过的坑总结一下:

  1. Kafka分区数别拍脑袋:先做压测,按峰值流量的1.5倍预留。
  2. CDC必须用ROW模式:否则Binlog捕获不全,数据对不上。
  3. Schema Registry一定要上:别图省事用JSON,后面改字段会让你崩溃。
  4. Filebeat内存要限制:背压机制弱,容易OOM。
  5. Pulsar虽好,运维成本高:小团队慎选,Kafka更成熟。

数据采集层做好了,实时OLAP系统就成功了一半。下一层,咱们聊聊数据如何高效传输与缓冲。嗯,先到这里。