五百台设备,每天原始日志四个 G,一年下来存储加流量是笔不小的钱。这篇文章写我们怎么把它压到每天三百兆,而排障能力反而变强的过程。
先说要解决什么问题。设备日志的用途只有两个:出事时回溯,以及看趋势做优化。前者要完整不能缺,后者要聚合不需要明细。搞清楚这两件事,很多钱就省下来了。
一、分级:不是所有日志都值钱
最开始我们把所有级别的日志全量上云,包括海量的 INFO 心跳、轮询记录。实际统计下来,真正被查过的日志不到总量的千分之一。
现在的分级规则是:ERROR 和 FATAL 全收,一条不漏;WARN 按百分之十采样,但同一条错误码每小时最多保留二十条;INFO 只在开关打开时上传,默认关闭,需要现场排查时由运维远程打开;DEBUG 永远不上云。
采样有一个坑必须注意,采样率写死会导致偶发问题永远采不到。我们的做法是错误码首次出现必定采样,后续再按比例。这样新问题不会漏,重复问题不会淹。
二、结构化:别传一行字符串
原来每条日志是一整行文本,时间、设备、模块、错误码全混在里面,到了云端还得用正则解析。解析脚本一改,历史数据就对不上。
改成结构化之后,固定字段是时间戳、设备号、模块、级别、错误码、耗时,可变部分放在一个消息字段里。好处有三个:云端不用解析,查询走索引,聚合能直接按错误码统计。
体积上也有收益。一行文本平均一百八十字节,结构化后同样信息一百一十字节左右,压缩率还更高,因为字段值重复度高。
三、压缩与批量:两个动作省一半
日志是高度重复的文本,zstd 一级压缩通常能到六比一,比 gzip 又快又小。我们在网关侧就压,不压缩的数据不出设备。
批量上报的策略是六十秒或者一兆字节,先到先发。单条上报的协议开销比数据本身还大,改成批量之后,传输层的开销摊薄到几乎可以忽略。
这两件事叠加,四个 G 降到六百兆左右。后面还有一步是去重:同一设备同一错误码一分钟内重复出现的,只留第一条加计数。这一步又掉了一半,因为现场大量日志是同一条错误在一秒内刷了几十遍。
四、冷热分层:问题不会等三年才查
日志的访问规律非常集中,百分之九十的查询发生在七天以内。所以我们做三层:七天内放热存储,支持全文检索;七到九十天转温存储,只保留结构化字段和摘要;九十天以上归档到对象存储,压缩包按天存放,需要时再解冻。
这套分层让主库的容量压力降了一个数量级,查询速度反而更快,因为主库不再被冷数据拖累。
有个反例是我们最早做的"全量保留一年",看起来很安全,实际结果是查询变慢、成本变高、没人用。归档层的存在不是为了合规好看,是为了让热层能一直快。
五、成本账:从四个 G 到三百兆
按我们的实际数字:原始四个 G,分级采样后一点二 G,结构化加压缩后六百兆,批量加去重后三百二十兆。存储成本降到原来的十二分之一,流量成本降到十五分之一。
同时排障效率提升了,因为结构化之后可以按设备号、错误码、时间窗三维查询,原来只能全文搜关键词。有一次现场偶发通信中断,按错误码过滤三分钟就定位到是某个批次的电源模块在低温下复位。
六、几条经验
日志分级要按"谁在什么场景下会看"来定,不是按代码里写什么级别。
采样必须有首次必采的规则,否则偶发问题永远查不到。
结构化字段宁可少而稳,不要多而变,字段一改历史数据就断档。
压缩和批量要在设备侧做,不要指望云端省。
冷热分层的关键是让热层保持小,归档层只是兜底。
最后一句,日志系统的价值不在存了多少,而在出事时能不能三分钟内给出答案。按这个标准设计,成本自然会降下来。