4、索引更新策略:全量重建与增量更新、实时索引与近实时索引、合并策略
索引建好了,数据却一直在变。这是搜索引擎运维里最让人头疼的事。
我记得刚接手一个电商搜索系统时,每天凌晨都要跑全量重建,耗时四五个小时。业务方抱怨说,商品价格改了,用户搜到的还是旧价格。嗯,这其实就是索引更新策略没选对。
今天咱们就聊聊这个话题。说白了,就是怎么让索引跟上数据变化的节奏。
4.1 全量重建 vs 增量更新
先讲最基础的两个策略。全量重建,就是把所有数据重新捞一遍,从头建索引。增量更新,则是只处理新增或变化的数据。
全量重建,我习惯叫它「笨办法但最稳」。为什么?
- 索引结构最干净,没有碎片
- 不会出现数据不一致
- 适合数据量不大、更新不频繁的场景
但缺点也明显。数据量一大,全量重建就是噩梦。我在项目中遇到过,一个亿级文档的索引,全量重建要跑6小时。这期间用户搜到的都是旧数据。
增量更新,说白了就是只处理变化的部分。
- 速度快,秒级甚至毫秒级
- 资源消耗小
- 适合高频更新的场景
但增量更新有个坑——删除操作。你想想看,文档删除了,但它在旧索引段里还留着。搜索引擎不会立即感知到。我曾经踩过这个坑,用户搜到了已下架的商品,点进去404。这体验太差了。
我的建议:全量重建和增量更新不是二选一。实际生产中,我通常这样搭配:
- 日常用增量更新,处理实时变化
- 每周或每月做一次全量重建,清理碎片、修复不一致
4.2 实时索引 vs 近实时索引
这两个概念容易混淆。我简单解释一下。
实时索引:数据一变,索引立刻更新。用户马上能搜到。
近实时索引:数据变了,但索引不是立刻更新,而是延迟几秒到几分钟。
为什么会这样?因为实时索引的成本太高了。
你想想看,每次数据变化都要立即更新倒排表、更新词典、更新统计信息。如果每秒有上万次更新,搜索引擎的CPU和IO直接被打满。
我见过一个极端案例:某社交平台做实时搜索,用户发帖后希望立刻被搜到。结果搜索引擎扛不住,查询延迟从10ms飙升到500ms。最后不得不改成近实时,延迟控制在3秒以内,用户体验几乎没差别,系统却稳多了。
| 特性 | 实时索引 | 近实时索引 |
|---|---|---|
| 延迟 | 毫秒级 | 秒级到分钟级 |
| 资源消耗 | 极高 | 中等 |
| 适用场景 | 金融交易、监控告警 | 电商、内容搜索 |
| 实现复杂度 | 高 | 低 |
避坑指南:我曾经在电商搜索里强行上实时索引,结果大促期间系统直接挂了。后来改成近实时,延迟设了5秒。用户根本感知不到,系统却稳如老狗。所以,别为了「实时」而实时,够用就好。
4.3 合并策略
增量更新会产生很多小索引段。每个段都是一个独立的索引文件。段越多,查询时合并结果的开销越大。
合并策略,说白了就是怎么把这些小段合并成大段。
常见的合并策略有三种:
- 按大小合并:小段优先合并,大段不动。适合写入量稳定的场景。
- 按时间合并:定期合并,比如每小时合并一次。适合有明确时间窗口的场景。
- 按文档数合并:段内文档数达到阈值就合并。适合文档大小不均匀的场景。
我个人的习惯是,用按大小合并为主,辅以定时触发。
举个例子,Elasticsearch 的合并策略就很有意思。它默认用 tiered 策略,说白了就是按大小分层合并。小段先合并成中等段,中等段再合并成大段。这样能避免大段频繁被合并,减少IO开销。
// 伪代码示例:合并策略配置
{
"merge": {
"policy": "tiered",
"segments_per_tier": 10, // 每层最多10个段
"max_merged_segment": "5GB", // 单段最大5GB
"max_segments": 50 // 最多保留50个段
}
}
注意:合并操作非常消耗IO。我见过有人把合并线程数设得过高,结果磁盘IO被打满,查询延迟飙升。建议合并线程数不要超过CPU核数的一半。另外,合并期间要监控磁盘使用率,避免磁盘写满。
4.4 实战中的取舍
讲了这么多,其实核心就一句话:没有银弹。
我总结了一个决策树,你可以参考:
- 数据量小(百万级)→ 全量重建就够了,别折腾
- 数据量大但更新少 → 全量重建 + 定时增量
- 数据量大且更新频繁 → 增量更新 + 近实时 + 定期全量重建
- 对实时性要求极高 → 实时索引 + 内存索引 + 异步落盘
最后说一句,索引更新策略不是一劳永逸的。业务在变,数据在变,策略也得跟着调。我每年都会复盘一次索引策略,看看有没有优化的空间。
嗯,这一章就到这里。下一章咱们聊聊索引的存储结构,那才是真正决定性能的地方。