日志存储基础:传统存储模式与存储格式
聊审计日志存储,第一个绕不开的话题就是——存在哪?怎么存?
我见过不少团队,一开始图省事,随便往文件里一写,等日志量起来了,查一条记录要翻半天。也有的直接用数据库表硬扛,结果写入压力把业务库拖垮了。说白了,存储选型决定了后续索引能不能建得上去。
这一节我把传统存储模式和常见格式掰开了讲。先不讲分布式方案,那些后面有专门章节(嗯,但你要知道,很多分布式方案底层绕不开这俩基础模式)。
存储模式:文件还是数据库?
传统日志存储就两条路:文件存储和数据库存储。我习惯用下面这个表来对比,每次选型都拿出来看一眼。
| 维度 | 文件存储 | 数据库存储 |
|---|---|---|
| 写入方式 | 追加写(append only),几乎无锁 | 行插入,事务、索引维护有额外开销 |
| 读取查询 | 需要线性扫描或二分查找(带索引文件) | SQL 查询,支持条件过滤、聚合、排序 |
| 索引能力 | 需要自己实现索引(如倒排、B+树文件) | 内置 B+ 树 / 哈希索引,但建索引有写放大 |
| 一致性保证 | 靠文件系统同步,断电可能丢最后几条 | ACID 事务,但高并发下性能衰减明显 |
| 扩展性 | 分文件(按时间、按用户),天然水平 | 分表、读写分离、分库,复杂度较高 |
| 典型场景 | 高吞吐、低价值、保留期短的审计日志 | 需要实时检索、复杂查询的审计日志 |
我的经验: 文件存储更适合流水线式的日志落盘,比如 Nginx 访问日志、系统 syslog。但一旦你需要按某个字段频繁检索,比如“查某个人最近10条操作”,文件模式没有索引就非常痛苦。
我记得有一次做金融审计项目,把日志全写进了 PostgreSQL 的普通表,每天几亿条插入,磁盘 I/O 直接打满。后来改成先写文件(按小时分片)再异步批量导入数据库,才把问题解决掉。
存储格式:文本、二进制、JSON
格式选择直接影响存储效率和解析速度。我按我最常用的三个方向来说。
文本格式(行协议)
典型代表:Apache 的 common log format、自定义“key=value”格式。每行一条记录,字段用分隔符(空格、逗号、竖线)隔开。
2025-03-20 10:15:30 | user_10086 | OPERATION | DELETE | /api/orders/98765 | SUCCESS
优点:人类可读,用 `grep`、`awk` 就能秒级排查。缺点也很明显:解析效率低(每行都要拆分字符串),存储冗余大(字段名重复出现)。
我曾经用文本格式存过亿级日志,单行平均200字节,压缩后还有40字节。查询时用 `grep` 配合索引文件(提前按时间建好偏移表)勉强能用,但跨天查询就慢了。
二进制格式
典型代表:protobuf、Thrift、自研结构体序列化。每条记录按固定 schema 编码,字段按类型编码。
// protobuf 消息定义
message AuditLog {
int64 timestamp = 1;
string user_id = 2;
int32 op_type = 3;
string resource = 4;
bytes detail = 5;
}
优点:体积小(可压缩至文本的 1/3~1/5),解析快(按偏移直接取字段)。缺点:肉眼无法直接看,需要用工具转码才能调试。
温馨提示: 如果团队监控、排查主要靠脚本和日志文件头,二进制会大幅拉高排障成本。我建议审计日志先用文本格式快速迭代,稳定后再切换到二进制以求存储效率。
JSON 格式
不用多解释,现在大部分应用框架默认输出 JSON。每条日志是一个 JSON 对象。
{
"time": "2025-03-20T10:15:30Z",
"user": "user_10086",
"action": "DELETE",
"resource": "/api/orders/98765",
"result": "SUCCESS"
}
JSON 的优点在于灵活——schema 可以随时加字段。但膨胀率惊人:同样的数据,JSON 比二进制大 2~4 倍,而且解析需要做 JSON parse,比文本行解析还慢。
我在项目中遇到过极端情况:某个服务改了一版接口,把日志里的 `resource` 字段从字符串改成了嵌套对象,导致下游日志解析全部挂了。JSON 的自由是一把双刃剑。
格式对比汇总
| 格式 | 存储体积(相对) | 解析速度 | 人类可读 | Schema 灵活性 | 推荐场景 |
|---|---|---|---|---|---|
| 文本行 | 大 | 慢 | 高 | 低 | 开发调试、小规模日志 |
| 二进制 | 小 | 快 | 低(需工具) | 低(Schema 固定) | 高吞吐、长期存储、性能敏感 |
| JSON | 很大 | 慢(解析成本高) | 中(可格式化查看) | 高 | 多团队协作、快速迭代 |
避坑指南: 不要在生产环境直接用 JSON 做百万级日志的实时检索,否则 CPU 和内存成本会让你怀疑人生。我曾经犯过这个错——上线第一天就把日志存储节点的 GC 时间打到了 30% 以上。
传统存储的整体架构图
下面这张图梳理了文件与数据库两种模式,以及各自适用的格式和索引构建方式。你后续学索引优化时,会发现几乎所有优化手段都从这里出发。
你会发现,不管是文件还是数据库,下一步都要建索引。但建索引的方式完全不同——文件模式索引是自己写的“外挂”,数据库模式索引是内置的。后面的章节会深入这两种索引的实现细节。
嗯,这一节内容比较多,但都是基础。你把这几个概念理清了,后面讲索引优化时才不会迷糊。我建议你回头看看那个对比表格,尤其是“文件 vs 数据库”和“格式对比”,平时选型直接照搬就行。