-
目的
复现12.21号出现的大index查询导致磁盘IO异常。
在yum2环境压测未能复现,现在在测试环境进行测试。
节点信息:
索引信息:
-
压测方案
使用esperf 工具实现并发压测。
上次压测未能实现预期效果,怀疑是压测时使用相同的请求参数,导致第1次请求的结果缓存在内存中,后续N次请求直接从内存中查询数据导致的。
本次动态修改请求参数。esperf 脚本支持传入动态参数占位符,然后从文本中抽取参数替换占位符中的变量当作实际参数。
echo '{"from": 100, "size": 1, "timeout": "60s", "post_filter": {"bool": {"filter": [{"geo_shape": {"theGeom": {"shape": {"type": "Point", "coordinates": [$RDICT]}, "relation": "intersects"}, "ignore_unmapped": false, "boost": 1.0}}, {"terms": {"brand": ["KFC"], "boost": 1.0}}], "adjust_pure_negative": true, "boost": 1.0}}, "_source": {"includes": ["id", "brand", "storeCode", "name", "areaType", "status", "updateTime"], "excludes": []}, "sort": [{"name": {"order": "asc"}}, {"storeCode": {"order": "asc"}}]}' | ./esperf -r 50 -t 1 -d ./location.txt "http://172.17.18.254:9200/emap_area_kfc_wgb_20250105_0120/_search"
说明:
-d <dictionary_file>: Newline delimited strings dictionary file
压测过程中观察 grafana 监控,查看被压测的集群的磁盘io压力状态:
infra-grafana.hwwt2.com/d/na_nxrE_m…
-
前置条件
环境复原
索引副本改为1 (现状为5)
Y2 的磁盘改为50GB (现状为200GB)
-
使用esperf 工具动态修改请求参数
-
压测状态和结果记录1
压测索引 emap_area_kfc_wgb_20250106_0120 单分片,数据量2.2gb
Es jvm参数 -xms3910 -xmx3910
压测效果如下:
压测时刻的磁盘io:Cluster-read=203io/s cluster-write=1.57io/s
io瞬时、短时间内读压力上升,是因为es将索引数据从磁盘加载到内存中。
压测时刻的CPU负载:98%
此时在内存中执行计算。
查询平均耗时:
在内存中执行计算,响应查询速度肯定很快。
esperf 压测平均响应速度维持在0.008s(8毫秒)
(初次压测忘记截图,补充 esperf 压测截图)
-
压测状态和结果记录2
对es的某个索引进行压测时,es把该索引数据从磁盘加载到内存中,所以在grafana监控面板上看到io瞬时、短时间内读压力上升。因为es jvm参数设置为 -xms3910 -xmx3910,并且该索引数据量为2.2gb,所以理论上都可以加载到内存中。
当该索引数据从磁盘加载到内存中后,磁盘负载降低,后续的查询是在内存中计算的,此时表现为CPU压力上升。
所以为了检测内存驱逐(内存不足)情况下的查询效率,需要增加压测场景:
对多个大索引同步压测,此时所有索引数据不足以全加载到内存中,会有内存驱逐,此时会服务器不停的执行以下过程:
加载数据到内存 -> 内存分析计算-> 内存驱逐 -> 加载数据到内存 -> 内存分析计算-> 内存驱逐....
此场景更能反映真实的生产环境。
预测: 此时磁盘io 读压力达到高峰后会持续一段时间,CPU负载维持在高位,内存占用维持在高位并重复驱逐动作。
实际:
磁盘io 读压力达到高峰后并没有持续一段时间。(不符合预期,估计是样本参数问题,导致所有的内存数据未加载到内存中)
调整样本参数后,iops达到新高,但还是未能实现预期。
压测时间内CPU负载维持在高位。
内存占用维持在高位并重复驱逐动作。
iops达到新高,未持续一段时间?
怀疑es加载数据使用的不是堆内内存,es在进行jvm内存回收时是不会导致索引数据失效的。
es加载数据使用的是堆外内存,使用free -m 命令查看缓存清除前后的区别:
上图中free=4032mb。
当使用echo 3 > /proc/sys/vm/drop_caches 命令释放缓存后,free=6194mb,相当于回收了2gb多的内存(与emap_area_kfc_wgb_20250107_0120 索引的数据量吻合)
iops达到新高,持续一段时间
如下,构造出多个大索引数据,对这些索引进行压测,模拟内存驱逐场景。
emap_area_kfc_wgb_20250101_0120 ~ emap_area_kfc_wgb_20250110_0120 共10个索引,并行进行压测。
在极限压测下,出现请求失败的情况。
此时测得的磁盘iops如下,极限iops压力 885 io/s:
-
结论
经过多种测试场景验证,得知磁盘IOPS升高确实是内存驱逐引起的。性能瓶颈不是在iops,而是内存。
如下以free -m 命令为例:
当服务器内存不足(表现为free 内存不足)而es需要查询其他索引需要加载更多数据时,es已加载进内存的原缓存数据会被驱逐(用于腾出内存空间以加载新索引数据),此时就会导致磁盘IO升高。
如果业务场景上在频繁的使用某些es,并且这些es数据量大于内存空间,就会导致服务器重复执行以下步骤:
-
建议
基于实际场景分析:
-
假如实际使用中es是6分片,并且不能修改分片数量或es集群不方便进行rebalance,则新增加的节点并不能均匀分摊压力,此时建议对每个节点增加硬件资源。
-
如果实际使用中可以对es进行rebalance(或者每天都是新索引,新索引可以设置新的分片数),则增加集群节点数或增加单个节点的资源均可。
另外:
- 对于es上的数据,可以计算活动期间的活跃索引数据量,计算一下这些索引的数据量,然后对比集群所有节点的 filesystem cache(可以理解为
free -m查询出的free内存),如果 filesystem cache >= 活跃索引数据量,就不会引起内存驱逐。比如我们活动期间使用到 6个索引,这些索引总数据量大概20gb(不算副本),则我们集群所有节点可用的filesystem cache 最好大于20gb。(一些轻微的数据倾斜引起的内存驱逐引/io压力不会太高) - 可以在活动期间禁止其他索引的访问,尽可能的给活跃索引腾出足够的filesystem cache(比如暂时close索引,或者客户端使用索引别名访问,活动期间临时修改索引别名)。
注:对于es独占型服务器,filesystem cache = (osMamory - es jvmHeap) * 0.8(因为系统内核会占用部分资源)
如何规划es服务的jvm参数和filesystem cache?
es的jvm虚拟机负责处理客户端的请求,它处理数据时会从filesystem cache取数据,如果数据在filesystem cache中不存在则会从磁盘加载。
如果jvm参数设置的太小,则es服务端并行处理多个索引请求时,会引起频繁的gc,影响响应速度。
如果jvm参数设置的太大,则留给filesystem cache的内存不足,可能触发内存驱逐。
建议es jvm xmx设置和filesystem cache 差不多。比如服务器32GB内存,一般内核程序等会占用2gb左右的内存空间,剩余的30gb,设置 jvm xmx15gb。