Elasticsearch 数据落盘异常优化

204 阅读3分钟

今天任务在将数据写入Elasticsearch的时候出现了异常,定位问题花了很久,这里记录一下解决过程。

从某一刻开始写入任务开始失败,紧接着大部分任务开始写不进去,但是一小部分任务仍然能正常写入数据,写入数据的任务是执行Spark SQL将数据从Hive中查询处理然后写入Elasticsearch,看任务日志是在写入的时候连接不到Elasticsearch集群的client,报错org.apache.spark.util.TaskCompletionListenerException: Connection error (check network and/or proxy settings)- all nodes failed; tried [[xxx1:9200, xxx2:9200, xxx3:9200]]:

image.png

看到这个报错第一反应是网络不通,怀疑是不是Elasticsearch集群的网络变动了,于是让运维检查没动过,紧接着登录Spark集群的一个节点,然后尝试ping Elasticsearch集群的client节点,发现能够ping通,从ES集群节点也能反向ping通Spark集群节点,这说明网络没有问题,然后怀统是不是鉴权信息过期了,但是数据在写入的时候用的是用户名和密码,不可能是过期了。通过ES-state监控看到ES集群状态良好,但是通过ES集群节点监控可以看到部分节点GC时间特别长:

image.png

接着进入GC时间最长的ES节点看了一下日志,发现这段时间进程一直忙着做垃圾回收,于是猜测这应该是新生代young区域的对象无法正常回收进入老年代old:

image.png

然后看了一下该进程启动的时候用的是G1垃圾回收机制,看网上的说法是Eden 区新生代的大小初始默认为整个堆大小的5%,在JVM运行的过程中会进行动态扩充,但其最大不会超过堆大小的60%。可以通过参数-XX:G1NewSizePercent=5 和 -XX:G1MaxNewSizePercent=60调整该值,但是集群使用的G1MaxNewSizePercent=200,不知道有没有影响,这时尝试重启ES集群,应该不会花大量时间去进行垃圾回收,但是一旦写入进程过大还是报同样的错,有点纳闷,按理来说不应该有写入限制的,因为之前也是这么多进程写入的,一个大佬指点了一下,说ES数据落盘过程是先写入buffer然后refresh到cache,最后落到磁盘segment file文件里面,可以看一下相关参数,搜了一下发现ES默认自动刷新索引:

image.png

猜测可能是索引刷新太频繁了,于是尝试写入时设置es.batch.write.refresh=false,再次运行发现写入成功,立即在所有的任务中加上这个参数发现均能运行成功,同时,也设置一下es.batch.size.bytes=2mb,es.batch.size.entries=2000,保证批量刷新的时候不至于太少。

总结:写入ES失败报错排查先从报错开始排查,借助监控拓展思路,但同时也要对ES的写入原理很熟悉,我这里是大佬指导,后续还得多学习弥补,借大佬的话结尾:任何一个问题都是技术和业务碰撞的结果,不能单方面入手,要学会多角度切入。共勉!