数据采集层:前端埋点、服务端日志与消息队列
数据采集是整个用户行为流的起点。说白了,你后面分析得再花哨,如果采集层就漏了数据或者采错了,那全是白搭。我见过太多团队在实时计算上花了大价钱,最后发现是埋点埋歪了——嗯,这种坑踩一次就够了。
这一章我们聚焦三个核心问题:前端怎么采、后端怎么补、中间怎么传。我把它们拆成三块来讲。
2.1 前端埋点:代码埋点 vs 全埋点
前端埋点,就是用户在浏览器或 App 里操作时,我们把行为数据发回来。目前主流就两种方式:代码埋点和全埋点。我分别说说它们的适用场景和坑。
2.1.1 代码埋点
代码埋点是最传统的方式。开发人员在需要追踪的交互位置,手动插入一段上报代码。比如用户点击「加入购物车」按钮,你就写一行:
// 代码埋点示例
trackEvent('add_to_cart', {
product_id: 'P10086',
price: 199.00,
quantity: 1,
page: 'product_detail'
});
优点很明显:数据精确,你想采什么字段就采什么字段。缺点也直接:每次改埋点都要发版,而且容易漏埋。
2.1.2 全埋点
全埋点也叫无埋点或自动埋点。前端 SDK 自动监听所有用户交互事件——点击、滑动、页面浏览——然后一股脑全发回来。你不需要写任何业务代码。
听起来很爽对吧?但有个大问题:数据量爆炸。一个页面可能触发几十个事件,其中 80% 是你根本不需要的。而且全埋点拿不到业务语义——它只知道「用户点了坐标 (x,y) 处的元素」,不知道那是「加入购物车」按钮。
| 对比维度 | 代码埋点 | 全埋点 |
|---|---|---|
| 数据精确度 | 高,字段可控 | 低,缺乏业务语义 |
| 开发成本 | 高,每次改埋点需发版 | 低,接入 SDK 即可 |
| 数据量 | 可控,只采需要的 | 巨大,大量冗余事件 |
| 适用场景 | 核心业务路径 | 探索期、A/B 测试 |
2.2 服务端日志采集
前端埋点有个天然缺陷:用户可能禁用 JavaScript、网络断连、或者直接关掉页面。这时候行为数据就丢了。服务端日志采集就是来补这个缺的。
服务端日志,说白了就是你的后端服务在处理每个请求时,把关键信息打印到日志文件里。比如用户下单,后端收到请求后记录:
// 服务端日志示例(JSON 格式)
{
"timestamp": 1712563200000,
"event": "order_created",
"user_id": "U_12345",
"order_id": "O_67890",
"amount": 299.00,
"ip": "192.168.1.1",
"user_agent": "Mozilla/5.0..."
}
服务端日志的好处是:数据可靠,只要请求到了后端,日志就一定存在。而且你能拿到一些前端拿不到的信息,比如真实 IP、服务端处理耗时。
我个人习惯的做法是:前端埋点和服务端日志使用同一套 event_id 生成规则。这样在实时计算时,可以轻松做 join 操作,判断「点击了但没下单」的流失场景。
2.3 消息队列:Kafka 基础
数据采上来了,往哪放?直接写数据库?别闹。实时场景下,前端每秒可能产生几万甚至几十万条事件,数据库根本扛不住。这时候就需要消息队列来做缓冲和解耦。
Kafka 是目前实时数据 pipeline 的事实标准。我简单讲几个核心概念,够你上手用。
2.3.1 Topic 与 Partition
Topic 是消息的分类。比如你建一个 topic 叫 user_behavior,所有用户行为事件都往这个 topic 里发。Partition 是 topic 的分片,每个 partition 里的消息是有序的。
为什么要分 partition?为了并行。一个 topic 有 8 个 partition,就可以被 8 个消费者同时消费,吞吐量直接翻 8 倍。
# 创建 topic 示例
bin/kafka-topics.sh --create \
--topic user_behavior \
--partitions 8 \
--replication-factor 3 \
--bootstrap-server localhost:9092
2.3.2 Producer 与 Consumer
Producer 是生产者,负责把消息发到 Kafka。Consumer 是消费者,负责从 Kafka 拉取消息处理。两者通过 topic 解耦——producer 不需要知道谁在消费,consumer 也不需要知道谁在生产。
这里有个关键点:消息的可靠性。Producer 发送消息时可以设置 ack 级别:
| ack 级别 | 含义 | 可靠性 | 性能 |
|---|---|---|---|
| 0 | 不等待确认,直接发下一条 | 最低,可能丢消息 | 最高 |
| 1 | 等待 leader 确认 | 中等,leader 挂了可能丢 | 中等 |
| all | 等待所有副本确认 | 最高,不丢消息 | 最低 |
2.3.3 数据采集的整体架构
把前端埋点、服务端日志和 Kafka 串起来,就是一套完整的数据采集 pipeline。我画了一张图帮你理解:
你看,前端埋点和服务端日志是两条独立的采集通道,但它们最终都汇入 Kafka。Kafka 在这里扮演了「数据总线」的角色——上游生产者只管往里写,下游消费者只管往外读,互不干扰。
2.4 本章小结
数据采集层看起来简单,但细节决定成败。我总结几个要点:
- 前端埋点:核心路径用代码埋点,探索期用全埋点,两者互补
- 服务端日志:作为前端埋点的兜底,保证数据不丢
- Kafka:用 topic 做分类,用 partition 做并行,用 ack 级别做可靠性权衡
- 整体架构:前端 + 后端双通道采集,统一入 Kafka,再分发给实时和离线链路