日志存储与索引:分布式存储、倒排索引、时间序数据库选型

日志存好了,查不了——这算哪门子审计?

我做密文检索系统那会儿,第一次上线就栽在存储选型上。日志量一天暴涨到几百GB,传统单机MySQL直接崩了。嗯,从那天起我就明白了:存储和索引不是事后补的,必须从一开始就规划清楚。

分布式存储——日志不丢、不糊

密文检索的审计日志有什么特殊之处?

  • 写密集:每条请求、每个密钥操作、每次解密尝试,都得记下来。
  • 几乎不修改:审计日志是append-only模式,不会回头改。
  • 冷热分层:近期的日志查得勤,三个月前的可能一年才翻一次。

我个人习惯的做法是:

  1. 热数据放在SSD集群(推荐Ceph或MinIO对象存储打底)。
  2. 冷数据压缩后迁到廉价机械盘或归档存储。
  3. 元数据用分布式KV(比如TiKV或RocksDB集群)管理。
避坑提醒: 对象存储的单桶文件数别超过千万级,否则list性能直线下降。我曾经吃过这个亏,后来强制按小时分桶才稳住。

倒排索引——密文搜索的加速器

你想想看,审计员要搜一条“用户A在昨天14:00到底访问了哪个密钥?”

如果没有倒排索引,得扫全量日志,几千万行啊。

倒排索引的核心思路很简单:

  • 对每条日志的关键字段(用户ID、操作类型、时间戳)提取词条。
  • 建立一个词条 → 文档列表的映射。
  • 密文场景下,字段值本身是加密的,所以我们还要额外存一个明文指纹(比如SHA256+随机盐)作为索引键。
⚠ 注意: 指纹索引只能支持精确匹配,不支持模糊查询。如果需要范围或前缀搜索,就得结合其他方案——后面我会讲。

我记得有一次用户反馈查询太慢,排查发现倒排索引的存储没有做压紧(compaction)。冗余段太多,I/O全耗在合并上了。每天凌晨跑一次强制合并,问题就解决了。

时间序数据库选型——谁更合适?

审计日志本质上就是时间序列数据。选TSDB的时候,我列过一张表:

特性InfluxDBTimescaleDBClickHouse
写入吞吐高(约100万点/秒/节点)中(基于PostgreSQL)极高(列式存储,可达数百万行/秒)
压缩率中等(~8x)中等(~5x)优秀(~10x)
密文兼容需自定义字段映射支持二进制字段,方便字符串/二进制都行
运维复杂度较低,单机模式简单中等,依赖PG主从较高,需配置ZK
典型场景监控指标金融日志海量审计日志

我现在的团队,90%的审计日志都跑在ClickHouse上。原因很简单:它原生支持物化视图和采样查询。采样查询对于巡检特别有用——你不用全扫,只扫1%的行就能定位异常。嗯,这在密文场景下能大幅降低解密开销。

整体架构怎么搭?

下面这张图,就是我在多个项目里沉淀下来的日志存储与索引决策结构。

日志存储与索引选型架构 密文审计日志流 日志分发器(Kafka) 倒排索引构建 (指纹+词典) 热存储(SSD) ClickHouse / TiKV 冷归档(压缩) 对象存储/磁带 审计查询引擎(合并索引+扫描) 巡检 / 告警 / 审计报告 说明:灰色虚线表示按需拉取冷数据;实线为实时流。倒排索引默认只建热数据,冷数据按需重建。
实战要点:
  • 倒排索引建议用内存+SSD两级:常查的热词放内存,冷词落盘。我就是靠这个把P99查询耗时从3秒压到了200毫秒。
  • 冷数据的压缩算法我推荐ZSTD,速度比Gzip快2倍,压缩率接近。尤其是密文字段本身混乱度高,ZSTD的收益更明显。
  • 如果审计日志需要跨区域容灾,记得在分发器(Kafka)层就做副本复制,不要在存储层搞异步同步——后者容易丢数据。

最后说一句:没有完美的存储方案,只有当下最合适的组合。你到时候做选型,拿上面这张表做个对照,多半能避开我踩过的坑。嗯,今天先聊到这儿。