省掉千余台机器:广告索引压缩实战
2020 年是广告系统成本优化最激进的一年。我负责的索引压缩项目累计节省了数百G内存(千余台物理机)。这篇文章聊具体怎么做。
成本分析:内存花在哪了?
广告系统的数据分两类:
| 数据类型 | 占比 | 特点 |
|---|---|---|
| 倒排索引 | 55% | 稀疏结构,可高度压缩 |
| 正排数据 | 35% | 稠密字段,压缩空间小 |
| 模型/特征 | 10% | 基本不可压缩 |
倒排索引是压缩的头号目标。
压缩策略
1. 倒排链用 PForDelta + SIMD
原始的倒排链存完整 int32 docID,一条链可能有几十万条。改用差值编码后大部分差值能用 4-8 bit 表示。
// 解码时用 SIMD 一次性解压 128 个值
__m128i block = _mm_loadu_si128((__m128i*)compressed_data);
__m128i decoded = _mm_add_epi32(base, block);
SIMD 解压比标量解压快 3-5x,刚好抵消解压开销。
2. 正排字段按需加载
正排(广告标题、描述、落地页 URL 等)占用 35% 内存。但不是所有字段在每次请求中都用得到。
我们把正排拆成三层:
- L1(热数据):质量分、出价、预算——每次请求必用,全内存
- L2(温数据):标题、描述——召回时用,按需从共享内存加载
- L3(冷数据):完整素材——仅在确定要展示时加载
L2/L3 用 mmap 映射,操作系统来管理换入换出。
3. 字段级去重
大量广告主会批量创建相似广告(改个标题再投一次)。相同落地页、相同行业的广告,描述文本高度重复。
我们做了字段级全局去重:相同内容的字段(如落地页 URL)只存一份,索引里存指针。
效果:减少了约 15% 的正排内存。
整体效果
| 优化项 | 内存节省 |
|---|---|
| 倒排 PForDelta + SIMD | 约30% |
| 正排分层按需加载 | 约25% |
| 字段级去重 | 约15% |
| 其他 | 约10% |
| 合计 | 显著 |
千余台物理机撤下来后,季度成本明显下降。