• Shard内部原理


    https://blog.csdn.net/dailywater/article/details/104073944

    https://blog.csdn.net/zc19921215/article/details/105166841/

    一、预备知识:

    1、客户端处理请求:

      通过  nodes.get(index % nodes.size())  来负载均衡,轮询选取一个node,这里的index是个AtomicInteger,每次自增1来随机选取node。

    2、倒排索引

      倒排索引的结构,是非常适合用来做搜索的,Elasticsearch会为索引的每个 index 为 analyzed 的字段建立倒排索引。

    基本结构

    倒排索引包含以下几个部分:

    1. 某个关键词的doc list
    2. 某个关键词的所有doc的数量IDF(inverse document frequency)
    3. 某个关键词在每个doc中出现的次数:TF(term frequency)
    4. 某个关键词在这个doc中的次序
    5. 每个doc的长度:length norm
    6. 某个关键词的所有doc的平均长度

    记录这些信息,就是为了方便搜索的效率和_score分值的计算。

    不可变性

    倒排索引写入磁盘后就是不可变的,这样有几个好处:

    1. 不需要锁,如果不更新索引,不用担心锁的问题,可以支持较高的并发能力
    2. 如果cache内存足够,不更新索引的话,索引可以一直保存在os cache中,可以提升IO性能。
    3. 如果数据不变,filter cache 会一直驻留在内存。
    4. 索引数据可以压缩,节省 cpu 和 io 开销。

    二、doc底层原理

      前面提到倒排索引是基于不可变模式设计的,但实际Elasticsearch源源不断地有新数据进来,那光是建立、删除倒排索引,岂不是非常忙?如果真是不停地建立,删除倒排索引,那ES压力也太大了,肯定不是这么实现的。ES通过增加新的补充索引来接收新的文档和修改的文档,而不是直接用删除重建的方式重写整个索引。

    (1)doc写入

      整个写入过程如下图所示:

    1. 新文档先写入内存索引缓存
    2. 当间隔一定时间(1秒),将缓存的数据进行提交,这个过程会创建一个Commit Point,Commit Point包含index segment的信息。
    3. 缓存的数据写入新的index segment。
    4. index segment的数据先写入os-cache中
    5. 等待操作系统将os-cache的数据强制刷新到磁盘中
    6. 写入磁盘完成后,新的index segment被打开,此时segment内的文档可以被搜索到。
    7. 同时buffer的数据被清空,等待下一次新的文档写入。

      index segment翻译过来叫"段",每秒会创建一个,ES把这个1秒内收到的、需要处理的文档都放在这个段里,可以把段认为是倒排索引的一个子集。

      索引、分片、段的关系如下:索引包含多个分片,每个分片是一个Lucene索引实例,一个分片下面有多个段。如果把分片看作是一个独立的倒排索引结构,那么这个倒排索引是由多个段文件的集合。三者之间是包含关系:索引包含多个分片,分片包含多个段

    (2)doc删除和更新

      删除:当文档被删除时,Commit Point会把信息记录在.del文件中,在.del文件中会标识哪些文档是有deleted标记的,但该文档还是存在于原先的index segment文件里,同样能够被检索到,只是在最终结果处理时,标记为deleted的文档被会过滤掉

      更新:更新也是类似的操作,更新会把旧版本的文档标记为deleted,新的文档会存储在新的index segment中。

    补充:

    1、为什么es是近实时搜索

      上面的流程细节会发现,每次都需要fsync磁盘,数据才是可搜索的,那IO压力将特别大,耗费时间比较长,并且执行周期由操作系统控制,从一个新文档写入到可以被搜索,超过1分钟那是常有的事。所以Elasticsearch对此做了一个改进index segment信息写入到os-cache中,即完成上面的第3步,该segment内的文档信息就可以被搜索到了。fsync操作就不立即执行了,os-cache的写入代价比较低,最耗时的fsync操作交由操作系统调度执行。上述的index segment写入到os-cache,并打开搜索的过程,叫做refresh,默认是每隔1秒refresh一次所以,es是近实时的,数据写入到可以被搜索,默认是1秒。

      refresh的时间也可以设置,比如我们一些日志系统,数据量特别大,但实时性要求不高,我们为了优化资源分配,就可以把refresh设置得大一些:

    PUT /music
    {
      "settings": {
        "refresh_interval": "30s" 
      }
    }

      此参数需要在创建索引时使用,要注意一下的是除非有充分的依据,才会对refresh进行设置,一般使用默认的即可。

    2、translog机制

      上述的写入流程当中,如果fsync到磁盘的操作没执行完成,服务器断电宕机了,可能会导致Elasticsearch数据丢失。Elasticsearch也设计了translog机制,跟关系型数据库的事务日志机制非常像,整个写入过程将变成这样:

      新文档写入内存buffer的同时,也写一份到translog当中。内存buffer的数据每隔1秒写入到index segment,并写入os-cache,完成refresh操作。内存buffer被清空,但translog一直累加。每隔5秒translog信息fsync到磁盘上。默认每30分钟或translog累积到512MB时,执行全量commit操作,os-cache中的segment信息和translog信息fsync到磁盘中,持久化完成。生成新的translog,旧的translog归档(6.x版本translog做归档操作,不删除)。

      这个执行一个提交并且归档translog的行为称作一次flush。分片每30分钟被自动刷新(flush),或者在 translog 太大的时候(默认512MB)也会刷新,当然也可以手动触发flush的执行,如下请求:

    POST /music/_flush

    但任其自动flush就够了。如果重启节点前担心会对索引造成影响,可以手动flush一下。毕竟节点重启后需要从translog里恢复数据,translog越小,恢复就越快。

      translog写磁盘行为主要有两种,是由index.translog.durability配置项决定的:

    • request:同步写磁盘,每次写请求完成之后立即执行(新增、删除、更新文档),以及primary shard和replica shard同步都会触发,数据安全有保障,不丢失,但会带来一些性能损失。如果是bulk数据导入,每个文档平摊下来的损失是比较小的。
    • async:异步写磁盘,默认5秒fsync一次,如果有宕机事件,可能会丢失几秒的数据,适用于允许偶尔有数据丢失的场景,如日志系统。

    如果系统不接受数据丢失,用translog同步方式,示例设置:

    # 异步方式
    PUT /music_new
    {
      "settings": {
        "index.translog.durability": "async",
        "index.translog.sync_interval": "5s"
      }
    }
    
    # 同步方式
    PUT /music_new
    {
      "settings": {
        "index.translog.durability": "request"
      }
    }

    3、segment合并

      Elasticsearch针对活跃的索引,每秒都会生成一个新的index segment,这些segment最终会以文件的形式存储在磁盘里,如果不对其进行处理,那么索引运用一段时间后,会有特别多的文件,零碎的文件太多了,也不是什么好事情,更耗费更多的文件资源,句柄等,搜索过程也会变慢。

      合并过程:Elasticsearch会在后台对segment进行合并,减少文件的数量,同时,标记为deleted的文档在合并时会被丢弃(delete请求只是将文档标记为deleted状态,真正的物理删除是在段合并的过程中),合并过程不需要人工干预,让Elasticsearch自行完成即可。

      两个已经提交的段和一个未提交的段合并成为一个大的段文件,合并时会挑一些大小接近的段,合并到更大的段中,段合并过程不阻塞索引和搜索。

      合并完成后,新的更大的段flush到磁盘中,并完成refresh操作,老的段被删除掉。

      optimize命令可以强制合并API,并指定最终段的数量,如下命令:

    POST /music_new/optimize
    {
      "max_num_segments": 1
    }

      指定segment最大数量为1,表示该索引最终只有一个segment文件。

    适用场景

    1. 正常活跃的、经常有更新的索引不建议使用
    2. 日志类的索引,对老数据进行优化时,可以将每个分片的段进行合并

    使用建议

    1. 一般不需要人工干预合并过程
    2. optimize操作会消耗大量的IO资源,使用要慎重考虑
  • 相关阅读:
    Git--记一次丢失本地记录但是代码已提交到gerrit
    IDEA--IDEA配置web项目
    JavaSE--泛型
    Cassandra--Cassandra 安装
    Git--.gitignore
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner
    散列·跳房子散列
    散列·布谷鸟散列
    散列·完美散列
    散列·再散列
  • 原文地址:https://www.cnblogs.com/guoyu1/p/13755165.html
Copyright © 2020-2023  润新知