本文所涉及的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
},
所以,针对这个问题,我们可以选择下面两个方案来提高搜索速度:
- 为你常用的index设置更为具体的pattern
- 冻结不经常使用的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页面搜索速度的几个办法:
- 为你常用的index设置更为具体的pattern
- 冻结不经常使用的index
- 在discover页面中,选择更长的时间间隔来作聚合分析。
- 在Kibana的配置中,把时区修改为Etc/GMT-8(根据你当前的时差去设置)。
- 关闭highlight的功能