ElasticStack系列之十五 & query cache 引起性能问题思考
问题描述
一个线上集群,执行的 Query DSL 都是一样的,只是参数不同。统计数据显示 98% ~ 99% 的查询相应速度都很快,只需要 4 ~ 6ms,但是有 1% 左右的查询响应时间在 100ms ~ 200ms 之间。集群硬件配置较高,使用的是 SSD 硬盘,系统可用内存远高于索引所使用内存总和的 2 倍,并且线上已经运行有一段时间了,数据也不存在是否已经预热的问题。
诊断过程
首先,通过监控系统排出集群所有关键数据,未发现任何可能引起查询耗时高的性能瓶颈问题。因此初步怀疑就是有查询本身比较慢的原因。从日志系统里拿到记录的一个耗时 150ms 的查询(这里只把关键内容粘贴出来,隐掉了非关键部分):
POST /xxxindex/xxxdb/_search?routing=Mxxxxxxx
{
"from": 0,
"size": 100,
"query": {
"bool": {
"filter": [
{
"bool": {
"must": [
{
"bool": {
"must": [
{
"bool": {
"should": [
{
"match_phrase": {
"ord_orders_uid": {
"query": "Mxxxxxxx",
"slop": 0,
"boost": 1
}
}
}
],
"disable_coord": false,
"adjust_pure_negative": true,
"boost": 1
}
},
{
"range": {
"ord_orders_orderdate": {
"from": "1405032032",
"to": "1504014193",
"include_lower": true,
"include_upper": true,
"boost": 1
}
}
},
{
"term": {
"ord_orders_ispackageorder": {
"value": 0,
"boost": 1
}
}
},
{
"bool": {
"must_not": [
{
"exists": {
"field": "ord_hideorder_orderid",
"boost": 1
}
}
],
"disable_coord": false,
"adjust_pure_negative": true,
"boost": 1
}
}
],
"disable_coord": false,
"adjust_pure_negative": true,
"boost": 1
}
}
],
"disable_coord": false,
"adjust_pure_negative": true,
"boost": 1
}
}
],
"disable_coord": false,
"adjust_pure_negative": true,
"boost": 1
}
}
}
拿到查询后,自己手动执行了一下,0hits 共耗时 1ms,应该是命中了 query cache 所以才这么快。
于是使用 clear api 清掉了 query cache,然后再执行几次,有以下发现归纳如下:
1. 前两次查询耗时 36ms 左右,这是因为没有 cache 需要访问倒排索引,耗时是符合预期的。之所以两次同样耗时,是因为索引有一个副本,两次查询分别落在了主分片和副分片上导致。
2. 接下来两次查询耗时 150ms 左右,这里此时是一头雾水留作思考?
3. 之后不管再怎么查询,耗时全部都是在 1~5ms,这是因为又开始命中 cache 了。
至此,大致明白日志中记录的高耗时是 步骤2 产生的。那么到底是什么操作会导致耗时这么久呢?根据以往的经验,我判断主要是用于为 range filter 生成缓存,也就是生成文档列表的 bitmap,然后存放到 query cache 中。
我使用的是 ElasticSearch5.5.1 版本,而在 ElasticSearch5.1.1 版本开始,去掉了对 term filter 的 cache,理由是 term filter 已经足够快了,缓存 term filter 往往得不尝试反而会白白浪费掉内存空间。那么我就将注意力集中到了查询里唯一的 range filter 上。
单独执行了一下这个 range filter,match 到的文档是千万量级的,为何这个 range filter 会 hit 到这么多的文档,通过了解得知,用户主要就是查询从当前时间开始至过去 1 年的数据,类似于做一个 [now - 1y TO now] 这样的过滤。至此初步得出结论,因为这个 range filter 匹配到的文档树太多了,在 query cache 里为这个 filter 构建 bitmap 耗时会有些高,应该就是它带来了那额外的 100 多毫秒。
但是还有一个待解释的问题,这种高耗时查询比例为何这么高?
再仔细想想也是能够想明白的:
因为这个集群的搜索并发量还是挺高的,300 ~ 400/s 的样子,加上时间字段的精度是秒,所以,在某一秒刚开始的时候,前两次查询因为没有 cache,耗时可能在 36ms 左右,之后会有 2 次查询因为需要缓冲 range filter,耗时会增加到 150 ~ 200ms 的样子,之后这 1s 里剩余的查询都会命中 cache,全部是 几 ms,直到下一秒开始,周而复始。因为每秒钟都会产生 2 个这样需要构建缓存的查询,耗时较高,对比每秒几百词的查询量,换算成百分比就有点高了。
问题修复
对于大量含有 [now - xxx TO now] 这样的 range 查询,实际上官方有对应的加速技巧介绍:Search rounded dates 也就是说,将查询时间的上下限 round 到整分钟 或者 整小时,让 range filter 可以换成的更久,避免出现这种过于频繁重建 cache 的情况。
{
"range": {
"my_date": {
"gte": "now-1y/h",
"lte": "now-1y/h"
}
}
}
在原始 query 里,将 range filter 写成以上形式,手动测试验证是可行的。range filter 有效期延长到 1小时,从而每个小时里,只需要为 range filter 重建 2次 cache,至此问题得以解决。
总结
1. cache 并非建的越多越好,因为 cache 的生成 和 销毁 会带来额外的开销,特别是结果集非常大的 filter,缓存的代价相对查询本身可能非常高。
2. ElasticSearch5.1.1 开始取消了 terms filter cache,因为 terms filter 执行非常快,取消缓存多数情况下反而可以提高性能。
3. 大量用到 [now - xxx TO now] 这样的 range filter 的时候,可以借助 round date 技巧,提高 cache 的有效期,减轻频繁重建 cache 带来的性能问题。
ElasticStack系列之十五 & query cache 引起性能问题思考的更多相关文章
- webpack4 系列教程(十五):开发模式与webpack-dev-server
作者按:因为教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<webpack4 系列教程(十五):开发模式与 webpack-dev-server>原文地址.更欢迎来我的 ...
- ElasticStack系列之十六 & ElasticSearch5.x index/create 和 update 源码分析
开篇 在ElasticSearch 系列十四中提到的问题即 ElasticStack系列之十四 & ElasticSearch5.x bulk update 中重复 id 性能骤降,继续这个问 ...
- Java 设计模式系列(十五)观察者模式(Observer)
Java 设计模式系列(十五)观察者模式(Observer) Java 设计模式系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Java ...
- Java 设计模式系列(十五)迭代器模式(Iterator)
Java 设计模式系列(十五)迭代器模式(Iterator) 迭代器模式又叫游标(Cursor)模式,是对象的行为模式.迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(interna ...
- Unity3D脚本中文系列教程(十五)
http://dong2008hong.blog.163.com/blog/static/4696882720140322449780/ Unity3D脚本中文系列教程(十四) ◆ LightRend ...
- SQL注入之Sqli-labs系列第二十五关(过滤 OR & AND)和第二十五A关(过滤逻辑运算符注释符)
开始挑战第二十五关(Trick with OR & AND) 第二十五关A(Trick with comments) 0x1先查看源码 (1)这里的or和and采用了i正则匹配,大小写都无法绕 ...
- SQL注入之Sqli-labs系列第十五关和第十六关(基于POST的时间盲注)
开始挑战第十五关(Blind- Boolian Based- String)和 第十六关(Blind- Time Based- Double quotes- String) 访问地址,输入报错语句 ' ...
- Dubbo学习系列之十五(Seata分布式事务方案TCC模式)
上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...
- ABP框架系列之十五:(Caching-缓存)
Introduction ASP.NET Boilerplate provides an abstraction for caching. It internally uses this cache ...
随机推荐
- Alpha版本BUG BASH
在本次软件开发的第一轮迭代中,我们团队遇到了很多问题.首先是和学长联系不上导致拿到项目前一版本的代码的时间延后了一个星期. 拿到代码后发现由于安装环境的问题代码无法移植.在这一阶段我们就耗费了大量的时 ...
- Git基础级介绍
这篇随笔是在学习了廖雪峰老师的git教程之后写的总结,要看详细的基础级git介绍可以去http://www.liaoxuefeng.com/wiki/0013739516305929606dd1836 ...
- First scrum meeting report - 151017
提要 今天开会主要是讨论一下北航MOOC客户端的具体要求和每个人的大致分工.会议后来还简单商讨了一下我们app的大致界面框架. 会议地点:大运村KFC 会议时间:2015年10月17日,15:00-1 ...
- YQCB冲刺第二周第二天
今天的任务依然为实现查看消费明细的功能. 遇到的问题为从数据库中分类读取,实现图标的显示. 站立会议为: 任务面板为:
- mianshi
https://blog.csdn.net/u012557610/article/details/80350099 https://blog.csdn.net/liuqiyao_01/article/ ...
- 【Coursera】应用机器学习的建议
偏差方差权衡 使用较小的神经网络,类似于参数较少的情况,容易导致高偏差和欠拟合,但计算代价较小使用较大的神经网络,类似于参数较多的情况,容易导致高方差和过拟合,虽然计算代价比较大,但是可以通过归一化手 ...
- DPDK helloworld 源码阅读
在 DPDK Programmer's Guides 中的 EAL 一篇中有一个图可以很清晰地看到一个DPDK的应用程序的大致执行思路: 初始化检查CPU支持.微架构配置等完成后,执行main()函数 ...
- 补发9.28“天天向上”团队Scrum站立会议
组长:王森 组员:张金生 张政 栾骄阳 时间:2016.09.28 地点:612寝 组员 已完成 未完成 王森 搭建初步原型 完善原型 张金生 更新UI设计 生成应用界面原型 张政 初步设计框架图 完 ...
- [日常工作] SQLSERVER 数据库出问题..搜索到的有用的网页信息
Finding a table name from a page ID By: Paul Randal Posted on: September 25, 2014 1:42 am (Check o ...
- Task的运行原理和工作窃取
在net4.0以前,当调用ThreadPool.QueueUserWorkItem方法往线程池中插入作业时,会把作业内容(其实就是一个委托)放到线程池中的一个全局队列中,然后线程池中的线程按照先进先出 ...