7.6.2 ES scroll游标BUG解决方案汇总

62 阅读3分钟

在本地经过长期验证,已在本地测试环境3节点集群进行150亿次左右的scroll查询,7.6.2版本es游标查询bug未能在本地复现。

在源码上尝试复现bug,做过如下尝试:

尝试使用源码中提供的测试类进行测试也未能成功复现。

修改源码尝试在es初始化阶段直接给scroll计数器赋值模拟bug未能成功。

尝试使用java反射机制修改scroll计数器(不可行)




  1. 升级版本(官方建议)

es7.7.0版本修复了此bug,由于7.7.0版本引入了lucene8.5,导致的fetch耗时增加问题无法通过调优解决。

在升级到7.7.1版本发现fetch耗时有50%-100%的增加。此方案会造成较为明显的性能下降,目前已在7.7.1 , 7.7.0 , 7.10.1版本发现均存在性能下降问题。




  1. 将max_open_scroll_context参数设置为int最大值(官方给出的解决方案)

修改参数 search.max_open_scroll_context=2147483647

风险:在极端情况下可能会存在大量scroll上下文。

但是在scroll查询完成后手动释放scroll上下文(java客户端程序做的处理)和 scroll到期清除(es自身特性)两种机制的保障下,集群不会存在太多的scroll上下文。

方案出处:

github.com/elastic/ela…




  1. 修改源码重新打版(风险较高)

基于es 7.6.2源码修复滚动游标超限问题并重新编译打包,直接修改源码的话可能会引入不可预知的兼容性问题。滚动游标的修改涉及到底层分片管理,非官方修复容易导致数据一致性风险。(这个方案挑战大,时间和质量风险不可预估)。




  1. 通过脚本实现scroll阈值控制(可作为长期解决方案)

grafana监控scroll_current值,在检测到发生溢出时进行告警,同时用脚本定时获取scroll_current,检测到溢出,设置search.max_open_scroll_context = 2147483647。通过脚本来实现原有的scroll阈值控制。

暂时无法在飞书文档外展示此内容

脚本实现方式:

  1. scroll_current状态获取

分两种情况

  • 溢出发生前

脚本获取scroll_current将直接从http://localhost:9200/_nodes/stats/indices/search 进行获取,不依赖Prometheus数据源。

  • 溢出发生后

scroll_current = 2147483647,已无法再从http://localhost:9200/_nodes/stats/indices/search获取正确的scroll_current 数量。需要根据scroll_total进行计算。(计算出来的scroll_current不是绝对准确值,但可以作为判断集群当前scroll状态的一个依据)

通过脚本最近几次采集的历史scroll_total值,推算当前scroll趋势及存量,从而判断是否达到阈值。

  1. 清理动作:
curl --location --request DELETE 'http://ip::9200/_search/scroll/_all'

3. 执行周期:

使用crontab作为定时器,定时执行脚本,此方法可行性较高,且不需要脚本一直处于运行状态。

  1. scroll释放周期:

scroll在查询完成后进行释放(java客户端程序使用scroll查询后会主动释放scroll)。

scroll在创建时会设置一个生命周期,到期自动清除(es自身特性)。 脚本实现的阈值相当于一个保险机制,防止scroll占用系统资源过大。