Elasticsearch 内存使用

Elasticsearch 内存使用

  • 一. 初窥内存
  • 二. 内存分布详解
    • 2.1 Elasticsearch heap
    • 2.2 Lucene (off-heap)
  • 三. 疑问

序号 内容 链接地址
1 SpringBoot整合Elasticsearch7.6.1 https://blog.csdn.net/miaomiao19971215/article/details/105106783
2 Elasticsearch Filter执行原理 https://blog.csdn.net/miaomiao19971215/article/details/105487446
3 Elasticsearch 倒排索引与重建索引 https://blog.csdn.net/miaomiao19971215/article/details/105487532
4 Elasticsearch Document写入原理 https://blog.csdn.net/miaomiao19971215/article/details/105487574
5 Elasticsearch 相关度评分算法 https://blog.csdn.net/miaomiao19971215/article/details/105487656
6 Elasticsearch Doc values https://blog.csdn.net/miaomiao19971215/article/details/105487676
7 Elasticsearch 搜索技术深入 https://blog.csdn.net/miaomiao19971215/article/details/105487711
8 Elasticsearch 聚合搜索技术深入 https://blog.csdn.net/miaomiao19971215/article/details/105487885
9 Elasticsearch 内存使用 https://blog.csdn.net/miaomiao19971215/article/details/105605379
10 Elasticsearch ES-Document数据建模详解 https://blog.csdn.net/miaomiao19971215/article/details/105720737

一. 初窥内存

Elasticsearch 内存使用_第1张图片
从图中可以看到,整个物理内存被划分成了两块区域: Elasticsearch heap(分配给Elasticsearch的堆内存)Lucene(off-heap) 非堆内存

平常我们在elasticsearch.yml中定义的配置仅仅只是用于约束堆内存的大小。

二. 内存分布详解

2.1 Elasticsearch heap

分配Elasticsearch堆内存,由Node Query Cache、Shard Request Cache、Indexing Buffer以及Field Data Cache组成。

  • Node Query Cache
    在Elasticsearch 7.5版本前,当前缓存被称作"filter cache",但在7.5版本后被重命名为"Node Query Cache",负责缓存通过滤器过滤后的查询结果。每一个Elasticsearch节点都会有这样的查询缓存,并且在所有分片之间共享。

       缓存使用LRU清除策略(Least Recently Used): 当缓存已满时,清除最近最少使用的查询结果缓存,以便为新的查询结果腾出存储空间。遗憾的是,Elasticsearch没有提供任何方法让我们查看目前到底缓存了哪些过滤后的查询结果。

       默认情况下,最多能缓存10000个查询结果,最多占据堆内存10%的空间。

       并非所有包含filter的查询都有缓存的资格。如果某个index segment至少包含10000个document,并且至少占据了当前所在分片中存储该index的数据总量的3%,那么这个index segment就有资格被缓存了。这么做是因为Elasticsearch为了节省存储空间和IO开销,会在执行写入操作时进行merge操作,合并数据量较少的index segment,而合并后,又会导致之前缓存在Node Query Cache当中的index segment失效,所以索性不缓存包含数据量较少的segment。

       如有必要,可以自行修改Node QueryCache的配置,这些配置必须添加到每个节点上。

#过滤器查询缓存最多占据堆空间的大小,默认为10%。可以填写百分比(如5%)或者具体值(如512mb)
indices.queries.cache.size: 15%

        每个索引的过滤请求缓存默认都是开启状态,如果想关闭,可以在创建索引时指定:

PUT /index_name
{
  "settings": {
    "index.queries.cache.enabled": false
  }
}

       可以手动的清空指定index的Node Query Cache:

# 清除(Node)query cache
POST /index_name1,index_name2/_cache/clear?query=true
  • Shard Request Cache
    分片请求缓存。我们来复习一下搜索执行的过程: 首先,Elasticsearch将搜索请求发送给协调节点,由协调节点将请求转发至位于不同节点的分片上,接着,收到请求的分片会在本地执行搜索操作,并将结果返回至协调节点,最后由协调节点将数据汇总(可能还会涉及到分页之类的操作),得到最终的执行结果。纵观整个执行过程,如果我们能在分片上缓存常用的搜索结果,那么每次分发出去的请求几乎可以立刻返回到协调节点,这样就极大的提高了整个搜索操作的执行效率。这里的缓存就是Shard Request Cache。

        默认情况下,Elasticsearch只缓存size=0的请求,也即不缓存搜索结果,只缓存搜索结果的总数、聚合的结果以及搜索建议。此外,使用非确定性API(比如Math.random()或new Date())的脚本化查询结果也不会被缓存。

        若分片执行了refresh操作,缓存的结果会自动失效。通过学习document写入原理得知,只有当有新的数据写入至buffer时,Elasticsearch会通过定时任务刷新buffer,并将document写入至index segment中临时保存。换句话说,如果没有新的数据写入到当前分片,那么我们每次发起请求并从缓存中获取的数据与直接从index segment中读取数据没有任何区别。

        手动清空指定index的Node Query Cache:

# 清除(Shard)request cache
POST /index_name1,index_name2/_cache/clear?request=true

        默认开启分片请求缓存。手动启用或停用Shard Request Cache:

PUT /my_index
{
  "settings": {
    "index.requests.cache.enable": false
  }
}

       允许在已有的索引上更新缓存的启停状态:

PUT /my_index/_settings
{ "index.requests.cache.enable": true }

       甚至可以在每次请求时携带参数来决定是否使用缓存:

GET /my_index/_search?request_cache=true
{
  "size": 0,
  "aggs": {
    "popular_colors": {
      "terms": {
        "field": "colors"
      }
    }
  }
}

       Shard Request Cache属于节点级别管理,默认可用的内存大小的上限为当前节点分配堆内存的1%,这是一个静态配置,只能在config/elasticsearch.yml中修改,修改后重启对应的ES节点才能生效。

indices.requests.cache.size: 2%

       查看指定索引缓存中分片缓存的大小(以字节为单位)和清除次数:

GET index_name1,index_name2/_stats/request_cache
  • Indexing Buffer
    索引缓冲区。根据Document的写入原理,Elasticsearch会把写入信息(可能是新增、删除、修改document)存放至Indexing Buffer,当Buffer被填满或者过了一定时间后,Elasticsearch会将Buffer中的数据refresh到index segment,最后通过commit,将数据写入至segment File持久化到磁盘Disk中。

       与Indexing Buffer相关的配置都是静态的,必须在每一个节点的config/elasticsearch.yml中配置。同节点内,所有的分片共享当前节点的配置。
       Indexing Buffer虽然默认被分配堆空间10%的内存,但这个数值并非是Buffer的上限。换句话说,如果一次性写入的数据量过大,比如超过了堆空间剩余内存的大小,则会报错Elasticsearch 请求报错 Data too large。

#同一个节点内,所有分片共享的索引缓冲区的大小 可以填写百分比或具体数值(单位:字节)
#默认10%,意味着将(当前节点被分配的)堆空间的10%的内存分配给索引缓冲区
indices.memory.index_buffer_size: 10%


如果index_buffer_size使用百分比配置,则可以使用本配置指定索引缓冲区的最小分配数值(单位:字节) 默认为48mb
indices.memory.min_index_buffer_size: 500mb


如果index_buffer_size使用百分比配置,则可以使用本配置指定索引缓冲区的最大分配数值(单位:字节) 默认是无限制(unbounded)
indices.memory.max_index_buffer_size: 10gb

  • Field Data Cache
    fielddata缓冲区。一般而言,text类型字段会被分词,只会创建倒排索引。但在某些业务场景下,我们需要对它们进行聚合、排序、父子关系以及脚本处理,因此Elasticsearch会为这类字段专门创建了正排索引,其数据被缓存在fielddata缓冲区。fielddata是在针对这个字段进行聚合分析时,才会逆转倒排索引并加载到内存中,因此是一个在查询时生成的正排索引(query-time)。这块内容可以参考我的文章Elasticsearch 聚合搜索技术深入 第2.18节。

除上述外,还有一些常用的清空缓存的命令:

# 清除所有索引的所有缓存
POST /_cache/clear

# 清除指定字段的缓存
POST /index_name/_cache/clear?fields=field_name1,field_name2

2.2 Lucene (off-heap)

Lucene 被设计为可以利用操作系统底层机制来缓存内存数据结构。 Lucene 的段是分别存储到单个文件中的。因为段是不可变的,这些文件也都不会变化,这是对缓存友好的,同时操作系统也会把这些段文件缓存起来,以便更快的访问。

Lucene 的性能取决于和操作系统的相互作用。如果你把所有的内存都分配给 Elasticsearch 的堆内存,那将不会有剩余的内存交给Lucene。 这将严重地影响全文检索的性能。

三. 疑问

  1. 假设一个位于非堆内存的segment File中有10000条document,现在发起请求,仅修改其中的一条document的数据,那么segment File缓存会增量更新吗?还是说直接新增一份segment File,对旧文件缓存进行全量替换呢?
  2. Shard Request Cache中,怎样配置才能缓存搜索结果呢?

你可能感兴趣的:(#,分布式搜索引擎)