社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Elasticsearch

Elasticsearch基础概念之基本原理

逍遥白亦 • 4 年前 • 359 次点击  

ES基本原理

名词解释

In-memory buffer: ES内存缓冲区,新建的document写入的地方

document:索引和搜索的主要数据载体,对应写入到ES中的一个doc

Segment: Lucene里面的一个数据集概念,前边提到的document最终就是存放在这里边,一个Segment包含多个document

Refresh:将In-memory buffer中的数据生成一个segment并放入系统缓存区,同时清空In-memory buffer

Translog: 新建的document也会写入到这个里边,记录这些日志,并用于回放

Flush:会先执行一次refresh操作,之后将系统缓存区中的一个一个Segment拷贝到磁盘中,之后清空translog

Refresh过程

新建的document会先写进ES内存缓冲区中,但是这个区域是不可见的,不能被搜索到,所以Refresh的过程就是产生一个segment放入系统缓存区,这部分区域是可读的,可以被搜索到。在默认情况下ES每隔1秒钟,会自动Refresh,保证数据可见。

Refersh的执行条件:

  1. 手动触发,通过GET查询以及index、bulk写入时指定refresh
  2. 自动触发,配置refresh_interval
  3. In-memory buffer满了

可以更改这个配置

改为10秒

POST /index/_settings
{“refresh_interval”: “10s”}

改为不自动更新

POST /index/_settings
{“refresh_interval”: “-1″}

Segment合并

由于每一次refresh都会新建一个Segment,那么随着refresh次数越来越多,segment文件也会越来越多,而每一次查询最终都会检索segment文件,每一个segment都会占用操作系统的CPU、文件句柄和内存资源,而且,在查询的时候,需要在每个segment上都执行一次查询,这样是很消耗性能的。

为了解决这个问题,es会自动定期的将多个小segment合并为一个大的segment,这次合并是真正意义上的物理删除。

当新合并后的segment完全写入磁盘之后,es就会自动删除掉那些零碎的segment,之后的查询都在新合并的segment上执行。Segment的合并会消耗大量的IO和cpu资源,这会影响查询性能。

下面是几个常用配置项

  1. index.merge.policy.floor_segment:该属性用于阻止碎片段的频繁刷新。小于或者等于该设定值的段将考虑被合并。默认值为2M。
  2. index.merge.policy.max_merge_at_once:该属性指定了索引过程中同一时刻用于合并的段的最大数量,默认为10。如果将值设置得更大,一次合并操作将合并更多的段,同时合并过程也需要更多的I/O资源。
  3. index.merge.policy.max_merged_segment:默认值为5GB,该属性指定了索引过程中单个段的最大容量。这个值是一个近似值,因为合并操作中,段的大小等于待合并段的总大小减去各个段中删除文档的大小。
  4. index.merge.policy.segments_per_tier:该属性指定了每层段的数量。较小的值带来较少的段。这意味着更多的合并操作,和更低索引性能。默认值为10,其值应该不低于index.merge.policy.max_merge_at_once属性值,否则就会使合并次数过多,引起性能问题。

Translog与Flush

由于Refresh操作将数据放入到内存中,而内存中的不保险,所以就会把每一条document新建和更新记录得translog中,这样如果出现意外情况,可以从translog中找到这部分数据,并进行恢复。然后会通过Flush操作,将这部分数据内存中的数据,写入磁盘里,也为了避免translog太大,同时情空该部分数据。

Flush的具体流程:

  1. 将系统缓存区里的一个一个segment写入到磁盘中
  2. 执行一次refresh操作
  3. 清空translog日志

具体源码如下:

// Only flush if (1) Lucene has uncommitted docs, or (2) forced by caller, or (3) the
// newly created commit points to a different translog generation (can free translog)
if (indexWriter.hasUncommittedChanges() || force || shouldPeriodicallyFlush()) {
    ensureCanFlush();
        try {
            translog.rollGeneration();
            logger.trace("starting commit for flush; commitTranslog=true");
            //将系统缓存区里的一个一个segment写入到磁盘中
            commitIndexWriter(indexWriter, translog, null);
            logger.trace("finished commit for flush");
            //执行一次refresh操作
            refresh("version_table_flush", SearcherScope.INTERNAL);
            //清空translog日志
            translog.trimUnreferencedReaders();
        } catch (AlreadyClosedException e) {
            throw e;
        } catch (Exception e) {
            throw new FlushFailedEngineException(shardId, e);
        }
         refreshLastCommittedSegmentInfos();

}

该段源码很好解释了执行flush的三个内部条件

  1. Lucene中有未提交的文档
  2. 强制调用
  3. 定期执行

ES默认配置中,translog的配置同flush进行绑定,每一次index、bulk这些写入更新操作,都会先flush然后返回200,但是这种配置会牺牲很大的性能,可以采用异步刷新的方式,并配置每隔几秒进行刷新,来提高写入性能。

注意:该操作要先关闭索引,才能执行

PUT /index/_settings
{
    "index.translog.durability": "async",
    "index.translog.sync_interval": "5s"
}

Flush执行条件:

  1. 默认配置下(index.translog.flush_threshold_period),每30分钟进行一次
  2. 当translog的大小超过设定值(index.translog.flush_threshold_size),默认是512MB
  3. 多少时间间隔内(index.translog.interval:多少时间间隔内会检查一次translog,来进行一次flush操作。es会随机的在这个值到这个值的2倍大小之间进行一次操作,默认是5s。)会检查一次translog,来进行一次flush操作。es会随机的在这个值到这个值的2倍大小之间进行一次操作,默认是5s。

近实时搜索与实时搜索

看过上边的Refresh操作,可以得知,在默认情况下,每隔一秒进行一次refresh操作,写入的docment才可以搜索出来,这是准实时的原因。但是ES也提供了实时搜索的功能。下面就是两种实时搜索的操作。

  1. GET查询
  2. 写入时同步执行refresh操作再返回200

这两种操作的原理都是手动执行refresh操作,保证数据从In-memory buffer写入到系统缓存区,但是这种操作,相比每秒或者定时刷新refresh,在性能上的开销是很大的,相当于每一次请求就会执行一次refresh操作,生成一个新的segment,完全没有用到In-memory buffer这个缓冲区。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/103935
 
359 次点击