Elasticsearch进阶笔记第二十七篇

109 阅读4分钟

Elasticsearch高手进阶篇(55)

深入聚合数据分析_fielddata内存控制以及circuit breaker断路器

fielddata核心原理

  • fielddata加载到内存的过程是lazy加载的,对一个analzyed field执行聚合时,才会加载,而且是field-level加载的
  • 一个index的一个field,所有doc都会被加载,而不是少数doc
  • 不是index-time创建,是query-time创建

fielddata内存限制

  • indices.fielddata.cache.size: 20%,超出限制,清除内存已有fielddata数据

    • fielddata占用的内存超出了这个比例的限制,那么就清除掉内存中已有的fielddata数据
    • 默认无限制,限制内存使用,但是会导致频繁evict和reload,大量IO性能损耗,以及内存碎片和gc(垃圾回收)

监控fielddata内存使用

 GET /_stats/fielddata?fields=*
 GET /_nodes/stats/indices/fielddata?fields=*
 GET /_nodes/stats/indices/fielddata?level=indices&fields=*
  • 结果数据太多就不进行展示了

circuit breaker

  • 如果一次query load的feilddata超过总内存,就会oom --> 内存溢出

  • circuit breaker会估算query要加载的fielddata大小,如果超出总内存,就短路,query直接失败

    • indices.breaker.fielddata.limit:fielddata的内存限制,默认60%
    • indices.breaker.request.limit:执行聚合的内存限制,默认40%
    • indices.breaker.total.limit:综合上面两个,限制在70%以内

Elasticsearch高手进阶篇(56)

深入聚合数据分析_fielddata filter的细粒度内存加载控制

 POST /waws_index_1/_mapping/waws_type
 {
   "properties": {
     "my_field": {
       "type": "text",
       "fielddata": { 
         "filter": {
           "frequency": { 
             "min":0.01, 
             "min_segment_size": 500  
           }
         }
       }
     }
   }
 }
  • min仅仅加载至少在1%的doc中出现过的term对应的fielddata

    • 比如说某个值,hello,总共有1000个doc,hello必须在10个doc中出现,那么这个hello对应的fielddata才会加载到内存中来
  • min_segment_size少于500 doc的segment不加载fielddata

    • 加载fielddata的时候,也是按照segment去进行加载的,某个segment里面的doc数量少于500个,那么这个segment的fielddata就不加载

这个,就我的经验来看,有点底层了,一般不会去设置它,大家知道就好

Elasticsearch高手进阶篇(57)

深入聚合数据分析_fielddata预加载机制以及序号标记预加载

预先生成加载fielddata到内存

  • 问题:
    • 如果真的要对分词的field执行聚合,那么每次都在query-time现场生产fielddata并加载到内存中来,速度可能会比较慢

我们是不是可以预先生成加载fielddata到内存中来

fielddata预加载
 POST /waws_index_1/_mapping/waws_type
 {
   "properties": {
     "test_field": {
       "type": "string",
       "fielddata": {
         "loading" : "eager" 
       }
     }
   }
 }

query-time的fielddata生成和加载到内存,变为index-time,建立倒排索引的时候,会同步生成fielddata并且加载到内存中来,这样的话,对分词field的聚合性能当然会大幅度增强

序号标记预加载

global ordinal原理解释

  • doc1: status1
  • doc2: status2
  • doc3: status2
  • doc4: status1

有很多重复值的情况,会进行global ordinal标记

status1 --> 0
status2 --> 1

  • doc1: 0
  • doc2: 1
  • doc3: 1
  • doc4: 0

建立的fielddata也会是这个样子的,这样的好处就是减少重复字符串的出现的次数减少内存的消耗

 POST /waws_index_1/_mapping/waws_type
 {
   "properties": {
     "test_field": {
       "type": "string",
       "fielddata": {
         "loading" : "eager_global_ordinals" 
       }
     }
   }
 }

Elasticsearch高手进阶篇(58)

深入聚合数据分析_海量bucket优化机制:从深度优先到广度优先

从深度优先到广度优先

当buckets数量特别多的时候,深度优先和广度优先的原理

  • 案例:
    • 我们的数据,是每个演员的每个电影的评论
    • 每个演员的评论的数量 --> 每个演员的每个电影的评论的数量
    • 评论数量排名前10个的演员 --> 每个演员的电影取到评论数量排名前5的电影
 {
   "aggs" : {
     "actors" : {
       "terms" : {
          "field" :"actors",
          "size" :10,
          "collect_mode" : "breadth_first" 
       },
       "aggs" : {
         "costars" : {
           "terms" : {
             "field" : "films",
             "size" :  5
           }
         }
       }
     }
   }
 }
深度优先
  • 深度优先的方式去执行聚合操作的
actor1actor2.... actor
film1 film2 film3film1 film2 film3...film

比如说,我们有10万个actor,最后其实是主要10个actor就可以了

  • 但是我们已经深度优先的方式,构建了一整颗完整的树出来了,10万个actor,每个actor平均有10部电影,10万 + 100万 --> 110万的数据量的一颗树

  • 裁剪掉10万个actor中的99990 actor,99990 * 10 = film,剩下10个actor,每个actor的10个film裁剪掉5个,110万 --> 10 * 5 = 50个

  • 构建了大量的数据,然后裁剪掉了99.99%的数据,浪费了

广度优先
  • 广度优先的方式去执行聚合

    • actor1 actor2 actor3 ..... n个actor
  • 10万个actor,不去构建它下面的film数据,10万 --> 99990,10个actor,构建出film,裁剪出其中的5个film即可,10万 -> 50个