Skip to content

存储原理与Segment

存储架构

┌─────────────────────────────────────────┐
│           ES写入流程                     │
├─────────────────────────────────────────┤
│                                          │
│  文档 ──→ Buffer ──→ Translog ──┐       │
│                      │          │       │
│                      │     ─────▼─────┐
│                      │     │ refresh   │       │
│                      │     └─────┬─────┘       │
│                      │           │              │
│                      │      ┌────▼────┐         │
│                      │      │Segment │         │
│                      │      │ (.liv) │         │
│                      │      └────────┘         │
└─────────────────────────────────────────┘

Segment结构

Lucene索引结构

Index

  ├─ _1.fdt  (Document数据)
  ├─ _1.fdx  (Document索引)
  ├─ _1.fnm  (Fields信息)
  ├─ _1.fdt  (Term字典)
  ├─ _1.tip  (Term索引)
  ├─ _1.doc  (Posting列表)
  ├─ _1.pos  (位置信息)
  ├─ _1.pay  (载荷信息)
  └─ _1.liv  (Live文档标记)

Segment文件说明

文件说明
.fdt文档数据
.fdx文档索引
.fnmFields信息
.fdtTerm字典
.tipTerm索引
.docPosting列表
.pos位置信息
.pay载荷信息
.livLive文档标记

Segment特点

  • 不可变性:Segment生成后不可修改
  • 合并机制:后台合并小Segment
  • 删除逻辑:.liv标记删除

写入流程

1. 写入Buffer

┌─────────────────────────────────┐
│          写入流程               │
├─────────────────────────────────┤
│                                  │
│  1. 写入Memory Buffer           │
│     (同时写入Translog)          │
│                                  │
│  2. refresh (默认1s)           │
│     Buffer → Segment (.liv)      │
│     清空Buffer                  │
│                                  │
│  3. flush (默认30m或512MB)     │
│     Segment → 磁盘               │
│     删除Translog                │
│                                  │
└─────────────────────────────────┘

2. Translog

json
// Translog配置
{
  "index": {
    "translog": {
      "sync_interval": "5s",
      "size": "512mb",
      "durability": "async"
    }
  }
}
参数说明
sync_interval同步间隔(默认5s)
sizeTranslog大小
durability同步模式(request/async)

3. flush

时机:
- 30分钟
- 512MB
- Translog太大

refresh vs flush

操作作用开销
refresh写入Buffer到Segment��可搜索
flush写入Segment到磁盘,清理Translog高(I/O)

删除与更新

删除逻辑

写入时:.liv = [0, 1, 1, 0]
删除doc 2:.liv = [0, 1, 0, 0](标记删除)

合并时:清理.liv=0的文档,真正删除

更新逻辑

1. 文档标记为删除(.liv=0)
2. 新文档写入新Segment

合并Segment

json
// 手动合并
POST /my_index/_forcemerge
{
  "max_num_segments": 1
}

// 定期合并
{
  "index": {
    "merge": {
      "scheduler": {
        "max_thread_count": 1
      }
    }
  }
}

面试考点

Q: 为什么Segment不可修改?

  • 写入优化:顺序写,提高性能
  • 方便合并:无需随机删除
  • 缓存友好:无需维护更新状态

Q: refresh默认1s能改吗?

json
PUT /my_index/_settings
{
  "refresh_interval": "-1"  // 关闭
  // "refresh_interval": "10s"  // 10秒
}

Q: 删除的文档占空间吗?

  • 查询时跳过(.liv标记)
  • 合并时清理

Q: 为什么ES是近实时?

  • refresh 1s写入Buffer到Segment
  • flush 30m持久化到磁盘

Q: Translog作用?

  • 保证数据不丢失
  • 恢复未flush的数据

最后更新: