记一次ES查询优化
[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/design/ES-Query-Optimization.html
除此,还有一个比较好的优化,见: ES文档结构优化
背景
难得有数据留存,写一篇^_^
原逻辑
- ES接收新单、改单、状态数据(占总数据的70%),写入ES的7天索引中
- ES存在以天为单位的7个索引(如:20210101~20210107,7个索引)
- 存储逻辑:
- 根据订单创建时间,保存到对应月日的索引内,如:1月1日的保存到20210101
- 如果不再最近7天内的特殊订单,那么会存到今天最新的一天的索引内
- 查询查询:
- 接收到查单请求后,根据订单创建时间,根据月日指定去查询这7个索引的某一个或多个
- 如果是在最近7天的,那么保存到该日期对应的索引内
- 如果在最近7天以外的订单,那么会保存到今天最新的一天的索引内
- 更新逻辑:
先查询出原来的订单,然后更新,更新后保存到原来的索引内
初步分析
监控问题分析
大数据监控显示:在双十一前后ES监控IO读写次数过高,出现读/写拒绝,CPU占用高,初步分析主要原因有以下:
- 量大:写入ES的数据为新单、改单、状态变化3种,其中状态变化占据最多,共2亿/天的量
- 查询多:接收新单、改单、状态都需要查询一次ES
- 大部分查询无法使用索引:状态数据没有有效索引,会触发ES全局查询
初步分析人话结论
其实之中最主要的问题是因为接收状态数据的时候,没有创建时间字段,导致触发了ES全索引查询
状态数据量大,占大头,导致触发ES查询的量占超过70%,蛇打七寸,解决状态数据的查询问题,基本就可以解决问题了
场景论证
原逻辑场景分析
场景1
- 改单数据在7天外
- 操作状态数据无CreateTm字段,故7天内的单对应的状态与7天外的改单一致
有效查询率: 仅为1/35=2.85%
场景2
- 下改单数据为7天内的数据
有效查询率: 仅为1/5=20%
思路与方案
思路
其实经过场景论证后思路很明显,真正的问题所在便是接收新单、改单、状态数据的时候时间字段无法很有效地为ES查询指定分区,导致一个查询查了7个索引。
那么,问题解决思路就简单了:
- 为新单、改单、状态数据选择新的字段匹配ES索引,不再使用或者不再仅使用createTm字段
- 如1无法实现,ES换一个索引分区方式,如按照地区分区
很幸运的是,在思路1中,我们的内部订单号里包含着订单的创建时间,所以我们可以直接使用订单号来匹配ES索引,这样就可以很好地解决问题了。
优化方案
- 根据
订单号
规则,优化索引:
订单号004150222
12022830806377748,其中0222
为为订单生成日期
故直接以其为分区素引,直接查询、 更新该素引,根据场景不同至少减
少6/7
的查询量
Other More
其实在上面演示的图解里还能发现,在每个索引里还存在5个分片,也许是因为当初大数据团队操作问题又或是什么原因没有把内部订单号作为ID,
导致通过内部订单号到ES查询订单信息的时候,ES会把这个订单号的所有分片都查询一遍,这也是导致ES查询量过大的一个原因。
额外优化
通过ES-API 指定查询路由/D,可以指定查询到唯一—个分片,减少80%
的查询量
优化后
优化后逻辑
优化后逻辑(7天外)
减少6/7(85.7%)查询量
优化后逻辑(7天内)
减少4/5(80%)查询量
优化后效果(监控)