1.性能评估模型概述
我们的系统性能到底能不能够支撑线上真实大量的订单交易?
我想,这是我们每一个互联网交易或者负责大并发项目的同学都很关心的问题,也是性能评估模型篇需要解答的最终问题。所以我们就带着这个问题来一步步深入性能测试。本问题的难度不在于一个简单的结果,而在于答案背后的一系列性能测试的评估数据和算法,以及如何建立一个良好可持续的“性能评估模型”。
通常来讲,性能测试是指通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。
而要回答“能否支撑线上真实大量的订单交易”这样带有预测性的问题,实际上还需要用上另一种手段,即“性能预测”,而“在线性能评估模型”就是用来做性能预测的。
在预测之前,我们先来做一个数据分析,通过这个分析我们可以大概了解线上与线下的推算过程。
2013年11月11日,支付宝实现了当天交易总金额350亿元,订单总数1.8亿笔(其中手机支付占24%),活跃用户1.2亿。(来源:支付宝官方微博http://weibo.com/1627897870/AiiAjEwHO)
显然这是一个非常震惊的数字,它见证着电商的今天也预示着电商的未来。针对这个数字,下面我们就一起来剖析数字背后的性能情况。
双11当天,支付宝的订单数是1.8亿笔,意味着每小时订单数达到1.8亿 / 24 = 750万笔,也意味着每秒订单数达到750万 / 3600 = 2083笔。
首先,让我们先来看看吞吐率指标(TPS),假设支付宝有100台前置服务器,分到每台机器就是每秒处理订单2083笔/100 = 20笔。这是不是意味着只要单台服务器的性能达到20tps,我们的线上服务就足以支撑每天1.8亿的交易量呢?答案显然不是。
我们先来看看淘宝网每天交易量分布图:
可以看到,交易量并不是24小时平均分布的,从早上8点开始到晚上12点才是交易量发生的主要时间段,也就是说实际上每天只有2/3的时间(16小时)才是有效时间。我们的性能指标应该调整到20tps * 150% =30tps。
即使是16个小时中,交易量也不是平均的,在午饭和晚饭时间会出现两个波谷,晚上8点到11点之间是一天的最高峰。最高峰大约是平均值的1.2倍,如果我们不想损失掉高峰时期的交易量的话,我们的吞吐率指标需要再上调到30tps * 1.2 = 36tps。
以上只是一个普通日子的交易量分布情况,如果有某些重大活动事件,比如限时抢购、定时秒杀等活动,那么我们很可能在短时间承受几倍甚至十几倍的压力。如下图是公司某年某活动当天的交易量分布图:
总体交易量是平日的几倍到十几倍,交易量从零点开始就达到一个小高峰,凌晨2点后逐渐降到冰点,早上8点又开始了一天的持续热度,下午7点出现一个小波谷紧接着就迎来了晚上11点左右的最高峰。对于这种特别庞大的活动我们需要提前做好性能预案,以往的数据就是我们最好的参考。
通常来讲,我们对于系统的性能要求在每天高峰时期的1.5倍到4倍,如果按2倍计算,那么我们的吞吐率指标就继续上调到 36tps * 2 = 72tps。
好了,单台服务器的性能达标了72tps。但是100台服务器加起来就能承载 72tps * 100 =7200tps吗?
比较难,这依赖于我们的负载均衡算法。假设我们有一个还不错的算法,但也不能保证长时间绝对的公平,所以单台服务器还需要做好压力波动的缓冲,如果按1.5倍计算,这样我们的指标又要上调到72tps*150% = 98tps。
这里,我们已经把对单台服务器的性能指标从20tps逐渐上调到近100tps,是原来的5倍。当然这里还远没有结束。这1.8亿笔只是单一的下单操作的PV,假设用户每下单一笔,需要伴随着10次查询,3次提交,那么我们的服务器需要再评估其他或查询或提交的性能。假设这些其他附带请求的压力总和可能还得增大5倍,即达到98tps * 5 = 500tps。
还没完,这只是100台前置服务器,后面还有我们的核心业务层、消息系统、数据库系统、第三方依赖等等。它们中的任何一方都有可能成为性能瓶颈,虽然我们的分析假设了对外依赖都不是瓶颈的情况,但实际上往往就是某些不起眼的有限资源的依赖导致了整体吞吐率的下降。
这是一个水桶效应,装水量是由最小的那块板决定的。显然我们有必要对每一个子系统(公司内和公司外)分别做单独的性能测试和评估。
完了吗?可能还没有。假设我们的稳定性足够好,好到99.99%,即使这样,在面对超大量订单(1.8亿)的时候也还是意味着有1.8万个订单是失败的。
每一次失败对用户来讲都是一次糟糕的体验,可能还会因此引起一些连锁反应。所以稳定性也是系统性能的重要指标,我们做性能测试不能仅仅关注数量,还要关注质量。
对了,既然我们已经提到用户体验,那就不得不谈响应时间(RT)了,这是性能指标的又一个维度。
一般用户不会关心你有多少台服务器,也不会关心服务器能支撑多大的交易量,他们只关心你让他等了多长的时间。关于这方面的研究有不少,较新的观点可能是:
用户的耐心似乎一直在下降。不管怎么样,从性能角度上看,用户的诉求就是一句话:“不要让我等!”。为了不让用户等,我们的性能测试需要针对不同场景给出不同的考察指标,比如前端页面加载时间,后端系统响应时间,并统计出最大、最小、平均值、标准差等等。
好吧,到这里我们已经层层分析,从TPS开始到用户体验上。需要注意的是,在分析中我们使用了一些模糊的参数,比如前面说1.5倍到4倍,那到底应该是多少呢?
我想不同的业务、不同的架构、甚至不同的工程师,都有可能导致不同的结果。
而对于性能预测来讲,最重要的是建立起一个系统良好的可持续的“在线性能评估模型”,将线上和线下性能跟踪形成闭环,并不断调整动态发展,那样我们就可以适应任何的差异化,就算某一次我们评估错了,我们可以及时调整纠正,下一次我们就能更准了。
1.1 闭环流程图
一个可持续的良好模型需要测试流程上的配合,下图是一个将线下性能测试与线上性能状况相连接的闭环流程图。
与传统流程不同点在于:
l 性能测试的终点不再是发布上线,上线之后我们仍然会继续跟踪性能情况,并将结果用于下一次性能测试需求分析。
l 将线下与线上真正关联起来,并通过换算系数实现性能预测,系数可动态调整的。
l 全程性能跟踪,在生产环境中也加入性能监控,更快的解决线上性能问题。
1.2 TPS计算公式
ü 线下单机基线TPS =线上日均交易量 / 86400 / 机器数 * 160% * F
注:86400为一天的秒数。
注:假设硬件软件环境条件大致相同。
注:F为影响因子,默认为1 。
关键系数160%的由来,简单点讲就是在每天约50%的时间里完成了80%的工作,80% / 50% = 160%。
该公式还只是最简单场景的抽象,真实的情况可能会很复杂(详见前面的数据示例分析),不过作为线下基线TPS来讲具备很重要的参考意义。
线下基线TPS代表着为了达到线上的交易量,我们线下至少应该满足的性能指标。我们在做性能测试和评估的时候,基线TPS是一定要体现并首先要达到的目标。
影响因子F是一个经验值,也是需要不断调优的,线上与线下的软硬件环境不同都会导致F值的变化,甚至不同的业务线可以有不同的值。当我们的性能沙箱建立、性能闭环成型之后,会更加稳定下来。
1.3 影响因子
我们的计算公式是建立在假设硬件软件环境条件大致相同的基础上。但是在现实中,线上生产环境与线下测试环境总会难以避免的出现不一样的情况,当出现不一致的情况后我们如何来估算?这里我们很难给出准确的推算公式,但是我们列出了可能的影响因素:
影响因子 |
吞吐率(TPS) |
响应时间(RT) |
硬件环境 |
||
CPU核数越多 |
越高 |
可能越低 |
CPU频率越高 |
可能越高 |
越低 |
CPU支持64位指令 |
越高 |
可能越低 |
内存越大 |
可能越高 |
可能越低 |
磁盘空间越大 |
不明显 |
不明显 |
磁盘速率越高 |
可能越高 |
可能越低 |
网卡速率越高 |
越高 |
越低 |
服务器品牌 |
未知 |
未知 |
显卡性能越高 |
无影响 |
无影响 |
软件环境 |
||
操作系统 |
首选Linux |
首选Linux |
Linux版本越高 |
不一定(2.6以上) |
不一定(2.6以上) |
JDK版本越高 |
不明显(1.6) |
不明显(1.6) |
SWAP分区越高 |
不一定 |
不一定 |
与其他服务共用 |
具体分析 |
具体分析 |
业务特点(计算型、IO型) |
具体分析 |
具体分析 |
1.4 响应时间
ü 后端核心服务响应时间不超过100ms
ü 后端一般服务响应时间不超过300ms
ü 前端用户页面加载时间不超过3s
注:这里是指平均响应时间。但性能测试报告必须给出最大、最小、平均、方差等数值。
1.5 稳定性要求
ü 确保零崩溃, 99.9% 的稳定性。
零崩溃是指在任何非外部原因的情况下,不管运行多长时间,都不能出现程序崩溃的情况。
99.9%的稳定性,意味着每千条交易中只能容许一条出错,也意味着任何可能导致稳定性不达标的改进都需要慎重考虑。比如我们引入一种新的技术能使TPS增大50%,但是稳定性下降到97%,那么这可能也不能接受。
1.6 性能测试环境要求
为了更准确的预测性能,我们必须尽可能的保证性能测试环境的稳定。
ü 性能测试环境要求真实的物理机,一般不能是虚拟机。
ü 压力工具与被测环境不能在同一台机器部署。
ü 尽可能的利用晚上无人操作的时间来做性能测试。
测试环境准备是一个很重要又很繁琐的工作,它的效率提升依赖于我们的环境搭建平台的建设。
1.7 并发量和吞吐量(TPS)之间的关系
并发量(或叫并发用户数):是指同一时间点对业务功能同时操作的用户数。
吞吐量(TPS):一段时间内系统处理用户的请求数量。
虽然两者关系并不紧密,但是往往会有同学将它们搞混淆。其实我们可以用多线程模型来解释他们,并发量就相当于线程数,吞吐量就是所有线程处理请求数之和。
通常我们做性能测试主要考察和评估的是TPS,而并发量是一个相对较虚的概念,比如我们说一个系统支持同时1k人操作,一般不在评估的范围内。
1.8 线上性能数据采集
为了闭环需要,线上抽样一台机器,采集每天的PV数据,每隔5分钟采集一次,每天就有60/5 * 24 = 288个点。每个点需要采集Linux资源、JVM、IO以及PV数据,这些数据将成为将来性能评估的重要依据。平台化也是趋势,目前可以依赖公司的性能平台以及监控平台去观察统计数据。定期消除异常数据噪音,以月为单位可观察规律变化。
2. 性能测试需求分析
对于性能测试,一般来说工具的使用不是大的问题,问题是前期的需求分析,要不要做性能测试?性能测试的目的是什么?要做或不做性能测试的理由是什么?如何来做性能测试?这些问题的答案都是通过分析性能测试需求得到的。以下将阐述性能需求分析的一些基本方法。
2.1 业务调研
为了合理评估与制定系统的性能指标,业务调研是一个必备的过程,业务调研主要包含以下几个方面的内容:
系统信息调研
- 系统类型:系统的基本特性,如交易处理型系统、数据处理型系统等
- 架构部署:系统的整体架构、服务器部署方式
- 技术信息:系统运行平台、数据库产品、使用的中间件、协议及通讯方式等
- 业务信息:支持的业务类型、业务范围与功能、与其它系统的业务关系等
- 系统历史运行情况:目标TPS,用户数、PV等数据
- 系统数据规模:将来系统使用规模,历史系统数据规模
业务信息调研
- 基本业务功能:系统的基本业务概念以及系统的业务种类与具体功能
- 关键业务逻辑处理流程:关键业务的业务流程、交易路径、交易数据、交易流程与时序图
- 交易列表:调查业务系统全部交易清单,了解交易的组合关系、执行顺序等
- 交易量信息:在不同时间粒度下统计单个交易处理量以及总交易量信息
- 业务目标/业务拓展计划:目前的生产业务量和用户数以及系统预期业务目标和本次测试预期业务指标
文档资料调研
- 功能规格说明书
- 系统设计文档
- 生产运营统计
- 前期系统测试资料
业务调研涉及到的角色有以下几个:业务人员、开发人员、客户、产品人员、运维人员、DBA等。
通过业务调研至少可以得到以下几个方面的产出:
- 项目背景
- 系统架构说明
- 系统拓扑说明
- 测试范围说明
- 交易路径描述
- 需要测试的特性
- 不需要测试的特性
2.2 性能需求评估
在实施性能测试之前,需要对被测项目做相应的评估。主要目的是明确是否需要做性能测试和确立性能点,明确该测什么、期望值是多少。测试期望值也会根据情况评估,要求被测系统能满足将来一定时间段的压力。判断是否进行性能测试可以从以下几个方面进行思考:
a、从业务角度来分析,如果一个项目上去后使用的人数比较多,量比较大,就有做性能测试的必要,反之,如果一个项目上线后,没有几个人在用,无论系统多大,设计如何复杂,并发性的性能测试是没有必要做的,前期可以否决。
b、从系统架构角度来分析,如果一个系统采用的框架是老的系统框架,只是在此框架上增加一些应用,其实是没有必要做性能测试。如果一个系统采用的是一种新的框架,可以考虑做负载测试。
c、从实时性角度来分析,如果一个项目要求某个功能的响应时间,这个有作并发测试的可能性,在大并发量的场景下,查看这个功能的响应时间。
d、从数据库角度分析,很多情况下,性能测试是大数据量的并发访问、修改数据库,而瓶颈在于连接数据库池的数量,而非数据库本身的负载、吞吐能力。这时,可以结合DBA的建议,来决定是否来做性能测试。
如果要进行性能测试,接下来我们就需要确定相应的性能点。主要从以下 4 个维度进行确定:
- 关键业务。
首要维度,是确定被测项目是否属于关键业务,有哪些主要的业务逻辑点,特别是跟交易相关的功能点。例如快捷签约、交易等接口。如果项目(或功能点)不属于关键业务(或关键业务点),则可转入第二、三、四个维度。
2. 日请求量。
第二个维度,是界定被测项目各功能点的日请求量。如果日请求量很高,系统压力很大,而且又是关键业务,该项目需要做性能测试;而且其关键业务点,可以被确定为性能点。
3. 逻辑复杂度。
第三个维度,是判定被测项目各功能点的逻辑复杂度。如果一个主要业务的日请求量不高,但是逻辑很复杂,则也需要通过性能测试。原因是,在分布式方式的调用中,当某一个环节响应较慢,就会影响到其它环节,造成雪崩效应。
4. 运营推广计划。
第四个维度,是根据运营的推广计划来判定待测系统未来的压力。未雨绸缪、防患于未然、降低运营风险是性能测试的主要目标。被测系统的性能不仅能满足当前压力,更需要满足未来一定时间段内的压力。因此,事先了解运营推广计划,对性能点的制定有很大的作用。
例如,运营计划做活动,要求系统每天能支撑多少 PV、多少 UV,或者一个季度后,需要能支撑多大的访问量等等数据。当新项目(或功能点)属于运营重点推广计划范畴之内,则该项目(或功能点)也需要做性能测试。
以上 4 个评估维护,是相辅相成、环环相扣的,它们合成一个维度集。在实际工作中应该具体问题具体分析。例如,当一个功能点不满足以上 4 个维度,但又属于内存高消耗、CPU高消耗时,也可列入性能测试点行列。
2.3 性能测试指标
性能需求分析一个很重要的目标就是需要确定后期性能分析用的性能指标,性能指标有很多,可以根据具体项目选取和设定,而具体的指标值则需要根据业务特点和上述的一些方法进行设定。性能评估模型章节中也给了一些指标换算的基本方法。
2.3.1 性能指标分析
判断一个系统的性能通常会取决于这三个最重要的性能指标:
ü 吞吐率(TPS)
ü 响应时间(RT)
ü 系统资源利用率(Load)
通常经验告诉我们,它们三者的趋势会如下图所示:
当处于轻负载区的时候,压力有多大,吞吐率就有多大。
一旦进入重负载区,就算是再怎么努力可能也会是白费。
如果到了崩溃区,那我们的努力就开始有反效果。
同样,对于我们做性能测试来讲,我们的目的就是找出这三个区域的分界线来。
所以在设计上,我们需要不断地递增负载来观察和评估系统性能情况。
比如下表(以下数据为伪造):
TPS |
RT(AVG/MIN/MAX) |
Load(cpu idle/mem/io) |
100 |
50/15/80 |
93/8/2 |
200 |
50/18/90 |
91/8/2 |
400 |
55/18/145 |
87/9/4 |
800 |
130/25/560 |
70/10/14 |
1500 |
250/58/4488 |
48/11/75 |
可以看出,TPS低于400的时候基本属于轻负载区,400到800之间属于重负载区,高于800基本上属于崩溃区了。
2.3.2 业务性能指标
指标名 |
指标说明 |
采集方法 |
并发用户数 |
在同一时刻与服务器进行了交互的在线用户数量 |
Jmeter/loadrunner |
响应时间 |
客户发出请求到得到响应的整个过程的时间。一般他可以分为三部分:呈现时间,数据传输时间和系统处理时间 |
Jmeter/loadrunner |
吞吐量 |
一次性能测试过程中网络上传输的数据量的总和 |
Jmeter/loadrunner |
每秒处理事务数(TPS) |
每秒钟系统能够处理事务或交易的数量,它是衡量系统处理能力的重要指标。 |
Jmeter/loadrunner |
点击率 |
点击率可以看做是TPS的一种特定情况。每秒钟用户向web服务器提交的HTTP请求数。 |
Jmeter/loadrunner |
事务成功率 |
本次测试中出现成功的事务数量/事务的总数 |
Jmeter/loadrunner |
2.3.3 应用服务器及硬件性能指标
指标名 |
指标说明 |
采集方法 |
CPU占用率 |
对一个时间段内CPU使用状况的统计。 建议:<75% |
nmon/vmstat/top |
Load Average |
一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。 建议:<0.7*CPU个数*核数 |
top/uptime |
Paging rate |
内存页交换率,建议<80% |
nmon/vmstat/top |
磁盘I/O |
Iowait<30% |
nmon/iostat/sar |
SWAP |
有没有交换页面 |
nmon |
Tomcat启动的总线程数 |
关注线程数会不会无限制增长、线程数量是否足够 |
Top |
Full GC次数 |
关注Full GC次数,以及Full GC后内存占用有没有明显增长 |
Jstat/jconsole |
JVM内存使用与回收 |
|
Jstat/jconsole |
JDBC监控 |
|
Jprofiler |
Exception日志监控 |
监控压力过程中是否有异常日志产生 |
Tail&grep |
2.3.4 数据库性能指标
指标名 |
指标说明 |
采集方法 |
DB cpu占用率 |
数据库cpu利用率,建议<70% |
nmon |
DB load |
数据库服务器负载 |
Top |
DB mem |
内存使用是否平稳 |
Nmon |
DB 磁盘与I/O |
I/O是数据库性能一个非常重要的因素,建议IOwait<30% |
Nmon/iostat/sar |
数据库线程数 |
|
Top |
缓存命中率 |
点击率可以看做是TPS的一种特定情况。每秒钟用户向web服务器提交的HTTP请求数。 |
AWR |
共享池命中率 |
假如这个值低于95%就要考虑调整应用(改写多为变量绑定)或者增加内存 |
AWR |
Top 耗时 sql |
找出性能较差的sql,进行优化 |
AWR |
2.3.5 性能指标参考
在确定性能指标的时候,可以参考一下表中对应的数值。
指标项 |
优秀 |
中等 |
差 |
TPS |
TPS >=100 |
50<TPS <100 |
TPS<=50 |
响应时间 |
RT<=200ms |
200ms<RT<500ms |
RT>=500ms |
响应长度 |
ResponseSize<=100KB |
100KB<ResponseSize<500KB |
ResponseSize>=500KB |
CPU |
CPU<=75% |
75%<CPU<80% |
CPU>=80% |
Load |
Load<=2 |
2<Load<5 |
Load>=5 |
FullGC |
FullGC<=1 |
1<FullGC<10 |
FullGC>=10 |
DBQPS |
DBQPS<5*TPS |
5*TPS<DBQPS<10*TPS |
DBQPS>=10*TPS |
慢SQL数量 |
慢SQL=0 |
慢SQL=1 |
慢SQL>=2 |
2.3.6 压力与容量预估
首先,由产品同学给出线上交易量预估,并根据TPS线上线下换算公式,得出线下TPS基线。
ü 达标目标:TPS基线必须在轻负载区区域内。
面对数据库或第三方依赖,需要评估可能的瓶颈,数据库最好使用真实的并容量与线上最大值保持一致,因为数据库成为瓶颈的可能性比较大。
假如我们有一个数据库线上有数据100G,分了4个库,每个库128张表,平均每张表有195M数据,约15w条数据。性能上我们可以只构造一个库的情况,约25G的数据。我们在做性能测试之前必须提早做好这25G的数据。
其他第三方依赖如果已经做过良好的性能评估,比如内部消息系统服务,那么我们可以适当采用性能桩的方式来替代真实后端。
注:不管是压力还是容量,都离不开具体的业务分析,只能这样才能把性能测试做到最完美。