数据采集与存储:日志采集策略、数据格式与存储方案

做数据回放,第一步就是要把数据「捞」上来,并且存好。这一步要是没做好,后面所有的回放都是空中楼阁。我个人习惯把数据采集和存储看作一个整体工程,而不是割裂的两个环节。今天我们就来聊聊日志怎么采、用什么格式存、以及存到哪里去。

一、日志采集策略:不是所有数据都值得采

很多团队一上来就说「我们要全量采集」。嗯,这个想法很美好,但现实很骨感。全量采集意味着巨大的存储成本和网络开销。我在项目中遇到过,一个高并发服务一天就能产生几十GB的日志,全量存下来,光磁盘就扛不住。

所以,采集策略的核心是:明确采集目标,按需采集。

1. 采样策略

对于高频事件,比如用户点击、接口调用,我们可以采用采样策略。比如每100次请求只记录1次,或者按时间窗口采样(每秒记录前10条)。

我的经验:采样率不是固定的。我建议先全量跑一周,分析数据量级,再根据业务重要性动态调整采样率。比如核心交易链路用100%采样,非核心链路用1%采样。

2. 分级采集

把日志分成不同等级:ERROR、WARN、INFO、DEBUG。线上环境一般只采集ERROR和WARN,INFO级别按需开启。DEBUG级别?千万别在生产环境开,否则日志量会爆炸。

3. 动态开关

我曾经踩过一个坑:线上出了个诡异bug,需要看DEBUG日志,但当时没开。后来我学乖了,所有日志采集都加上动态开关。通过配置中心,随时可以调整某个模块的日志级别,不用重启服务。

避坑指南:我曾经因为忘记关闭DEBUG日志,导致线上磁盘被打满,服务挂了半小时。从那以后,我强制要求所有日志采集策略必须包含「自动降级」机制——当磁盘使用率超过80%时,自动切换到只采集ERROR级别。

二、数据格式: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。

我的建议:不要只用一种格式。我通常的做法是:采集端用ProtoBuf,存储层同时保留原始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()

你看,这个方案既简单又可靠。我在多个项目中都用过,从来没丢过数据。

核心要点:数据采集和存储没有银弹。你需要根据业务场景、数据量、预算来权衡。但有一条原则是通用的:先保证数据不丢,再考虑性能优化。

四、知识体系总览

下面这张图是我自己梳理的数据采集与存储知识体系,你可以对照着看,查漏补缺。

数据采集与存储知识体系 日志采集策略 采样策略 分级采集 动态开关 数据格式 JSON CSV ProtoBuf 存储方案 本地存储 云存储 混合方案 核心原则:先保证数据不丢,再考虑性能优化 按需采集 → 合理选型 → 分层存储

这张图把今天讲的内容串起来了。你想想看,从采集策略到数据格式,再到存储方案,每一步都有取舍。没有最好的方案,只有最适合你的方案。

好了,数据采集与存储就聊到这里。记住,数据是回放的基础,基础打牢了,后面的回放才能稳。如果你在实际落地中遇到什么问题,欢迎随时交流。