文章目录
参考文献
Elasticsearch原理详解:https://blog.csdn.net/chuixue24/article/details/104022065
41张图了解Es原理:https://juejin.cn/post/6906430715731116045
Es中的概念介绍:https://juejin.cn/post/6908620596523827213#comment
Es全流程:https://juejin.cn/post/6972038748049670175
ElasticSearch原理知识点和整体结构详解:https://juejin.cn/post/6986480874137059341
Es方法论认知清单:https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484194&idx=1&sn=09fafbe34dc17a8bbe64919ac6be2662&chksm=eaa82b0adddfa21c8aa65b47f1c5b0a25c9ceaeb0ecc47055fd9c615d0f7a3fbfb6febee46e7&scene=21#wechat_redirect
原理涉及的概念
概念 | 意义 |
---|---|
Segment File | 分段,每个 Segment 事实上是一些倒排索引的集合 |
Commit | 将 Segment 合并,并写入磁盘 |
Commit Point | 记录着对每个 Segment 的操作 |
Translog | 提供所有还没有被刷到磁盘的操作的一个持久化纪录 |
Refresh | 刷新 |
Fsync | 刷磁盘,将 filesystem cache 中的所有 segment 刷新到磁盘的操作 |
Flush | 清理 |
Segment - 分段
Elasticsearch 存储的基本单元是 shard , ES 中一个 Index 可能分为多个 shard , 事实上每个 shard 都是一个 Lucene 的 Index ,并且每个 Lucene Index 由多个 Segment 组成, 每个 Segment 事实上是一些倒排索引的集合, 每次创建一个新的 Document , 都会归属于一个新的 Segment , 而不会去修改原来的 Segment ; 且每次的文档删除操作,会仅仅标记 Segment 中该文档为删除状态, 而不会真正的立马物理删除, 所以说 ES 的 index 可以理解为一个抽象的概念。es 每秒都会生成一个 segment 文件,当文件过多时 es 会自动进行 segment merge(合并文件),合并时会同时将已经标注删除的文档物理删除;
Commit - 提交
为了数据安全, 每次的索引变更都最好要立刻刷盘, 所以 Commit 操作意味着将 Segment 合并,并写入磁盘。保证内存数据尽量不丢。但刷盘是很重的 IO 操作, 所以为了机器性能和近实时搜索, 并不会刷盘那么及时。
Commit Point - 提交节点
记录当前所有可用的 segment ,每个 commit point 都会维护一个 .del 文件( es 删除数据本质是不属于物理删除),当 es 做删改操作时首先会在 .del 文件中声明某个 document 已经被删除,文件内记录了在某个 segment 内某个文档已经被删除,当查询请求过来时在 segment 中被删除的文件是能够查出来的,但是当返回结果时会根据 commit point 维护的那个 .del 文件把已经删除的文档过滤掉;
Translog - 持久化纪录
translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。为了防止 elasticsearch 宕机造成数据丢失保证可靠存储,es 会将每次的操作同时写到 translog 日志中。新文档被索引意味着文档会被首先写入内存 buffer ,操作会被写入 translog 文件。每个 shard 都对应一个 translog 文件;translog 会每隔 5 秒异步执行或者在每一个请求完成之后执行一次 fsync 操作,将 translog 从缓存刷入磁盘,这个操作比较耗时,如果对数据一致性要求不是跟高时建议将索引改为 async ,如果节点宕机时会有 5 秒数据丢失;
Refresh - 刷新
写入和打开一个新 segment 的轻量的过程,es 接收数据请求时先存入内存中,默认每隔一秒会从内存 buffer 中将数据写入 filesystem cache 中的一个 segment,内存 buffer 被清空,这个时候索引变成了可被搜索的,这个过程叫做 refresh;
Fsync - 刷磁盘
fsync 是一个 Unix 系统调用函数, 用来将内存 buffer 中的数据存储到文件系统. 这里作了优化, 是指将 filesystem cache 中的所有 segment 刷新到磁盘的操作;
Flush - 清理
es 默认每隔 30 分钟或者操作数据量达到 512mb ,会将内存 buffer 的数据全都写入新的 segment 中,内存 buffer 被清空,一个 commit point 被写入磁盘,并将 filesystem cache 中的数据通过 fsync 刷入磁盘,同时清空 translog 日志文件,这个过程叫做 flush;
数据写入过程 - 近实时搜索
提交(Commit)一个新的 segment 到磁盘需要一个 fsync 来确保 segment 被物理性地写入磁盘,这样在断电的时候就不会丢失数据。 但是 fsync 操作代价很大; 如果每次索引一个文档都去执行一次的话会造成很大的性能问题。我们需要的是一个更轻量的方式来使一个文档可被搜索,这意味着 fsync 要从整个过程中被移除。在 es 和磁盘之间是 filesystem cache 。 像之前描述的一样, 在内存缓冲区中的文档会被写入到一个新的段中。 但是这里新段会被先写入到文件系统缓存,这一步代价会比较低,稍后再被刷新(flush)到磁盘,这一步代价比较高。不过只要文件已经在 filesystem cache 中, 就可以像其它文件一样被打开和读取了。Lucene 允许新 segment 被写入和打开,使其包含的文档在未进行一次完整提交时便对搜索可见。 这种方式比进行一次提交代价要小得多,并且在不影响性能的前提下可以被频繁地执行。而 es 中底层搜索的此种方式基于 refresh ,refresh 的默认值是 1s ,所以搜索不是实时的,而是近实时。
一个 ElasticSearch 的 Shard 本质上是一个 Lucene Index
Lucene 是一个开源的,全文索引工具包。有 索引,搜索,分词 等功能,是 ElasticSearch 和 Apache Solr 的核心,它引入了按段(Segment)搜索的概念
相关入门资料:https://juejin.cn/post/7021683796747485214
优化方案
写入优化
-
使用bulk api批量操作
-
调整refresh_interval的间隔,es在每一次refresh时都会创建lucene的segment,并尝试进行segment的合并,开销较大,若对搜索的实时性要求不高,可以适当的调大refresh_interval的大小
-
不需要索引的字段指定index属性为not_analyzed
读取优化
-
没有范围查找需求的number类型字段,类型定义为keyword
-
慎用wildcard query,尽量使用分词后的结果使用match query,有使用wildcard query的需求,注意字符转义
-
搜索词的长度要做限制
-
feed流场景使用search_after
-
不需要得分的字段用filter context替换query content