跳转到内容

写入与近实时刷新

用途:解释“刚写入为什么搜不到”,并优化写入吞吐

1 请求路由到主分片
2 写入内存 buffer + 事务日志 translog(fsync 策略可配)
3 每隔 refresh_interval(默认 1s)生成一个新段(segment)并使其可搜 → 近实时
4 buffer 满或 flush 时把段持久化,translog 截断
5 后台 merge 合并小段,删除标记的文档真正回收

关键结论:ES 是近实时(NRT)而非实时。refresh 只让段可搜,不代表持久化;持久化靠 translog 与 flush。

“刚写的数据查不到”的正确处理

「“刚写的数据查不到”的正确处理」小节链接
  1. 业务需要读己之写:从数据库读,或写入后按 _id get(get 走 translog/段,实时)。
  2. 需要强制可见:refresh=wait_for(等待下次 refresh)或 refresh=true(立即 refresh,代价高,禁止在批量写入时使用)。
  3. 搜索场景可接受 1 秒延迟:不要为此调小 refresh_interval(会制造大量小段,拖慢查询与合并)。
手段 说明
_bulk 批量 单批 5-15MB 起压测调优,避免过大导致队列拒绝
关闭副本导入 大批量导入时 number_of_replicas: 0,完成后恢复
refresh_interval: -1 导入期间关闭 refresh,完成后恢复
translog 异步 fsync index.translog.durability: async + sync_interval,吞吐提升,宕机可能丢几秒
合理 index sorting / 关闭不需要的打分 减少段开销
避免自动生成 _id 自定义 ID 可做版本控制与幂等(op_type=create)
客户端并发与队列 监控 429 es_rejected_execution_exception,做退避重试

ES 不原地更新:更新 = 标记旧文档删除 + 索引新文档;因此频繁局部更新会造成大量已删除文档堆积,段合并压力上升、查询变慢。

优化方向:

  • 能用 append-only 模型就用新文档 + 别名切换。
  • 局部字段变更考虑 update_by_query 的代价(它会重写文档),或改为把易变字段放数据库、ES 只存检索字段。
  • 监控 docs.deleted 与段数量,必要时手工 _forcemerge(只读索引上做,滚动索引场景慎用)。
  • 外部版本或 if_seq_no + if_primary_term 实现乐观并发,避免“后写覆盖先写”。
  • 数据同步链路(binlog → ES)必须按实体串行或带版本判断,否则乱序会让 ES 落后于 DB。
误区 修正
批量写入时每条都 refresh=true 段爆炸,写入与查询同时劣化
调小 refresh_interval 到 100ms 追求实时 同上,1s 是合理折中
认为 refresh = 落盘 持久化靠 translog/flush
高频局部更新 删除文档堆积,考虑改数据模型
同步链路不带版本 乱序覆盖导致 ES 与 DB 长期不一致
无限增大 bulk 体积 线程队列拒绝与内存压力
  • Elasticsearch 官方文档:Near real-time search、Translog、Index modules settings
  • 《Elasticsearch 权威指南》写入调优章节