zoukankan      html  css  js  c++  java
  • Elasticsearch由浅入深(十一)内核原理

    倒排索引组成结构以及索引不可变原因

    对于倒排索引是非常适合用来进行搜索的
    它的结构:
    (1)包含这个关键词的document list
    (2)包含这个关键词的所有document的数量:IDF(inverse document frequency)
    (3)这个关键词在每个document中出现的次数:TF(term frequency)
    (4)这个关键词在这个document中的次序
    (5)每个document的长度:length norm
    (6)包含这个关键词的所有document的平均长度
    其实本质上主要是为了计算相关度分数

    _score = boost * idf * tf 
    此时boost = 2.2, idf = 0.18232156, tf = 0.5116279
    
    idf = log(1 + (N - n + 0.5) / (n + 0.5))
    此时n = 2 (n, number of documents containing term), 
    N = 2(N, total number of documents with field)
    
    tf = freq / (freq + k1 * (1 - b + b * dl / avgdl))
    此时freq = 1(freq, occurrences of term within document), 
    k1 = 1.2(k1, term saturation parameter), 
    b = 0.75(b, length normalization parameter), 
    d1 = 4 (dl, length of field), 
    avgdl = 5.5(avgdl, average length of field)

    倒排索引的不可变好处

    (1)不需要锁,提升了并发能力,避免锁的问题
    (2)数据不变,一直保存在OS cache中,只要cache内存足够
    (3)filter cache一直驻留在内存
    (4)可以压缩,节省cpu和io开销
    这个对应的就是primary shard的数量不变,不能修改field的属性(将date改成text)

    倒排索引不可变的坏处

    (1)每次都需要重新构建整个索引

    document写入原理

    (1)数据写入buffer
    (2)commit point
    (3)buffer中的数据写入新的index segment
    (4)等待在OS cache中的index segment被fsync强制刷到磁盘上
    (5)新的index segment被打开,供search使用
    (6)buffer被清空

    下面做几点说明:

    1、在Elasticsearch中,底层用的是lucene,lucene底层的index是分为多个segment的,每个segment都会存放部分数据。
    2、如果是删除操作,每次commit的时候,就会生成一个.del文件,标明哪个index segment的哪个document被删除了。
    3、如果是更新操作,实际上是将的doc标记为deleted,然后将新的document写入新的index segment中。下次search过来的时候,也许会匹配到一个document的多个版本,但是之前的版本已经被标记为deleted了,所以只会返回最新版本的doc
    4、如果搜索请求过来,在index segment中,匹配到了id=1的doc,此时会发现在.del文件中已经被标识为deleted了,这种数据就会被过滤掉,不会作为搜索结果返回。
    图示如下:

    写入流程近实时NRT(filesystem cache,refresh)

    现有的流程的问题,每次都必须等待fsync将segment刷入磁盘,才能将segment打开供search使用,这样的话,从一个document写入,到它可以被搜索,可能会超过1分钟,这也就不是近实时的搜索了。主要的瓶颈在于fsync从磁盘IO写数据进磁盘是很耗时的。
    ES写入流程的改进:
    (1)数据写入buffer
    (2)每个一定时间,buffer中的数据被写入segment文件,但是先写入OS cache
    (3)只要segment写入OS cache,那就直接打开供search使用,不立即执行commit
    数据写入OS cache,并被打开供搜索的过程,叫做refresh,默认是每隔一秒refresh一次,也就是说,每隔一秒就会将buffer中的数据写入OS cache中,写入一个新的index segment file。所以ES是近实时的,数据写入到可以被搜索,默认是1秒。
    一般不用修改,让ES自己搞定就好了,要修改的话,通过refresh_interval参数即可
    格式:

    写入流程的实现 durability可靠存储(translog,flush)

    最终流程:

    1)数据写入buffer缓存和translog日志文件
    (2)每隔一秒,buffer中的数据被写入新的segment file,并进入os cache,此时segment被打开并供search使用
    (3)buffer被清空
    (4)重复1~3,新的segment不断添加,buffer不断被清空,而translog中的数据不断累加
    (5)当translog长度达到一定程度的时候,commit操作发生
        (5.1)buffer中的所有数据,写入一个新的segment,并写入os cache,打开供使用
        (5.2)buffer被清空
        (5.3)一个commit point被写入磁盘,标明了所有的index segment
        (5.4)filesystem cache中的所有index segment file缓存数据,被fsync强制刷到磁盘上
        (5.5)现有的translog被清空,创建一个新的translog

    translog

    对Lucene的更改仅在Lucene提交期间持久保存到磁盘,这是一项相对昂贵的操作,因此无法在每次索引或删除操作后执行。如果进程退出或硬件发生故障,Lucene将在一次提交之后和另一次提交之前发生的更改将从索引中删除。

    因为Lucene提交对于每个单独的更改都执行起来太昂贵,所以每个分片副本还有一个事务日志,称为与之关联的translog。所有索引和删除操作在由内部Lucene索引处理之后但在确认之前写入translog。在发生崩溃的情况下,最新的已确认但尚未包含在上一个Lucene提交中的事务可以在分片恢复时从translog中恢复。

    Elasticsearch flush是执行Lucene提交并启动新的translog的过程。在后台自动执行刷新以确保translog不会变得太大,这将使得在恢复期间重放其操作需要相当长的时间。手动执行刷新的能力也通过API公开,尽管很少需要。

    translog设置

    translog中的数据仅在fsync编辑和提交translog时持久保存到磁盘 。如果发生硬件故障,自上次translog提交以来写入的任何数据都将丢失。

    默认情况下,fsync如果index.translog.durability设置为async或request 在每个索引,删除, 更新或 批量请求结束时设置为(默认),则Elasticsearch会每隔5秒提交一次translog 。更确切地说,如果设置为request,则fsync在主数据库和每个已分配的副本服务器上成功编辑和提交translog之后,Elasticsearch将仅向客户端报告索引,删除,更新或批量请求的成功 。

    以下可动态更新的每索引设置控制translog的行为:

    index.translog.sync_interval
        fsync无论写入操作 如何,translog都经常被写入磁盘并提交。默认为5s。小于的值100ms是不允许的。
    index.translog.durability
        是否fsync在每个索引,删除,更新或批量请求之后提交translog。此设置接受以下参数:
            request
            (默认)fsync并在每个请求后提交。如果发生硬件故障,所有已确认的写入都已提交到磁盘。
            async
            fsync并在每个背景中提交sync_interval。如果发生硬件故障,将丢弃自上次自动提交以来的所有已确认写入。
    index.translog.flush_threshold_size
        translog存储尚未安全保存在Lucene中的所有操作(即,不是Lucene提交点的一部分)。尽管这些操作可用于
        读取,但如果要关闭并且必须恢复,则需要重新编制索引。此设置控制这些操作的最大总大小,以防止恢复时间
        过长。达到最大大小后,将发生刷新,生成新的Lucene提交点。默认为512mb。
    index.translog.retention.size
        要保留的translog文件的总大小。保留更多的translog文件会增加在恢复副本时执行基于同步操作的机会。如
        果translog文件不足,副本恢复将回退到基于文件的同步。默认为512mb
    index.translog.retention.age
        保留translog文件的最长持续时间。默认为12h。
    PUT /my_index/_settings
    {
        "index.translog.durability": "async",
        "index.translog.sync_interval": "5s"
    }

    图示如下:

    数据恢复

    假设os cache中囤积了一些数据,但是此时不巧,宕机了,os cache中的数据全部丢失,那么我们怎么进行数据恢复呢?
    我们知道写doc的时候也会写入translog,那么translog就存储了上一次flush直到现在最近的数据变更记录。机器被重启之后,disk上的数据并没有丢失,此时就会将translog文件中的变更记录进行回收,重新执行之前的各种操作,在buffer中执行,在重新刷一个一个的segment到os cache中,等待下一次commit发生即可。

    海量磁盘文件的合并(segment merge,optimize)

    每秒一个segment file,会导致文件过多,而且每次search都要搜索所有的segment,很耗时。所以在Elasticsearch内部会默认在后台执行segment merge操作(forcemerge),在merge的时候,被标记为deleted的document也会被彻底物理删除掉。
    每次merge的操作流程:
    (1)选择一些有相似大小的segment,merge成一个大的segment
    (2)将新的segment flush到磁盘上去
    (3)写一个新的commit point,包括了新的segment,并且排除旧的那些segment
    (4)将新的segment打开供搜索
    (5)将旧的segment删除 

    POST /my_index/_optimize?max_num_segments=1尽量不要手动执行,让它自动默认执行就可以了
  • 相关阅读:
    欧拉定理证明&阶乘的逆元
    Tree POJ
    GCD
    java42
    java41
    java
    java40
    搭建两个网站的琐碎问题
    虚拟机从无到有,服务器从无到有的历程(在更)
    java39
  • 原文地址:https://www.cnblogs.com/wyt007/p/11425039.html
Copyright © 2011-2022 走看看