【ElasticSearch】_cat/nodes接口影响集群写入性能问题排查及修复

问题

当集群分片数达到140K以上时,ES的_cat/nodes被调用后协调节点出现写入性能下降的问题

原因分析

  1. 根据硬件资源分析
    FGC time有突增,CPU、IO指标没有变化,进一步查看细粒度的GC指标(jstat -gcutil)。可以看出在调用_cat/nodes后内存逐步上升,发生了一次长达7秒的FGC
    怀疑点:
  2. _cat/nodes返回的结果过大占用的很多内存
  3. _cat/nodes执行过程创建了大量对象
  4. 对象分配分析
    方法:通过使用async-profiler生成_cat/nodes执行过程中协调节点上的对象分配火焰图,查看_cat/nodes执行过程中对象分配情况,确定上述的怀疑点是否成立
    结果:cat/nodes执行过程中创建对象的大小仅占总大小的3.77%,上述怀疑点不成立
    在这里插入图片描述
    方法(交叉验证):使用MAT分析接口调用时的堆内存,查看是否有_cat/nodes执行过程创建的大对象
    在这里插入图片描述

结果:没有找到_cat/nodes创建的任何大对象

代码路径分析

_cat/nodes接口执行流程如下:

  1. 协调节点向Master发起请求获取集群元数据
    1. Master节点从内存获取元数据返回给协调节点
  2. 协调节点向所有节点发起请求获取nodes/info(包含indices,jvm,os,http,process等初始信息,无论请求是否标识了获取该信息)
    1. 所有节点从内存中直接获取nodes/info并返回给协调节点,nodes/info在节点启动时已初始化,无需计算
    2. 协调节点收到其他节点的响应后将返回值保存到内存
  3. 协调节点向所有节点发起请求获取nodes/states(包含indices,jvm,os,http,process等所有的运行时信息,无论请求是否标识了获取该信息)
    1. 所有节点检查节点的运行信息是否需要刷新(根据刷新间隔判断)。如果需要则调用API获取运行信息,否则直接返回上次获取的运行信息
    2. 协调节点收到其他节点的响应后将返回值保存到内存
  4. 将上面获得的三部分信息和请求参数(指定获取的指标)进行格式化并返回给客户端

结论:从代码流程来看,_cat/nodes过程中协调节点没有创建大量对象,但对于节点响应的处理次数和节点数量相关,所以怀疑_cat/nodes过程占用了较多的CPU

再次回到硬件指标

上文观测的CPU指标为有写入流量情况下的分钟级粒度的CPU load/CPU使用率指标,可能由于该指标存在的局限性导致结论有误,局限性如下

  • _cat/nodes接口的执行时长少于1分钟,CPU使用率是瞬时值,获取CPU使用率时可能ES没有在执行_cat/nodes。顺便说一句,GC指标为当前GC总时间瞬时值减去上一分钟GC总时间瞬时值,所以不会有这个问题。
  • CPU load指标的计算口径是1分钟内的平均值,_cat/nodes带来的CPU影响会被均摊或减弱。GC指标不会有这个问题
    因此,我们需要观测秒级的CPU使用率指标,并且关闭写入流量来排除写入带来的影响。指标获取语句:top -b -p 437645 -n 1 | awk ‘NR>7’ >> top_output.txt
    在这里插入图片描述

结论:_cat/nodes接口调用后,CPU使用率突增6.7% -> [600% ~ 1447%]。

CPU分析

火焰图中NioEventLoop.run栈帧及其上面栈帧为_cat/nodes执行过程中调用的,NioEventLoop.run方法调用的方法可以分为三个部分NodeStats.,NodeInfoRequest.writeTo和NodeStatsRequest.writeTo分别对应代码路径分析中的3.b,2,3部分
在这里插入图片描述

为什么上述方法的CPU占用和集群规模相关?

NodeStats.分析

该方法CPU占用较多且最底层的方法是ShardStats.,ShardStats.被调用的时机为根据其他节点的响应反序列化每个分片的指标,每个节点返回给协调节点它拥有的分片指标。ShardStats.方法的触发次数为集群总分片数。因此ShardStats.的时间复杂度=O(分片数)。

NodeInfoRequest.writeTo和NodeStatsRequest.writeTo分析

这两个方法很相似所以放在一起分析。方法被调用的时机是协调节点将NodeInfoRequest或NodeStatsRequest进行序列化过程中,序列化后将请求发送给集群里的其他节点。这两个方法CPU占用较多且最底层的方法是DiscoveryNode.writeTo,该方法是将请求中的DiscoveryNode对象序列化,DiscoveryNode是ES节点的抽象,一个请求中包含所有节点的DiscoveryNode对象。DiscoveryNode.writeTo方法的触发次数为节点数请求数=节点数节点数。因此NodeInfoRequest.writeTo和NodeStatsRequest.writeTo的时间复杂度=O(节点数^2)。

原因验证

验证方法:通过侵入代码去除ShardStats.和DiscoveryNode.writeTo过程,观察协调节点执行_cat/nodes过程的CPU使用情况和Full GC情况
验证结果:

  • 无写入流量时的CPU使用情况
    在这里插入图片描述

  • 有写入流量时的Full GC情况和写入延时无异常

结论:_cat/nodes接口被调用后协调节点触发的请求序列化(主要是节点列表数据结构)和分片级别指标反序列化产生了大量的CPU开销,导致写入性能受到影响

提issue给社区

#99744

问题解决

a. DiscoveryNode部分 #99990 #99938
b. Shards stats部分 #100466.

[root@mobilexw ~]# curl -XGET localhost:9200/_cluster/allocation/explain {"note":"No shard was specified in the explain API request, so this response explains a randomly chosen unassigned shard. There may be other unassigned shards in this cluster which cannot be assigned for different reasons. It may not be possible to assign this shard until one of the other shards is assigned correctly. To explain the allocation of other shards (whether assigned or unassigned) you must specify the target shard in the request to this API.","index":"pds_dacfga_egebpl","shard":0,"primary":true,"current_state":"unassigned","unassigned_info":{"reason":"ALLOCATION_FAILED","at":"2025-03-02T16:10:26.604Z","failed_allocation_attempts":1,"details":"failed shard on node [4bMI2hXVThm4Qr1axNbCjA]: shard failure, reason [merge failed], failure MergeException[org.apache.lucene.index.CorruptIndexException: checksum failed (hardware problem?) : expected=77ca06fc actual=dc58566c (resource=BufferedChecksumIndexInput(MMapIndexInput(path=\"/opt/dpmon/server/vendor/elasticsearch/data/nodes/0/indices/uiziMJtlSXWQ4SCFdQ8zPQ/0/index/_39qu.cfs\") [slice=_39qu_Lucene80_0.dvd]))]; nested: CorruptIndexException[checksum failed (hardware problem?) : expected=77ca06fc actual=dc58566c (resource=BufferedChecksumIndexInput(MMapIndexInput(path=\"/opt/dpmon/server/vendor/elasticsearch/data/nodes/0/indices/uiziMJtlSXWQ4SCFdQ8zPQ/0/index/_39qu.cfs\") [slice=_39qu_Lucene80_0.dvd]))]; ","last_allocation_status":"no_valid_shard_copy"},"can_allocate":"no_valid_shard_copy","allocate_explanation":"cannot allocate because all found copies of the shard are either stale or corrupt","node_allocation_decisions":[{"node_id":"4bMI2hXVThm4Qr1axNbCjA","node_name":"node-1","transport_address":"10.39.0.162:9300","node_attributes":{"ml.machine_memory":"67387416576","xpack.installed":"true","transform.node":"true","ml.max_open_jobs":"512","ml.max_jvm_size":"4294967296"},"node_decision":"no","store":{"in_sync":true,"allocation_id":"u37eokDMRGyGni3c6xnwdw","store_exception":{"type":"corrupt_index_exception","reason":"failed engine (reason: [merge failed]) (resource=preexisting_corruption)","caused_by":{"type":"i_o_exception","reason":"failed engine (reason: [merge failed])","caused_by":{"type":"corrupt_index_exception","reason":"checksum failed (hardware problem?) : expected=77ca06fc actual=dc58566c (resource=BufferedChecksumIndexInput(MMapIndexInput(path=\"/opt/dpmon/server/vendor/elasticsearch/data/nodes/0/indices/uiziMJtlSXWQ4SCFdQ8zPQ/0/index/_39qu.cfs\") [slice=_39qu_Lucene80_0.dvd]))"}}}}}]}[root@mobilexw ~]# 这个报错里面有pds_dacfga_egebpl这个索引的信息吗?
03-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值