Elasticsearch(简称ES)服务器本质上是把数据以倒排索引为核心结构存储在本地磁盘上,底层依赖Lucene库完成读写。你写入的每一条JSON文档,最终都会被拆解、转换并落盘为Lucene的段(Segment)文件,ES并不是直接把原始数据原封不动存进硬盘,而是经过一系列分析、分词、排序后,生成一套专为快速检索设计的文件体系,这套存储机制决定了ES在全文搜索场景下的高性能,也带来了它在数据更新和存储成本上的特殊表现。
es服务器是以什么方式存储的:先理解倒排索引这个“目录册”
要搞清ES的存储方式,倒排索引是绝对绕不开的第一课,你可以把ES想象成一个图书管理员,他不会每次找内容都从头翻书,而是提前准备了一本“关键词目录册”,这本目录册记录了每个词出现在哪些文档的哪个位置。
正向索引与倒排索引的区别
传统关系型数据库(比如MySQL)用的是正向索引:一行数据对应多个字段值,查询时扫描整张表或用B+树定位行记录,而ES的倒排索引反其道而行之:以“词条”为入口,映射到包含该词条的文档ID列表。
举个例子,你存了两条文档:
- 文档1:“北京欢迎你”
- 文档2:“欢迎来北京”
ES存储时会把文本拆成词条:“北京”“欢迎”“你”“来”,倒排索引表大致长这样:
| 词条 | 文档ID |
|---|---|
| 北京 | 1, 2 |
| 欢迎 | 1, 2 |
| 你 | 1 |
| 来 | 2 |
当你搜索“北京”,ES直接查词条“北京”对应的文档列表,瞬间返回文档1和2,这种结构让亿级数据下的搜索依然能保持毫秒级响应。
Lucene:ES存储的“地基”
ES本身不负责存储实现,它把这块脏活累活交给了Apache Lucene一个高性能的Java全文检索库,行业共识认为,Lucene的索引文件格式是ES存储性能的根基,ES通过封装Lucene的API,对外提供RESTful接口,但对内,所有数据最终都以Lucene定义的文件格式写入磁盘。
在Linux服务器上,你可以通过lsof命令或查看/usr/share/elasticsearch/data目录,看到一堆以.fdt、.fdx、.tim、.tip、.doc等后缀结尾的文件,这些就是Lucene的存储产物:
.fdt:存储文档的原始字段值(用于结果展示).fdx:字段值的位置索引.tim:词条字典(Term Dictionary).tip:词条字典的索引指针.doc:倒排列表(Postings),记录文档ID和词频
es索引存储结构拆解:分片、副本与段文件

了解了底层文件类型,下一步要看ES如何组织这些文件,ES存储的最小逻辑单元叫分片(Shard),而每个分片就是一个完整的Lucene索引。
为什么ES要把索引拆成分片
假设你有一个索引“products”,包含1000万条商品数据,ES默认会创建5个主分片,每个分片存储约200万条数据,这些分片可以分布在集群的不同节点上,这样做的好处是:
- 水平扩展:数据量增大时,增加节点并重新分配分片即可
- 并行处理:搜索请求会广播到所有分片,并行执行后合并结果
每个主分片还可以配置副本分片,默认情况下,每个主分片配1个副本,副本不仅提供高可用(主分片挂了副本顶上),还能分摊读请求压力,但注意,副本是完整的数据拷贝,会占用双倍磁盘空间。
段(Segment):真正落盘的文件单元
分片内部,数据并不是一次性写入一个大文件,而是被拆成多个段,每个段都是一个独立的Lucene索引文件集合,包含倒排索引和文档值。
写入流程是这样的:
- 新文档先进入内存缓冲区,同时写入translog(事务日志)
- 缓冲区满(默认1秒或堆内存的10%),触发refresh,生成一个新段
- 段先缓存在文件系统缓存中,随后通过fsync刷盘
- 随着写入增多,后台线程会将小段合并成大段(Segment Merge)
段的设计让ES写入无需随机IO,而是顺序追加,这极大提升了写入吞吐量,但代价是删除和更新操作不会立即物理删除旧数据,只做标记,等段合并时才真正清理,所以你会发现,频繁更新数据的ES索引,磁盘占用会持续增长,直到合并完成才回落。
translog:防止数据丢失的保险丝
translog是ES存储里容易被忽视但极其关键的部分,它记录所有未刷盘的操作,类似于MySQL的binlog,如果节点宕机,ES重启时会重放translog,恢复内存中尚未落盘的数据。
默认配置下,translog在每次请求后都会fsync到磁盘,这保证了数据的实时持久性,对于追求更高写入性能的场景,可以调整index.translog.durability为async,但这样会牺牲一定的数据安全。
es数据持久化过程:从写入到可搜索的完整链路
理解了文件构成,再看看一条数据从POST请求到磁盘存储的完整路径,这能帮你更直观地认识ES的存储机制。
写入阶段:实时性 vs 持久性的权衡
当你向ES发送索引请求:
- 节点计算文档所属分片(通过
routing字段哈希) - 写入主分片的translog
- 文档进入内存缓冲区
- 默认1秒后,缓冲区数据生成段,变为可搜索状态
- translog达到阈值(512MB或30分钟)时,触发flush,所有段强制fsync落盘

这意味着,刚写入的文档在1秒内是搜索不到的,但不会丢失(因为translog已持久化),这个机制常被称为近实时搜索。
更新与删除:标记+合并的“懒汉策略”
ES的文档是不可变的,所谓更新,其实是“写入新文档+标记旧文档删除”,删除操作同样只是打上删除标记,这些标记会在段合并时真正生效,释放磁盘空间。
实际操作中,如果你发现ES存储占用异常增大,可以执行POST /index/_forcemerge手动触发段合并,但要注意这会占用大量IO资源,建议在业务低峰期操作。
es存储配置实操:数据目录、磁盘水位与冷热分离
对于运维人员,了解存储方式之后,更关心的是如何配置和管理存储空间。
设置数据存储路径
ES的数据目录在elasticsearch.yml中通过path.data配置,默认是$ES_HOME/data,生产环境建议将path.data指向独立的数据盘(如挂载的SSD),避免和系统盘混用导致IO争抢。
path: data: /data/es-data logs: /var/log/elasticsearch
修改后需要重启ES节点,并且确保新目录属主为elasticsearch用户,否则会启动失败。
磁盘水位线:防止“撑爆”硬盘
ES为了保护集群稳定,内置了磁盘水位线机制,在elasticsearch.yml中配置:
cluster.routing.allocation.disk.watermark.low:默认85%,低于此值不再分配新分片cluster.routing.allocation.disk.watermark.high:默认90%,触发后节点尝试迁移分片cluster.routing.allocation.disk.watermark.flood_stage:默认95%,强制将索引设为只读
如果出现disk watermark exceeded报错,说明存储快满了,此时应清理数据或扩容磁盘,必要时用PUT /_cluster/settings临时调整水位线。
冷热节点架构:降低存储成本的常见方案
对于日志类时序数据,不是所有数据都需要高性能检索,行业里常见的做法是部署冷热分离架构:
- 热节点:使用SSD,存储近7天的活跃数据,响应高频查询
- 温节点:使用SATA盘,存储近30天的数据
- 冷节点:使用大容量机械盘,存储历史归档数据
通过索引生命周期管理(ILM)策略,索引会随着时间推移自动从热节点迁移到冷节点,设置一个策略:索引创建后7天从热节点滚动到温节点,30天后迁移到冷节点并缩减副本数,这样既保证了查询性能,又大幅降低了存储成本。
es存储常见问题排查:段合并、堆外内存与磁盘IO
实际运维中,ES存储相关的问题往往集中在性能瓶颈上,以下三个场景是排查重点。

段数量过多导致查询变慢
段过多会增加文件句柄占用,并让查询时需要遍历更多段,通过GET /_cat/indices?v查看每个索引的docs.count和store.size,如果段数明显异常,可以执行:
POST /logs-2026.05/_forcemerge?max_num_segments=1
这个操作会把该索引的所有段合并为1个,显著提升查询效率,但合并期间IO压力大,务必错峰执行。
堆外内存与文件系统缓存
ES的存储性能高度依赖操作系统的文件系统缓存,Lucene读段时优先走内存映射(mmap),如果物理内存足够,大部分热数据会缓存在page cache中,磁盘IO很低,这也是为什么ES节点建议内存至少配置为总内存的一半给文件系统缓存。
如果发现磁盘读IO居高不下,往往说明内存不足或段合并频繁,此时检查JVM堆内存设置是否合理(一般不超过32GB),以及是否需要增加节点分担压力。
清理已删除文档释放空间
由于删除是“标记式”的,长时间运行的索引会积累大量死文档,用GET /_cat/segments?v查看段内num_docs和deleted_docs,如果删除比例超过30%,建议执行段合并强制清理:
POST /old-index/_forcemerge?only_expunge_deletes=true
注意,这个操作只合并含有删除标记的段,相对温和。
关于es存储方式的高频问答
es服务器数据存储原理适合哪些业务场景?
ES的存储机制是为全文检索、日志分析、APM监控这类“写多读少、查询条件复杂”的场景设计的,它不像MySQL那样擅长事务性更新,也不适合作为主数据库存储核心业务数据,如果你的需求是订单管理、账户余额这类强一致性的OLTP业务,ES并不是合适选择,倒排索引的优势在于快速定位,而非数据完整性保障。
es索引存储在哪里,是否支持外部共享存储?
ES的数据只能存储在节点本地磁盘,不支持像Oracle那样使用SAN或NFS共享存储,这是因为Lucene依赖本地文件系统的mmap和文件锁机制,网络文件系统会导致性能骤降甚至数据损坏,官方明确不建议将path.data放在NFS或SMB挂载点上,如果确实需要集中存储,只能通过快照和恢复功能定期备份到对象存储或HDFS。
如何评估es存储需要多少磁盘空间?
ES的实际存储开销通常是原始数据量的5到3倍,原因包括:
_source字段默认存储原始JSON文档,不可压缩- 倒排索引和doc values会额外占用空间
- 副本分片翻倍存储
- 段合并期间的临时空间需求
建议按“原始数据大小 × 副本数 × 2”来规划磁盘容量,同时预留20%的余量给段合并和系统开销,每天产生50GB日志,保留30天,1副本,那么存储需求约为50×30×2×2=6TB。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/922712.html


评论列表(2条)
这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是文档部分,给了我很多新的思路。感谢分享这么好的内容!
@cute688er:这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于文档的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!