咱们团队基于Elasticsearch开发了一款将数据从数据库实时同步至Elasticsearch的工具——搜寻平台,其实现形式次要是通过flink将数据库中已有的存量数据导入Elasticsearch,并订阅数据表的binlog,将实时改变也同步至Elasticsearch。
问题发现
AIoT团队在搜寻平台上保护了一个较大的索引,其写入均匀有2k到3k的tps,查问也有数百QPS。因为该索引较重要且占用资源较多,因而应用Elasticsearch的template性能将之独自部署在专用的机器上。
从5月底开始,写入此索引的flink实时工作就会偶现失败重启的状况,经排查,发现是写入Elasticsearch的申请超时导致的,联合过后机器的cpu占用等指标断定是写入tps过高导致Elasticsearch无奈接受,因而,将该索引所占的机器从2台降级到3台,并应用业务数据进行了一轮写入压测,发现能撑持业务方的写入速率,扩完后较长一段时间内,该索引也始终没有呈现问题,因而认为问题曾经被解决了。
问题排查
然而,在6月22日凌晨,上述问题再次出现,通过查看指标,发现过后的写入速率并无显著晋升。
1.索引写入速率
既然不是由写入速率晋升造成的,那就接着排查其余可能占用CPU资源的行为。
2.索引查问速率
3.jvm gc次数
4.节点merge速率
5.节点写入队列长度
由上述指标能够看出,写入耗时过久是因为索引的其中一个节点写入队列过长,无奈及时处理写入导致的。然而在写入队列变长的过程中,节点的gc,merge等操作并无显著变动,索引的查问速率也没有显著晋升,因而猜想是某些具备非凡特色的文档导致es写入过慢导致的。
在上述猜想下,咱们的思路就变成了找出导致索引过慢的罪魁祸首文档。因而就从埋点数据中收集了很多慢索引文档,尝试手动索引,但均能很快索引实现。
然而线上问题仍旧存在,为了使业务不出问题,咱们从以下伎俩尝试修复线上问题:
1.减速Elasticsearch的索引效率
- 调大索引的refresh_interval参数
- 批改index.translog.durability为async等
- 敞开局部字段的索引配置
2.升高flink工作的写数据频率
然而每次尝试均以失败而告终,每次都是实时工作启动不久,写入就超时了。然而在一直排查问题过程中,发现了此问题的以下特色:
- 批量工作与实时工作的写数据TPS差不多,然而批量工作就不会有问题
- 每次出问题的机器都不是同一台
因而,不是机器的问题,应该也不是某些文档的问题(因为后续重建索引时会把之前实时工作同步的文档移到批量工作阶段同步)。因而,为了搞清楚Elasticsearch在这个阶段到底在做什么导致无奈写入数据,咱们选取了一个写入队列很长的节点,执行了数次jstack指令,获取Elasticsearch过程的执行堆栈后,发现其中的8个write线程很长时间都处于WAITING状态,其调用堆栈如下:
最初通过查看对应版本的Elasticsearch源代码,发现Elasticsearch的write线程在执行文档的索引操作时须要获取文档主键对应的锁,以避免不同线程同时批改同一篇文档,而出问题时,write线程大部分工夫都是在期待这个锁,那就阐明很可能是因为实时工作往Elasticsearch批量写入的文档里很多都是同一个主键的,导致write线程的锁争用状况十分重大,起初通过剖析数据binlog验证了这个猜测。同时也能够解释上述两个问题:
- 因为批量工作是从数据库中获取数据,对同一个id的屡次批改并不会保留历史记录,只会存储以后快照,而实时工作的数据源来自数据库的binlog,其中保留了数据表的所有改变,对同一个id屡次批改都会反复同步至Elasticsearch
- 因为每次大量批改的数据id不同,因而路由到的节点也不同,导致每次都会在不同节点上出问题。
问题解决
在确定问题的具体起因之后,咱们批改了同步实时数据的flink工作,应用滚动窗口聚合一段时间内的binlog,将之去重,在窗口完结时再把数据写往Elasticsearch。通过这种形式,升高了反复id呈现的频率,然而会导致数据同步的时效性缩短一个窗口的工夫。与业务方协商后,将窗口定位5s,并不会对业务造成影响,上线后终于解决了这个问题。
(本文作者:盛晓昌)
本文系哈啰技术团队出品,未经许可,不得进行商业性转载或者应用。非商业目标转载或应用本文内容,敬请注明“内容转载自哈啰技术团队”。