写入与近实时刷新
用途:解释“刚写入为什么搜不到”,并优化写入吞吐
写路径
「写路径」小节链接1 请求路由到主分片2 写入内存 buffer + 事务日志 translog(fsync 策略可配)3 每隔 refresh_interval(默认 1s)生成一个新段(segment)并使其可搜 → 近实时4 buffer 满或 flush 时把段持久化,translog 截断5 后台 merge 合并小段,删除标记的文档真正回收关键结论:ES 是近实时(NRT)而非实时。refresh 只让段可搜,不代表持久化;持久化靠 translog 与 flush。
“刚写的数据查不到”的正确处理
「“刚写的数据查不到”的正确处理」小节链接- 业务需要读己之写:从数据库读,或写入后按
_idget(get 走 translog/段,实时)。 - 需要强制可见:
refresh=wait_for(等待下次 refresh)或refresh=true(立即 refresh,代价高,禁止在批量写入时使用)。 - 搜索场景可接受 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 权威指南》写入调优章节