Elasticsearch 中Refresh 和 Flush的区别?
在 Elasticsearch 中,Refresh 和 Flush 是两个非常关键但容易混淆的概念。简单来说,它们的区别在于:
- Refresh(刷新): 解决的是数据 “可见性” 问题(让数据可以被搜索到)。
- Flush(冲刷): 解决的是数据 “持久化” 问题(将数据真正写入磁盘,防止丢失)。
为了深入理解,我们需要了解 Elasticsearch(基于 Lucene)写入数据的流程。
1. 核心流程图解
当一个文档被写入 ES 时,流程如下:
- 写入 Buffer & Translog: 数据首先被写入内存缓冲区(Memory Buffer),同时追加到事务日志(Translog)中(为了防止断电数据丢失)。
- Refresh(变为可搜索): 默认每 1 秒,ES 会将 Memory Buffer 中的数据生成一个新的 Lucene Segment,并放入 文件系统缓存(Filesystem Cache) 中。
- 此时:数据可以被搜索到了,但还在内存中,没有真正落盘。
- Flush(变为持久化): 当 Translog 达到一定大小或时间(默认 30 分钟),会触发 Flush。ES 会执行
fsync将文件系统缓存中的 Segment 写入物理磁盘,并清空 Translog。- 此时:数据安全地存储在磁盘上了。
2. 深度解析:Refresh
定义:
Refresh 操作是将内存缓冲区(Memory Buffer)中的文档生成一个新的 Lucene Segment,并将其打开以供搜索的过程。
- 目的: 实现 近实时搜索(Near Real-Time, NRT)。
- 发生了什么:
- Memory Buffer 被清空。
- 一个新的 Segment 被创建在操作系统的 Filesystem Cache 中(注意:此时还没有
fsync到物理磁盘)。 - 该 Segment 被打开,使得里面的文档可以被搜索查询。
- 触发时机:
- 默认每 1 秒自动触发一次(由
index.refresh_interval控制)。 - 当 Memory Buffer 满了时。
- 手动调用
_refreshAPI。
- 默认每 1 秒自动触发一次(由
- 性能影响:
- Refresh 是有成本的(创建 Segment、打开文件句柄)。
- 优化建议: 在批量导入大量数据时,建议将
refresh_interval设置为-1(关闭自动刷新)或调大时间,导入完成后再改回来,能显著提高写入速度。
3. 深度解析:Flush
定义:
Flush 操作是将文件系统缓存中的数据强制写入物理磁盘(fsync),并执行 Lucene Commit,最后清空 Translog 的过程。
- 目的: 确保数据 持久化,释放 Translog 空间。
- 发生了什么:
- 内存中所有未落盘的 Segment 被强制
fsync到物理磁盘。 - 写入一个 Commit Point 文件,标记这次提交。
- Translog 被清空/截断(因为数据已经安全落盘,不再需要日志来恢复了)。
- 内存中所有未落盘的 Segment 被强制
- 触发时机:
- Translog 大小达到阈值(默认 512MB,
index.translog.flush_threshold_size)。 - 距离上次 Flush 的时间达到阈值(默认 30 分钟)。
- 手动调用
_flushAPI。
- Translog 大小达到阈值(默认 512MB,
- 性能影响:
- Flush 是非常昂贵的操作(涉及物理磁盘 IO)。
- 通常不需要手动干预,ES 会自动管理。
4. Translog 的作用(连接 Refresh 和 Flush 的桥梁)
你可能会问:既然 Refresh 只是把数据放到内存缓存里,那如果服务器断电了,数据岂不是丢了?
这就是 Translog 存在的意义:
- 数据写入时是 同步 写入 Translog 的(默认配置)。
- 即使 Refresh 后的数据还在内存(Filesystem Cache)中,如果此时断电,ES 重启后会重放 Translog 中的操作,将数据恢复回来。
- Flush 的作用就是“截断”Translog。一旦数据真正落盘(Flush),Translog 里的旧记录就可以删除了。
5. 总结对比表
| 特性 | Refresh (刷新) | Flush (冲刷) |
|---|---|---|
| 核心目标 | 可见性 (Visibility) | 持久性 (Durability) |
| 操作对象 | Memory Buffer -> Filesystem Cache | Filesystem Cache -> Physical Disk |
| Lucene 动作 | Reopen (打开新段) | Commit (提交并 fsync) |
| Translog | 不影响 Translog | 清空/截断 Translog |
| 搜索实时性 | 决定了数据多久能被搜到 (默认 1s) | 不直接影响搜索可见性 |
| 物理落盘 | 否 (数据仍在 OS Cache) | 是 (执行 fsync) |
| 性能开销 | 中等 (频繁发生) | 高 (低频发生) |
| 常见调优 | 批量写入时调大或关闭 | 一般保持默认,极少手动触发 |
一句话总结:
Refresh 让你能搜到刚写进去的数据(近实时),而 Flush 确保数据真正写到硬盘上(不丢失)。