写点什么

支付宝的性能测试

2014 年 5 月 22 日

一、性能测试支付宝场景介绍

2013 年双 11 过程当中,促销开启的第一分钟内支付宝的交易总额就突破了一亿元,短时间内大量用户涌入的情况下,如何保证用户的支付顺畅,是对支付宝应用系统的一个极大的挑战。

支付宝的性能测试场景分为性能基线测试,项目性能测试。

任意一笔交易过来,我们都需要对交易进行风险扫描,对于有可能是账户盗用的交易,我们会把这笔支付直接拒绝掉,或者通过手机校验码等方式进行风险释放。

我们有一个老的扫描平台 A,现在需要构建一个新的扫描平台 B,对 A 中关键技术进行升级,并增加额外的功能。扫描的策略是存储在 DB 中的,需要通过发布来更新到应用服务器的内存中。

二、性能测试需求分析和方案制定

a. 需求挖掘

1), 查看业务方的显性需求。业务方给到的需求为平台 B 的分析性能要优于平台 A 的性能。除此之外无其它的需求。

2), 挖掘隐性需求. 了解业务架构,了解业务流程。为了保证扫描的性能,大量的存储类的需求被设计为异步处理,但是结果类的扫描需要使用到前面落地的数据,那么在系统正常运行时是否会存在落地数据读取不到的问题,在存储抖动时是否会导致后续的分析扫描全部失效?

首先我们通过运维监控平台拿到平台 A 的分析性能,RT<130ms, TPS>35.

基于以上的需求挖掘,我们确认的性能测试场景为

  1. 扫描性能场景。(单场景)
  2. 发布性能场景。(单场景)
  3. 扫描过程中发布性能场景。(混合场景)

b. 技术方案

1). 评估我们的系统架构,系统调到链路,定位可能存在问题的瓶颈点。

2). 掌握详细技术实现方案,了解具体技术方案可能存在的性能问题。

比如我们是否使用到了脚本动态编译,是 Java 脚本还是 groovy 脚本。是否使用到了线程池等异步处理,系统幂等性是如何控制的,数据结构是如何存储与读取的,是决策树还是图型结构。

3). 了解系统环境的差异,比如服务器位数、CPU、内存的差异,JDK 版本及位数的差异。

基于以上的技术方案,我们确认了上述 3 个性能测试场景可能存在的性能问题

1. 扫描性能场景

技术方案为扫描引擎 drools2 升级到了 drools5.

性能关注点为请求扫描 RT,TPS 是否满足我们的需求;JVM Old 区内存溢出,Old 区内存泄露;GC 频率过高。CPU 使用率,load.

2. 发布性能场景

技术方案为规则 DB 捞取 -> 规则加载 -> 规则引擎切换 -> 规则脚本编译。

性能关注点为 CPU 使用率,load。JVM Perm 区内存溢出,Perm 区内存泄露,GC 频率过高。GC 暂停应用时间。

3. 扫描过程中发布性能场景。

性能关注点为请求扫描 RT,TPS。规则发布耗时,CPU 使用率,load, JVM GC 频率。

c. 性能测试方案制订

  1. 分布式压测,参数自动化,使用单元测试脚本,接口测试脚本,jmeter 脚本等进行压测。
  2. 性能结果收集及统计。
  3. 性能测试通过标准。

基于以上的分析

1. 扫描性能场景

性能测试方案:

使用 jmeter 脚本进行分布式压测,一台 master, 三台 slaver. 参数自动构建,使用高斯定时器模拟真实场景。

使用 jmeter 收集分析性能数据,使用 nmon 收集服务器性能数据,使用 jconsole 收集 JVM 数据。

通过标准:

RT<130ms, TPS>35.

JVM old 区内无内存泄露,无内存溢出。GC 时间间隔 >30min,暂停应用时间 <150ms.

CPU<70%, load < core*1.5。

2. 发布性能场景

性能测试方案:

发布时间间隔时间限制从 1min 调整为 3s, 更快的暴露问题。

使用单元测试类推送发布消息。

服务器 shell 脚本收集发布模块性能数据。

使用 nmon 收集服务器性能数据。

使用 jconsole 收集 JVM 数据。

通过标准:

JVM Perm 区内无内存泄露,无内存溢出。GC 时间间隔 >10min,暂停应用时间 <200ms.

发布时间 <30S

CPU<70%, load < core*1.5。

3. 扫描过程中发布性能场景

性能测试方案:

使用 jmeter 脚本进行分布式压测,同时提交发布请求进行发布。

同时使用扫描性能场景和发布性能场景收集数据功能。

通过标准:

RT < 扫描性能场景结果 RT * 110%.

TPS > 扫描性能场景结果 TPS * 90%.

发布时间 < 40s。

d. 发现的问题

1. 扫描性能场景

AVG RT = 473ms, CMS GC = 90ms, 应用暂停时间 = 1s, 因此测试未通过。

问题定位:

dump 内存,使用 ibm memory analyzer 分析。

确认 cms gc 的原因为 drools 引擎的 finalize 方法。Finzlize 方法不能正确的释放对象的引用关系,导致引用关系一直存在,无法释放。

调优方案:

根据 drools 的升级文档,升级 drools 引擎后解决此问题

2. 发布性能场景

CMS GC 回收失败,内存无法被释放,应用宕机。

问题定位:

GC 回收比例为默认值 68%,OLD 区内存 1024M,那么回收的临界值为 1024*0.68=696.32M。系统的 JVM 内存占用为 500M,扫描策略相关的内存为 120M,在切换的过程中,依赖额外的 120M,因此只有在可用内存大于 740M 时才能正常回收。

解决方案:

调整 JVM 参数,扩大 GC 回收比例。

后续技术方案改造,使用增量发布解决此问题。

3. 扫描过程中发布性能场景

问题定位:

扫描平台发布流程,当首次请求进来时执行脚本动态编译过程,由于脚本较多,因此所有脚本的动态编译时间较长,在此过程中,进来的所有请求都会被 hand 住,造成大量超时

解决方案:

把脚本的动态编译提前到首次请求调用进来之前,编译通过后再切换扫描引擎,保证首次请求进来前一切准备就绪。

三:性能测试的执行和结果收集

3.1 性能测试的执行

性能测试的执行需要具备以下几个条件:施压工具, 测试环境以及对测试结果的收集工具。

3.1.1 施压工具

我们先来说说施压工具,支付宝使用的主流施压工具是开源工具 Apache JMeter,支持很多类型的性能测试:

  • Web - HTTP, HTTPS
  • SOAP
  • Database via JDBC
  • LDAP
  • JMS
  • 任何用 java 语言编写的接口,都可二次开发并调用。

支付宝大部分接口是 webservice 接口,基于 soap 协议,且都是 java 开发,所以使用 jmeter 非常方便,即使 jemter 工具本身没有自带支持的协议,也可以通过开发插件的方式支持。

3.1.2 测试环境

测试环境包括被压机和施压机环境,需要进行硬件配置和软件版本确认,保证系统干净,无其他进程干扰,最好能提前监控半小时到 1 小时,确认系统各项指标都无异常。

另外除了被压机和施压机,有可能应用系统还依赖其他的系统,所以我们需要明确服务器的数量和架构,1 是方便我们分析压力的流程,帮助后面定位和分析瓶颈,2 是由于我们线下搭建的环境越接近线上,测试结果越准确。但是通常由于测试资源紧张或者需要依赖外围,例如银行的环境,就会比较麻烦,通常我们会选择适当的进行环境 mock。当然,Mock 的时候尽量和真实环境保持一致,举个简单的例子,如果支付宝端系统和银行进行通信,线上银行的平均处理时间为 100ms,那么如果我们在线下性能测试时需要 mock 银行的返回,需要加入 100ms 延迟,这样才能比较接近真实的环境。

另外除了测试环境,还有依赖的测试数据也需要重点关注,数据需要关注总量和类型,例如支付宝做交易时,db 中流水万级和亿级的性能肯定是不一样的;还有 db 是否分库分表,需要保证数据分布的均衡性。一般考虑到线下准备数据的时长,一般性能测试要求和线上的数据保持一个数量级。

3.1.3 测试结果收集工具

测试结果收集主要包括以下几个指标:

响应时间、tps、错误率、cpu、load、IO、系统内存、jvm(java 虚拟内存)。

其中响应时间、tps 和业务错误率通过 jemter 可以收集。

Cpu、load、io 和系统内存可以通过 nmon 或 linux 自带命令的方式来监控。

Jvm 可以通过 jdk 自带的 jconsole 或者 jvisualvm 来监控。

总体来说,监控了这些指标,对系统的性能就有了掌握,同样这样指标也可以反馈系统的瓶颈所在。

四.性能测试瓶颈挖掘与分析

我们在上面一章中拿到性能测试结果,这么多数据,怎么去分析系统的瓶颈在哪里呢,一般是按照这样的思路,先看业务指标:响应时间、业务错误率、和 tps 是否满足目标。

如果其中有一个有异常,可以先排除施压机和外围依赖系统是否有瓶颈,如果没有,关注网络、db 的性能和连接数,最后关注系统本身的指标:

  1. 硬件:磁盘是否写满、内存是否够用、cpu 的利用率、平均 load 值
  2. 软件:操作系统版本、jdk 版本、jboss 容器以及应用依赖的其他软件版本
  3. Jvm 内存管理和回收是否合理
  4. 应用程序本身代码

先看下图:是一般性能测试环境部署图

1.

我们在定位的时候,可按照标注中的 1、2、3 数字依次进行排查,先排查施压机是否有瓶颈、接着看后端依赖系统、db、网络等,最后看被压机本身,例如响应时间逐渐变慢,一般来说是外围依赖的系统出现的瓶颈导致整体响应变慢。下面针对应用系统本身做下详细的分析,针对常见问题举 1~2 个例子:

4.1 应用系统本身的瓶颈

1. 应用系统负载分析:

服务器负载瓶颈经常表现为,服务器受到的并发压力比较低的情况下,服务器的资源使用率比预期要高,甚至高很多。导致服务器处理能力严重下降,最终有可能导致服务器宕机。实际性能测试工作中,经常会用以下三类资源指标判定是否存在服务器负载瓶颈:

  • CPU 使用率

  • 内存使用率

  • Load 一般 cup 的使用率应低于 50%,如果过高有可能程序的算法耗费太多 cpu,或者某些代码块进行不合理的占用。Load 值尽量保持在 cpuS+2 或者 cpuS*2,其中 cpu 和 load 一般与并发数成正比(如下图)

  • 内存可以通过 2 种方式来查看: 1) 当 vmstat 命令输出的 si 和 so 值显示为非 0 值,则表示剩余可支配的物理内存已经严重不足,需要通过与磁盘交换内容来保持系统的稳定 ; 由于磁盘处理的速度远远小于内存,此时就会出现严重的性能下降 ;si 和 so 的值越大,表示性能瓶颈越严重。

    2) 用工具监控内存的使用情况,如果出现下图的增长趋势(used 曲线呈线性增长),有可能系统内存占满的情况:

    如果出现内存占用一直上升的趋势,有可能系统一直在创建新的线程,旧的线程没有销毁;或者应用申请了堆外内存,一直没有回收导致内存一直增长。

4.2 Jvm 瓶颈分析

4.2.1Gc 频率分析

对于 java 应用来说,过高的 GC 频率也会在很大程度上降低应用的性能。即使采用了并发收集的策略,GC 产生的停顿时间积累起来也是不可忽略的,特别是出现 cmsgc 失败,导致 fullgc 时的场景。下面举几个例子进行说明:

1. Cmsgc 频率过高,当在一段较短的时间区间内,cmsGC 值超出预料的大,那么说明该 JAVA 应用在处理对象的策略上存在着一些问题,即过多过快地创建了长寿命周期的对象,是需要改进的。或者 old 区大小分配或者回收比例设置得不合理,导致 cms 频繁触发,下面看一张 gc 监控图(蓝色线代表 cmsgc)

由图看出:cmsGC 非常频繁,后经分析是因为 jvm 参数 -XX:CMSInitiatingOccupancyFraction 设置为 15,比例太小导致 cms 比较频繁,这样可以扩大 cmsgc 占 old 区的比例,降低 cms 频率注。

调优后的图如下:

2. fullgc 频繁触发

当采用 cms 并发回收算法,当 cmsgc 回收失败时会导致 fullgc:

由上图可以看出 fullgc 的耗时非常长,在 6~7s 左右,这样会严重影响应用的响应时间。经分析是因为 cms 比例过大,回收频率较慢导致,调优方式:调小 cms 的回比例,尽早触发 cmsgc,避免触发 fullgc。调优后回收情况如下

可以看出 cmsgc 时间缩短了很多, 优化后可以大大提高。从上面 2 个例子看出 cms 比例不是绝对的,需要根据应用的具体情况来看,比如应用创建的对象存活周期长,且对象较大,可以适当提高 cms 的回收比例。

3. 疑似内存泄露,先看下图

分析:每次 cmsgc 没有回收干净,old 区呈上升趋势,疑似内存泄露

最终有可能导致 OOM,这种情况就需要 dump 内存进行分析:

  • 找到 oom 内存 dump 文件,具体的文件配置在 jvm 参数里: ```

    -XX:HeapDumpPath=/home/admin/logs
    -XX:ErrorFile=/home/admin/logs/hs_err_pid%p.log

复制代码
- 借助工具:MAT,分析内存最大的对象。具体工具的使用这里就不再介绍。
- - - - - -
感谢 [侯伯薇](http://www.infoq.com/cn/author/%E4%BE%AF%E4%BC%AF%E8%96%87) 对本文的审校。
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 [editors@cn.infoq.com](mailto:editors@cn.infoq.com)。也欢迎大家通过新浪微博([@InfoQ](http://www.weibo.com/infoqchina))或者腾讯微博([@InfoQ](http://t.qq.com/infoqchina))关注我们,并与我们的编辑和其他读者朋友交流。
2014 年 5 月 22 日 04:2423012

评论

发布
暂无评论
发现更多内容

区块链与机械时钟的演化

CECBC区块链专委会

区块链

架构师训练营第七周作业

四夕晖

第三周学习总结

tothegump

极客大学架构师训练营

架构师训练营 1 期 -- 第七周作业

曾彪彪

极客大学架构师训练营

第七周作业(作业二)

Geek_83908e

极客大学架构师训练营

第三周作业二

Jack

区块链互联互通成为焦点

CECBC区块链专委会

区块链

第七周学习性能优化1 总结

三板斧

2020.11.02-2020.11.08 学习总结

icydolphin

极客大学架构师训练营

架构师系列之4 手写单例

桃花原记

聊聊Go代码覆盖率技术与最佳实践

大卡尔

go 覆盖率

第三周作业

Griffenliu

第7周课后作业

happy

目标检测之RetinaNet

Dreamer

Week3 作业

lggl

作业

架构师训练营第 7 周作业

netspecial

极客大学架构师训练营

多个区块链细分标准发布

CECBC区块链专委会

区块链 贸易

iOS性能优化 — 四、内存泄露检测

iOSer

ios 性能优化 编程语言 ios开发 内存泄露检测

架构师训练营第 7 周学习总结

netspecial

极客大学架构师训练营

架构师训练营 week3 课后作业

花果山

极客大学架构师训练营

作业-第3周

arcyao

甲方日常 46

句子

工作 随笔杂谈 日常

极客大学架构师课程-第三周-作业

井中人

极客大学架构师训练营

架构师训练营 总结3

Arthur

极客大学架构师训练营

第三周学习总结

Griffenliu

C语言重点——指针篇(一文让你完全搞懂指针)| 从内存理解指针 | 指针完全解析

公众号@编程指北

c++ 编程 后端 指针 C语言

架构师训练营 作业3

Arthur

极客大学架构师训练营

架构师训练营 week3 学习总结

花果山

极客大学架构师训练营

架构师训练营 1 期 -- 第七周笔记

曾彪彪

极客大学架构师训练营

架构师训练营 1 期 - 第七周 - 性能优化1

三板斧

极客大学架构师训练营

Web 性能压测工具

A p7+

低代码的认知误区与落地实践

低代码的认知误区与落地实践

支付宝的性能测试-InfoQ