Elasticsearch总结参照

问题总结
ES底层数据结构:倒排索引

词项字典(trem dictionary)、词项索引(trem index):
通过FST算法,压缩词项字典和词项索引数据。词项字典类似于前缀树结构,极大的减少存储内存,FST结构同时存储了词项索引用于定位倒排列表(posting list)
倒排表
通过FOR(Frame Of Reference()和RBM(Roaring Bitmaps)算法对文档id进行压缩,尽可能多的存放到内存中。

1、ES内部运行流程
① 写索引原理
下图描述了3个节点的集群,共拥有12个分片,其中有4个主分片(S0、S1、S2、S3)和8个副本分片(R0、R1、R2、R3),每个主分片对应两个副本分片,节点1是主节点(Master节点)负责整个集群的状态。

写索引是只能写在主分片上,通过routing 默认是文档_id,可以指定。
通过哈希取模获取分片位置:

Copyshard = hash(routing) % number_of_primary_shards

这就解释了为什么我们要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

由于在ES集群中每个节点通过上面的计算公式都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。在一个写请求被发送到某个节点后,该节点即为前面说过的协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。

  • 客户端向ES1节点(协调节点)发送写请求,通过路由计算公式得到值为0,则当前数据应被写到主分片S0上。
  • ES1节点将请求转发到S0主分片所在的节点ES3,ES3接受请求并写入到磁盘。
  • 并发将数据复制到两个副本分片R0上,其中通过乐观并发控制数据的冲突。一旦所有的副本分片都报告成功,则节点ES3将向协调节点报告成功,协调节点向客户端报告成功。

②、存储原理
数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。具体的存储路径可在配置文件../config/elasticsearch.yml中进行设置,默认存储在安装目录的data文件夹下。建议不要使用默认值,因为若ES进行了升级,则有可能导致数据全部丢失。

Copypath.data: /path/to/data  //索引数据
path.logs: /path/to/logs  //日志记录

分段存储
分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。
段被写入到磁盘后会生成一个提交点 ,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。
索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢?

  • 新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。
  • 删除,由于不可修改,所以对于删除操作,不会把文档从旧的段中移除而是通过新增一个.del文件,文件中会列出这些被删除文档的段信息。这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
  • 更新,不能修改旧的段来进行反映文档的更新,其实更新相当于是删除和新增这两个动作组成。会将旧的文档在.del文件中标记删除,然后文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除。

2、主分片和副本分片是如何同步的?

3、创建索引的流程是什么样的?

4、ES如何将索引数据分配到不同的分片上的?以及这些索引数据是如何存储的?

5、为什么说ES是近实时 搜索引擎而文档的 CRUD (创建-读取-更新-删除) 操作是实时的?
延迟写策略
为了提升写的性能,ES并没有每新增一条数据就增加一个段到磁盘上,而是采用延迟写 的策略。
每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点 。
在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索 ,因为文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。我们也可以手动触发 refresh,POST /_refresh 刷新所有索引,POST /nba/_refresh刷新指定的索引。

注意:尽管刷新是比提交轻量很多的操作,它还是会有性能开销。当写测试的时候, 手动刷新很有用,但是不要在生产> 环境下每次索引一个文档都去手动刷新。而且并不是所有的情况都需要每秒刷新。可能你正在使用 Elasticsearch 索引大量的日志文件, 你可能想优化索引速度而不是> 近实时搜索, 这时可以在创建索引时在settings中通过调大refresh_interval = "30s" 的值 , 降低每个索引的刷新频率,设值时需要注意后面带上时间单位,否则默认是毫秒。当refresh_interval = -1时表示关闭索引的自动刷新。

为了避免丢失数据,Elasticsearch添加了事务日志(Translog) ,事务日志记录了所有还没有持久化到磁盘的数据。添加了事务日志后整个写索引的流程如下图所示。

  • 一个新文档被索引之后,先被写入到内存中,但是为了防止数据的丢失,会追加一份数据到事务日志中。不断有新的文档被写入到内存,同时也都会记录到事务日志中。这时新数据还不能被检索和查询。
  • 当达到默认的刷新时间或内存中的数据达到一定量后,会触发一次 refresh,将内存中的数据以一个新段形式刷新到文件缓存系统中并清空内存。这时虽然新段未被提交到磁盘,但是可以提供文档的检索功能且不能被修改。
  • 随着新文档索引不断被写入,当日志数据大小超过512M或者时间超过30分钟时,会触发一次 flush。内存中的数据被写入到一个新段同时被写入到文件缓存系统,文件系统缓存中数据通过 fsync 刷新到磁盘中,生成提交点,日志文件被删除,创建一个空的新日志。
    通过这种方式当断电或需要重启时,ES不仅要根据提交点去加载已经持久化过的段,还需要工具Translog里的记录,把未持久化的数据重新持久化到磁盘上,避免了数据丢失的可能。

由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段然后合并查询结果,所以段越多,搜索也就越慢。

Elasticsearch通过在后台定期进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档不会被拷贝到新的大段中。合并的过程中不会中断索引和搜索。
段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。合并结束后老的段会被删除,新的段被 flush 到磁盘,同时写入一个包含新段(已排除旧的被合并的段)的新提交点,新的段被打开可以用来搜索。

段合并的计算量庞大, 而且还要吃掉大量磁盘 I/O,段合并会拖累写入速率,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然有足够的资源很好地执行。
6、Elasticsearch 是怎样保证更新被持久化在断电时也不丢失数据?还有为什么删除文档不会立刻释放空间?

Kibana可视化继承工具

ES数据查询插件elasticsearch-head

基本查询页

参照:
https://mp.weixin.qq.com/s/KMr7d7rh8N_FrqUbb9k9Kg

posted @   倔强的老铁  阅读(226)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示