在某一天,我们的系统突然异常,大面积出现白屏,搜索页面点击后,响应非常慢,大量出现响应超过4秒的情况,异常高峰期平均查询时间达到10多秒,后台不断有ES服务宕机重启,GC告警频繁,经过一阵排查折腾,发现居然是简单的_uid字段排序导致的,下面就详细的讲一下。
我们的ES搜索收到一个小小的需求,原来我们的搜索,新的结果会被放到后面去,产品经理希望能够对搜索结果进行排序,按照创建时间倒序排序。
这里自然的相对用ES系统字段_uid进行倒序排序,因为这个字段是按照创建时间生成的,结果问题来了,这么一个简单的排序功能,居然产品了一次严重故障。
首先,_uid是fielddata 类型,这是ES特有的特性,它能够将数据预加载在内存中,从而提高搜索速度。
但是呢,我们的业务数据量极大,达到几十亿数据量级别,当_uid被加载到内容中的时候,就占用了es集群大量的内容,这部分内存并不会主动回收,导致服务器不断的GC停顿。数据被逐出导致查询很慢。
Fielddata之所以占用很多内存的主要原因:
假设你的查询要求只返回命中的 100 个结果,ES的fielddata 并不管你这个查询是怎么样,所以它并不会只加载 100 个文档。而是fielddata 会加载索引中 所有的 文档。官方文档是这样解释的:如果查询会访问文档 X、Y 和 Z,那很有可能会在下一个查询中访问其他文档。