提高Kibana搜索速度

1,927 阅读5分钟

本文所涉及的Kibana和Elasticsearch版本:7.4.1

Discover页面经常被同事吐槽打开慢,搜索超时。在查看了一些es性能优化的文章,排除掉服务器性能与es配置的问题后,我把矛头指向了Kibana本身。

我在Discover页面做了一个请求,条件为:

  • 请求时间:2020.11.15 00:00:00.000 - 23:59:59.999
  • 请求的文件数:500(默认)
  • 没有添加其他条件。

在response(在Discover的inspect功能里,可以找到这个搜索对应的request和response)里可以看到,这一天的文件数有135万,es处理请求用了10秒+。后面我又多请求了几次,时间也在10秒左右。分析之后,我发现了几个会造成影响的因素:

  • Shard, Index和Index Pattern
  • Date Histogram
  • Time Zone
  • Highlight

接下来的文章中,我会一一地分析并提出解决方法。

Request

{
  "version": true,
  "size": 500,
  "sort": [
    {
      "@timestamp": {
        "order": "desc",
        "unmapped_type": "boolean"
      }
    }
  ],
  "_source": {
    "excludes": []
  },
  "aggs": {
    "2": {
      "date_histogram": {
        "field": "@timestamp",
        "fixed_interval": "30m",
        "time_zone": "Asia/Shanghai",
        "min_doc_count": 1
      }
    }
  },
  "stored_fields": [
    "*"
  ],
  "script_fields": {},
  "docvalue_fields": [
    {
      "field": "@timestamp",
      "format": "date_time"
    }
  ],
  "query": {
    "bool": {
      "must": [],
      "filter": [
        {
          "match_all": {}
        },
        {
          "range": {
            "@timestamp": {
              "format": "strict_date_optional_time",
              "gte": "2020-11-15T00:00:00.000Z",
              "lte": "2020-11-15T23:59:59.999Z"
            }
          }
        }
      ],
      "should": [],
      "must_not": []
    }
  }
}

Response

{
  "took": 10514,
  "timed_out": false,
  "_shards": {
    "total": 7,
    "successful": 7,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1354407,

Shard, Index和Index Pattern

在response中,可以看到请求的shard的数量为7。这是因为在我选择的这个index pattern中,未冻结的index有7个,并且每个index里只包含了一个shard。

GET /_cat/indices/stat-*?v&s=index&h=index,sth

index           sth
stat-2020.11.02 true
stat-2020.11.03 true
stat-2020.11.04 true
stat-2020.11.05 true
stat-2020.11.06 true
stat-2020.11.07 true
stat-2020.11.08 true
stat-2020.11.09 true
stat-2020.11.10 false
stat-2020.11.11 false
stat-2020.11.12 false
stat-2020.11.13 false
stat-2020.11.14 false
stat-2020.11.15 false
stat-2020.11.16 false

(列sth代表search.throttled,值为false的为未冻结的index)

所以Discover页面是用下面这样的方式,不加筛选地搜索了整个index pattern。

GET stat-*/_search

然而,如果我指定具体的index进行搜索

GET stat-2020.11.15/_search

得到的结果会减少大概两秒。

{
  "took" : 8125,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },

所以,针对这个问题,我们可以选择下面两个方案来提高搜索速度:

  1. 为你常用的index设置更为具体的pattern
  2. 冻结不经常使用的index

Date Histogram

在Discover页面的上方有一个条形图显示了搜索时间段内date histogram的聚合分析结果。 对应到request body里面就是这一部分

"aggs": {
  "2": {
    "date_histogram": {
      "field": "@timestamp",
      "fixed_interval": "30m",
      "time_zone": "Asia/Shanghai",
      "min_doc_count": 1
    }
  }
}

如果把聚合分析的部分去掉,我们的请求时间几乎都会在2秒以下。

如果用profile API去做完整的请求,会发先query的部分耗时只有200多毫秒,而aggregation却占了5秒多。

"profile" : {
    "shards" : [
      {
        "searches" : [
          {
            "query" : [
              {
                "type" : "BooleanQuery",
                "description" : "#*:* #ConstantScore(DocValuesFieldExistsQuery [field=@timestamp])",
                "time_in_nanos" : 235074290,
                ......
              }
            ],
            ......
          }
        ],
        "aggregations" : [
          {
            "type" : "DateHistogramAggregator",
            "description" : "2",
            "time_in_nanos" : 5519704113,
            ......
          }
        ]
      }
    ]
  }

Date Histogram在某些场景下是很有用的功能,比如我们想查看时间规律或者找出某些特殊时段的时候。 但是在某些场景下又没有什么用处,比如我们想检索一些比较少出现的信息的时候。所以如果Date Histogram能变成可选项就好了。

在Kibana的github上有这个需求,但是2016年提的issue,至今还是open的状态。

在不能避开聚合分析的情况下,我们就只能选择在discover页面中,选择更长的时间间隔来作聚合分析,但是在分桶的数目原本就少的情况下,能优化的力度是微乎其微的。

Time Zone

在github上搜索相关issue时,我发现很多issue提到了time zone的设置会影响date histogram的性能。在aggs里删掉time_zone这个条件后,搜索的速度减少到了4秒。不设置time zone和设置time zone相比,时间上差了一倍。

Github Kibana#18853的总结中可以了解到,如果我们设置的是一个固定时差的时区,比如Etc/GMT-8,就可以优化这个问题。原因和elasticsearch中aggregation的机制相关。由于很多国家区分冬令时和夏令时,所以es在做timestamp相关的aggregation时,会一个doc一个doc的去转化时间,聚合分析消耗的时间自然就变长了。但是,如果我们选择的是固定时差的时区,那么es就只需要在聚合分析结束后再根据时差将结果统一进行平移。

es上用java.time.ZoneId.getRules().isFixedOffset()方法判断时区是否有冬令时夏令时的转换。有趣的是,判断Asia/Shanghai时得到的结果居然是false,并且可以获取上一次的转换时间为1991-09-15T00:00+09:00 to +08:00。我查了一下才知道,原来中国真的在1986年至1991年间执行过六年的冬令时和夏令时。具体可以查看百科

ZoneId tz = ZoneId.of( "Asia/Shanghai" );
System.out.println(tz.getRules().isFixedOffset());	// false
Instant now = Instant.now();
System.out.println(now);	// 2020-11-17T10:25:26.989Z
System.out.println(tz.getRules().previousTransition(now));  // Transition[Overlap at 1991-09-15T00:00+09:00 to +08:00]

如果想避开timezone带来的问题,就要把时区设置为Etc/GMT-8。

ZoneId tz = ZoneId.of( "Etc/GMT-8" );
System.out.println(tz.getRules().isFixedOffset());	// true

Highlight

除了上面提到的,还可以在kibana的配置中关闭hightlight的功能,也会大大减少搜索的时间。 highlight的功能一早就被我关掉了,所以没有体现在前面的请求中。

总结

优化Discover页面搜索速度的几个办法:

  1. 为你常用的index设置更为具体的pattern
  2. 冻结不经常使用的index
  3. 在discover页面中,选择更长的时间间隔来作聚合分析。
  4. 在Kibana的配置中,把时区修改为Etc/GMT-8(根据你当前的时差去设置)。
  5. 关闭highlight的功能