性能优化是降低成本的手段之一,每年大促前业务平台都会组织核心链路上的应用做性能优化,一方面提升系统性能,另外一方面对腐化的代码进行清理。现结合业务平台性能优化的经验,探讨一下性能优化的思路及常用工具及手段。性能优化本质上是对资源的合理利用,将更珍贵的资源用在更重要的业务上,从而实现资源的充分利用,资源的合理利用。性能优化的对象包括业务运行的容器、业务依赖的中间件、业务依赖的数据库存储的优化,性能优化包括两部分:一、发现需要性能优化的点;二、改造代码设计实现性能优化;

一、发现需要性能优化的点

对于业务容器来说,需要性能优化的点,往往是对系统开销最大的业务方法,这部分代码功能上并没有任何问题,但在性能上并不是最优,在资源比较充足的情况下,这部分逻辑并不会导致性能问题,但当系统压力比较大,或者业务流量比较高的情况下,这部分就会成为压力最大的点。

1)放大系统的流量

将流量在部分容器上做放大,利用工具采集系统中的堆栈及性能数据。放大系统流量的情况下,需要提前关闭应用及容器的限流,可以利用 Sentinel 脚本调整。

### 取消限流 Xcurl http://localhost:8719/switchSet?value=false
### 取消限流 Xcurl http://localhost:8718/setSwitch?value=false

一、Duct 引流验证 

Duct 引流, duct 调整某一台机器的 CS 权重,将其他容器的流量引流到对应的 ip 上,从而实现压力的放大。

二、Amazon 构造压测数据验证 Amazon 压测,根据特定的业务场景,构造压测压测数据,压测模型,在 gray4 环境中打一部分压测流量,利用压测流量将系统的负载打高。Amazon 更适用于大促场景下的性能优化,能确定某些接口的比例,及场景的比例。

2) 利用工具采集系统热点

系统负载流量增加后,各个环节的系统性能消耗都会被放大,此时利用工具可以分析系统的性能情况。系统分析工具会带来系统压力增加,非必要情况下,尽量在隔离环境统计数据。

Arthas 性能数据采集

Arthas 提供了非常多的工具脚本,其中一部分数据组合起来使用,可以很方便的辅助做性能分析及线上问题排查,这里对其中常用的指令及使用场景做汇总。
安装方式:curl -sLk http://ops.jm.taobao.org:9999/pandora-web/arthas/install.sh|  sh

性能分析及问题分析工具说明

指令 说明 性能分析及问题排查的场景
classloader 查看当前 JVM 下 ClassLoader 的列表及加载的实例统计信息 - 常见于排查 Metaspace 空间利用率问题,常见的场景是由于 Groovy 脚本导致的 Metaspace 增加,进而导致应用 FGC 的问题排查
jad 反编译 - 常见于黑盒分析,无法快速活的源码的情况下分析程序内部逻辑的场景
getstatic 获取静态字段的值 - 常见于分析开关、配置、部分数据的情况,在分析性能数据时可以辅助排查
stack  从当前方法点打印堆栈 - 常见于分析热点方法调用来源,结合条件过滤,可以快速定位到异常数据产生的来源以及调用频率
trace 从当前方法下钻 - 常见于分析耗时情况,分析某一个方法耗时的原因。比如分析鹰眼某一个接口耗时很高的原因
watch 查看方法调用的参数及返回值 - 分析线上方法的入参及返回值,结合条件判断,可以快速知道某一个函数可能走到的场景
options Arthas 的一些选项 - 在需要分析 jdk 内部的调用时,可以打开某些选项
logger 打印日志相关的信息 - 分析日志冲突,临时关闭某些日志场景等
profiler 内部使用了 Async Profiler 工具,可以用来采集内存、cpu、锁、cache miss 等火焰图数据 - 性能分析,分析当前业务的热点方法

更多内容可以学习《测试工程师 Python 工具开发实战》书籍《大话性能测试 JMeter 实战》书籍

场景一、CPU 资源开销分析

利用 profiler 指令采集应用容器的性能,profiler start 默认采集的 CPU 的数据, profiler stop 自动 dump 对应的文件数据。

[arthas@2093]$ profiler startProfiling started[arthas@2093]$ profiler stopOKprofiler output file: /home/admin/ump2/bin/arthas-output/20230213-191902.html[arthas@2093]$ exit

场景二、JVM 内存中分配了比较多的对象,但很快回收,希望找到临时对象创建比较频繁的堆栈。

[arthas@2093]$ profiler -e alloc startProfiling started[arthas@2093]$ profiler stopOKprofiler output file: /home/admin/ump2/bin/arthas-output/20230213-192148.html[arthas@2093]$ exit

场景三、应用启动速度比较慢,希望找到原因。

[arthas@2093]$ profiler start -e wallProfiling started[arthas@2093]$ profiler stopOKprofiler output file: /home/admin/ump2/bin/arthas-output/20230213-192812.html[arthas@2093]$

场景四、利用 JFR 分析 JVM 整体的运行情况,采集数据用作分析。

[arthas@82348]$ jfr start -n test[arthas@82348]$ jfr stop -r 1 -f /tmp/1.jfrStop recording 1, The result will be written to:/tmp/1.jfr

天巡数据采集性能数据

工具地址: https://explorer.alibaba-inc.com/perf/#/profile

天巡功能采集指标说明注意: 指标采集功能从实现上基本都是在运行的 JVM 进程上挂载 agent,随后对部分代码进行增强及注入,会引起类的退优化及 C2 编译,本身会导致程序的 CPU 增高,对于性能的采集不能在系统高负载的情况下执行。必要时在仿真环境里执行。


|

黑屏场景下的性能分析

特殊的环境下,可能无法使用配套的工具,此时应尽量利用 JVM 及 Linux 系统中自带的工具,采集数据后,在本地利用工具进行数据分析。一、利用 Perf 分析系统性能,Perf 是 linux 内核提供的性能分析工具,利用该工具可以很方便的分析整机的性能数据 CPU 消耗来自非 Java 程序的场景,或者希望结合 Java 程序整体分析系统情况的场景📎perf-map-agent.compiled.tgz:https://yuque.antfin.com/attachments/lark/0/2024/gz/8526/1704162543426-7fcb3be9-4465-475e-8518-4cf6449ca3c8.gz

sudo yum -y install perfsh create-java-perf-map.sh# 采集性能数据sudo perf record -ag # 分析性能数据sudo perf report


图 1.4 利用 Perf 结合 perf-map-agent 分析高 CPU 消耗数据

二、利用 jstack 分析应用的启动情况分析应用在启动过程中,应用运行的堆栈,进而分析出启动过程中,应用执行耗时最多的热点代码,进而针对性的做启动优化

$cat 1.shfor i in `seq 10000`do
  /opt/taobao/java/bin/jstack $1 > /tmp/$1.$i.log
done

三、利用 jmap、jcmd dump 数据,相关数据 dump 出来后,可以进一步通过工具进行分析

/opt/taobao/java/bin/jcmd 82348 help/opt/taobao/java/bin/jcmd 82348 help CodeCache.dump/opt/taobao/java/bin/jcmd 82348 help Compiler.CodeHeap_Analytics/opt/taobao/java/bin/jcmd 82348 JVMTI.data_dump/opt/taobao/java/bin/jcmd 82348 help Metaspace.dump/opt/taobao/java/bin/jmap -dump:format=b,file=/tmp/heap.bin 82348


图 1.5 jcmd 分析 CodeCache 的大小及区间数据

二、常见的性能优化点及优化方式



|

三、影响性能的因素

经常会出现同样是 8C16G 的容器,但表现出来的性能确差异很大,这个在集团内表现尤为明显,这种情况实际和集团内部的编排策略有一定的关系。也可能和集团内部的机型差异存在关系。一、由于机型原因引起性能差异目前集团存在多种不同的机型,F4x、F5x、F6x、M 机型等。不同的机型单核性能上表现会有差异。

二、由于编排方式带来的性能差异

在 X86 架构下,由于超线程的存在,业务容器实际使用的是物理核心上的超线程,当一个 8C16G 的容器独占 8 个物理核的时候,性能会最好。当 8C16G 的容器占用 4 个物理核的时候,性能会相对最差。结合跨 Numa、跨 socket 等编排方式,也会带来性能的差异。

图 1.5 应用容器编排示意

四、外部依赖优化

数据库慢查询的优化

数据库侧的性能问题,主要有以下集中情况导致,常见的优化手段为:一、合理利用前置的缓存,降低对数据库的访问量。缓存从效率及成本上都优于数据库。二、清理数据库中的数据,对过期的数据、访问量少的冷数据进行清理及迁移。降低数据库的存储大小,对在线的查询会有帮助,对离线的存储、引擎、缓存等场景也会有收益。三、合理调整索引,结合业务场景丰富查询条件,提高数据库的执行效率。四、利用数据库聚合特性,调整主键的组成,提高数据的聚合度,降低逻辑读。

缓存类优化(Tair、Redis)

缓存类存储对随机的访问上效率上都非常高,在日常及大促的核心场景中发挥比较大的作用。缓存类常见的问题:

五、应用链路之间的优化

应用间链路依赖,一般是在单应用容量优化完成后,从整个链路上考察,优化链路的 RT 及链路的 CPU 开销。一般应用链路的优化,需要结合应用链路分析来考虑,这里主要利用鹰眼的数据进行分析。


图 1.6 利用鹰眼查找核心接口上耗时比较大的链路

六、最后

Q:例如 ASI 排查场景中,看到 pod cpu 高 或者 load 高,但根因是出在其他地方,可能是安全插件 rasp 负载高、也可能是后台异常内存回收、也可能是宿主机负载高导致,现在全凭经验做排除法,有没有类似字典的方式手段定位问题?A:一般情况下出现这种情况,可以从几个角度缩小问题产生的范围。1)是不是该宿主机上的所有容器都有类似的表现?如果所有容器都有类似的表现,那基本上是宿主机的问题,可能是由于离线导致,可能是由于内存回收,可能是由于部分 agent 导致,此时 case by case 分析,也可以让 TRE 团队协助分析。2)如果宿主机上只有本容器出现问题,大概率是本容器自身的问题,此时可以从几个角度入手:

Q:平台中使用到了云平台中相关的中间件比如 Kafka、Redis 等,由于平台运行环境(Daily、PPE、Online)不同最少需要申请两个实例,一个 Daily 实例和 Online 实例。Online 环境申请的规格是最低配置就可以满足,同时 Daily 环境中平台流量很小所以最低规格配置就大大浪费了,但是云平台又不支持更小规格配置申请,能否和云平台的同事沟通下此类问题。A:弹内一般情况下,数据库节点、缓存节点实际规格非常小,成本相对比较低。如果对成本有更进一步的诉求,可以考虑多业务公用的方式,一般情况下日常的存储及 QPS 量级均非常小,若干个业务共用同一套存储不会带来太大的问题,对于缓存需要重点考虑的就是隔离的问题,这部分可以通过工具方式解决。

更多内容可以学习《测试工程师 Python 工具开发实战》书籍《大话性能测试 JMeter 实战》书籍

转载于岱泽 阿里云开发者


↙↙↙阅读原文可查看相关链接,并与作者交流