日志,是分布式系统的“黑匣子”。在字节跳动,每天产生 数百 TB 日志,这些数据支撑着监控、推荐、增长、安全等核心系统。本篇文章将揭秘字节跳动的日志采集系统设计,并用 Node.js + Kafka 实现一个简化版日志采集链路。
🧠 一、日志采集的核心难点
- 量大:字节跳动级别每天产生数百 TB 日志
- 链路长:从客户端 → 采集器 → 聚合服务 → 下游消费(Hive、ES)
- 实时性要求高:部分日志需秒级进入实时推荐系统
- 多格式多来源:Web、App、后端、容器、基础设施全链打通
📦 二、字节跳动日志采集架构演进
🔷 架构概览:
Client → SLS SDK → DataWay(本地Agent)→ Kafka 集群 → Flink / Hive / ClickHouse
模块 | 功能说明 |
---|---|
SLS SDK | 各端采集,前端/客户端打点 |
DataWay | 轻量日志代理,支持压缩、批量、打标签 |
Kafka | 核心消息队列,支持异地复制、Topic 管控 |
后处理系统 | Flink 做实时指标,Hive 做离线分析 |
🔧 DataWay 是字节跳动自研的本地日志 Agent,稳定运行在数十万台机器上。
⚙️ 三、代码实战:Node.js + Kafka 模拟日志采集链路
1. 安装 Kafka 依赖:
npm install kafkajs
2. 创建 Kafka Producer(日志采集端)
const { Kafka } = require('kafkajs');
const kafka = new Kafka({ clientId: 'logger', brokers: ['localhost:9092'] });
const producer = kafka.producer();
async function sendLog(userId, action) {
await producer.connect();
await producer.send({
topic: 'user-events',
messages: [
{ value: JSON.stringify({ userId, action, timestamp: Date.now() }) },
],
});
await producer.disconnect();
console.log('日志已发送');
}
sendLog('u10001', 'click_button');
3. 创建 Kafka Consumer(日志聚合/处理端)
const consumer = kafka.consumer({ groupId: 'log-processors' });
async function start() {
await consumer.connect();
await consumer.subscribe({ topic: 'user-events', fromBeginning: true });
await consumer.run({
eachMessage: async ({ message }) => {
const log = JSON.parse(message.value.toString());
console.log('处理日志:', log);
// 模拟落地到存储系统
},
});
}
start();
🔍 四、工程实践中的重点细节
问题点 | 字节跳动做法 |
---|---|
网络不稳定 | SDK 离线缓存 → Agent 重发 |
日志质量问题 | 日志结构校验 + 异常字段打标 |
日志过载风险 | 限速 + 拆包 + 分区限流 + Topic 限制 |
可观测性 | 日志采集链路自身也打点监控 |
隐私合规 | 用户隐私字段需脱敏/加密 |
✍️ 五、总结与思考
- 字节跳动日志采集体系是分布式容错 + 实时传输 + 海量消费三者结合
- Kafka 是核心组件,但本地 Agent(如 DataWay)同样重要
- 中小型团队可以从 “SDK → Kafka → Hive/Flink” 模型入手,逐步演进
🎁 拓展推荐
- 《Kafka 权威指南》— Confluent 团队
- 《字节跳动日志系统 DataWay 架构设计与演进》
- Flink + Kafka 流处理实时日志系统实践