数据采集与存储:日志采集策略、数据格式与存储方案
做数据回放,第一步就是要把数据「捞」上来,并且存好。这一步要是没做好,后面所有的回放都是空中楼阁。我个人习惯把数据采集和存储看作一个整体工程,而不是割裂的两个环节。今天我们就来聊聊日志怎么采、用什么格式存、以及存到哪里去。
一、日志采集策略:不是所有数据都值得采
很多团队一上来就说「我们要全量采集」。嗯,这个想法很美好,但现实很骨感。全量采集意味着巨大的存储成本和网络开销。我在项目中遇到过,一个高并发服务一天就能产生几十GB的日志,全量存下来,光磁盘就扛不住。
所以,采集策略的核心是:明确采集目标,按需采集。
1. 采样策略
对于高频事件,比如用户点击、接口调用,我们可以采用采样策略。比如每100次请求只记录1次,或者按时间窗口采样(每秒记录前10条)。
2. 分级采集
把日志分成不同等级:ERROR、WARN、INFO、DEBUG。线上环境一般只采集ERROR和WARN,INFO级别按需开启。DEBUG级别?千万别在生产环境开,否则日志量会爆炸。
3. 动态开关
我曾经踩过一个坑:线上出了个诡异bug,需要看DEBUG日志,但当时没开。后来我学乖了,所有日志采集都加上动态开关。通过配置中心,随时可以调整某个模块的日志级别,不用重启服务。
二、数据格式:JSON、CSV、ProtoBuf 怎么选?
数据格式的选择,说白了就是「易用性」和「性能」之间的博弈。我三种格式都用过,各有各的适用场景。
| 格式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| JSON | 可读性强、生态好、支持嵌套结构 | 体积大、解析慢 | 调试、小规模数据、跨语言交互 |
| CSV | 体积小、易于导入Excel/数据库 | 不支持嵌套、类型信息丢失 | 批量导入、数据分析、报表 |
| ProtoBuf | 体积极小、解析极快、强类型 | 可读性差、需要定义schema | 高性能场景、微服务间通信 |
1. JSON:最通用的选择
我个人习惯在开发和调试阶段用JSON。为什么?因为一眼就能看懂。比如一个用户行为日志:
{
"event": "click",
"user_id": "12345",
"timestamp": 1696000000,
"page": "/home",
"extra": {
"button": "login",
"duration_ms": 120
}
}
你看,嵌套结构一目了然。但到了生产环境,JSON的冗余就让人头疼了。每个字段名都要重复出现,数据量大了之后,带宽和存储都是问题。
2. CSV:简单粗暴
CSV适合做批量导出和数据分析。比如我要把日志导入到Hive或者Pandas里,CSV是最省事的格式。但要注意,CSV不支持嵌套结构,如果你的日志里有数组或对象,就得自己想办法序列化。
event,user_id,timestamp,page,extra
click,12345,1696000000,/home,"{""button"":""login""}"
嗯,这里要注意,CSV里的引号转义很容易出问题。我建议如果数据里有复杂结构,还是用JSON或者ProtoBuf吧。
3. ProtoBuf:高性能场景的首选
如果你追求极致性能,ProtoBuf是王道。它的体积只有JSON的1/3到1/5,解析速度更是快一个数量级。但代价是:你得先定义好.proto文件,而且数据是二进制的,没法直接用文本编辑器看。
syntax = "proto3";
message UserEvent {
string event = 1;
string user_id = 2;
int64 timestamp = 3;
string page = 4;
map<string, string> extra = 5;
}
我在做实时数据回放时,内部链路全部用ProtoBuf。只有在需要对外输出或者调试时,才转成JSON。
三、存储方案:本地还是云端?
数据存到哪里,取决于你的数据量、查询频率和预算。我见过不少团队,一开始图省事全存本地,结果数据一多就崩了。也见过一上来就上云,结果成本高得吓人。
1. 本地存储
适合小规模、低延迟的场景。比如单机测试、边缘计算节点。本地存储的优点是快,没有网络开销。缺点是容量有限,且容易丢失。
- 文件系统:按日期分目录,比如 /logs/2024/01/15/。我习惯用滚动日志,单个文件不超过100MB。
- 本地数据库:SQLite 或者 LevelDB,适合需要结构化查询的场景。
2. 云存储
当数据量超过TB级别,或者需要跨地域访问时,云存储是必然选择。常见的方案有:
| 存储类型 | 代表产品 | 适用场景 | 成本 |
|---|---|---|---|
| 对象存储 | S3、OSS、COS | 冷数据归档、大规模存储 | 低 |
| 时序数据库 | InfluxDB、TimescaleDB | 监控数据、时间序列分析 | 中 |
| 数据湖 | Delta Lake、Iceberg | 大规模数据分析、机器学习 | 高 |
我个人习惯用「分层存储」策略:热数据(最近7天)存在本地SSD或者高性能云盘,温数据(7-30天)存在对象存储,冷数据(30天以上)压缩后归档到低成本存储。这样既保证了查询速度,又控制了成本。
3. 混合方案:本地缓存 + 云存储
这是我最推荐的方案。采集端先把数据写到本地磁盘作为缓冲,然后异步上传到云端。这样即使网络断了,数据也不会丢。
# 伪代码示例:本地缓存 + 异步上传
def collect_log(log_entry):
# 1. 先写本地文件
local_file.write(log_entry)
# 2. 如果本地文件超过阈值,触发上传
if local_file.size > 100MB:
async_upload_to_s3(local_file)
local_file.reset()
你看,这个方案既简单又可靠。我在多个项目中都用过,从来没丢过数据。
四、知识体系总览
下面这张图是我自己梳理的数据采集与存储知识体系,你可以对照着看,查漏补缺。
这张图把今天讲的内容串起来了。你想想看,从采集策略到数据格式,再到存储方案,每一步都有取舍。没有最好的方案,只有最适合你的方案。
好了,数据采集与存储就聊到这里。记住,数据是回放的基础,基础打牢了,后面的回放才能稳。如果你在实际落地中遇到什么问题,欢迎随时交流。