业务要求商品修改后 1 秒内可搜索,你会怎么解释 ES 的近实时并设计刷新策略?
先说结论:文档写入后先进入内存缓冲并记录 translog,refresh 会把缓冲内容形成新的 Lucene segment 并打开搜索视图,因此搜索通常要等下一次 refresh 才可见。这个秒级间隔使 Elasticsearch 被称为近实时搜索。
我先给结论,再说明它在项目里解决什么问题。理解 refresh、flush、translog 和 segment merge 的不同职责。文档写入后先进入内存缓冲并记录 translog,refresh 会把缓冲内容形成新的 Lucene segment 并打开搜索视图,因此搜索通常要等下一次 refresh 才可见。这个秒级间隔使 Elasticsearch 被称为近实时搜索。 refresh 不是把所有数据持久化到磁盘的同义词,flush 与 translog 生命周期相关,merge 则合并小 segment 并清理删除标记。
核心机制我会按一次真实执行过程来讲。沿着「请求写入主分片 → 写 translog 与内存 buffer → refresh 生成可搜索 segment → 查询新 Searcher → 后台 flush/merge 持久化整理」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 请求写入主分片 写请求成功先表示主分片与约定副本已接受操作,不等于普通搜索立即可见。
实现细节只抓关键入口,不会整段背源码。InternalEngine#refresh:Searcher 切换。 segments/stats:Segment 与 refresh。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。
放到生产使用时,我会关注参数和验证数据。写后分别 GET、search、refresh=waitfor,测可见延迟和小 Segment 数。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「segment 数」为主基线,记录值应满足「记录稳态基线」;同时保存 refresh latency/count、segment 数量,使后续变化能够回到同一时间轴比较。
最后补充常见误区和使用边界。写接口返回后前端立即走 search,refresh 尚未发生。把强一致回显改为按 ID GET,列表接受一秒内可见;管理操作必要时使用 refresh=waitfor,而不是每次强制 refresh。 把 refresh 当 fsync 持久化:refresh latency/count:读自己写用 GET。 方案:更适合的场景:主要收益:代价与边界。 默认周期 refresh:普通搜索可接受秒级延迟:写入吞吐平衡:写后立即搜索可能不可见。 refresh=waitfor:少量写后搜索必须可见:不主动制造额外 refresh:等待当前刷新周期增加响应延迟。 refresh=true:测试或极低频管理操作:立即可搜索:每次写生成小 segment,吞吐差。