系统的性能指标
(一)性能指标有哪些
1、响应时间(Response time)
响应时间就是用户感受软件系统为其服务所耗费的时间,对于网站系统来说,响应时间就是从点击了一个页面计时开始,到这个页面完全在浏览器里展现计时结束的这一段时间间隔,看起来很简单,但其实在这段响应时间内,软件系统在幕后经过了一系列的处理工作,贯穿了整个系统节点。根据“管辖区域”不同,响应时间可以细分为:
- 服务器端响应时间,这个时间指的是服务器完成交易请求执行的时间,不包括客户端到服务器端的反应(请求和耗费在网络上的通信时间),这个服务器端响应时间可以度量服务器的处理能力。
- 网络响应时间,这是网络硬件传输交易请求和交易结果所耗费的时间。
- 客户端响应时间,这是客户端在构建请求和展现交易结果时所耗费的时间,对于普通的瘦客户端 Web 应用来说,这个时间很短,通常可以忽略不计;但是对于胖客户端 Web 应用来说,比如 Java applet、AJAX,由于客户端内嵌了大量的逻辑处理,耗费的时间有可能很长,从而成为系统的瓶颈,这是要注意的一个地方。
那么客户感受的响应时间其实是等于 客户端响应时间
+ 服务器端响应时间
+ 网络响应时间
。细分的目的是为了方便定位性能瓶颈出现在哪个节点上。
2、吞吐量(Throughput)
吞吐量是我们常见的一个软件性能指标,对于软件系统来说,“吞”进去的是请求,“吐”出来的是结果,而吞吐量反映的就是软件系统的“饭量”,也就是系统的处理能力,具体说来,就是指软件系统在每单位时间内能处理多少个事务/请求/单位数据等。但它的定义比较灵活,在不同的场景下有不同的诠释,比如数据库的吞吐量指的是单位时间内,不同 SQL 语句的执行数量;而网络的吞吐量指的是单位时间内在网络上传输的数据流量。吞吐量的大小由负载(如用户的数量)或行为方式来决定。举个例子,下载文件比浏览网页需要更高的网络吞吐量。
#资源使用率(Resource utilization)
常见的资源有:CPU占用率、内存使用率、磁盘I/O、网络I/O。
3、点击数(Hits per second)
点击数是衡量 Web Server 处理能力的一个很有用的指标。需要明确的是:点击数不是我们通常理解的用户鼠标点击次数,而是按照客户端向 Web Server 发起了多少次 http 请求计算的,一次鼠标可能触发多个 http 请求,这需要结合具体的 Web 系统实现来计算。
4、并发用户数(Concurrent users)
并发用户数用来度量服务器并发容量和同步协调能力。在客户端指一批用户同时执行一个操作。并发数反映了软件系统的并发处理能力,和吞吐量不同的是,它大多是占用套接字、句柄等操作系统资源。
另外,度量软件系统的性能指标还有系统恢复时间等,其实凡是用户有关资源和时间的要求都可以被视作性能指标,都可以作为软件系统的度量,而性能测试就是为了验证这些性能指标是否被满足。
(二)如何发现性能瓶颈
在找性能瓶颈之前,我们要先对系统性能有一个概念
如何在不购买新硬件的条件下完成更多的工作?何时才真正需要添加硬件(更多的内存,更快的磁盘、 CPU以及网络接口)?有时只需消除一些简单的瓶颈即可解决许多性能问题——但是要实现它,你必须充分了解自己的计算机和网络,从而找到真正的瓶颈所在。
说得直白一点,系统性能就是在尽可能减少投资的情况下,解决下面两个事:
- Throughput:吞吐量。也就是每秒钟可以处理的请求数,任务数。
- Response time:响应时间。也就是系统在处理一个请求或一个任务时的响应时间。
我们要做优化,就是为了让吞吐量更大,让响应时间更短,在二者之间达到平衡,满足我们的业务要求。
所以,我们要发现性能瓶颈,其实就是找到影响吞吐量和响应时间的地方。
1、使用压力测试工具发现性能瓶颈
网上的压力测试工具有很多,这里举几个实际工作中常用的
Java Melody
能够在 QA 和实际运行生产环境监测 Java 或 Java EE 应用程序服务器。并以图表的形式显示:Java 内存和 Java CPU 使用情况,用户 Session 数量,JDBC 连接数,和 http 请求、sql 请求、jsp 页面与业务接口方法(EJB3、Spring、Guice)的执行数量,平均执行时间,错误百分比等。图表可以按天,周,月,年或自定义时间段查看。
2、Apache JMeter
Apache JMeter 是一个专门为运行和服务器装载测试而设计的、100% 的纯 Java 桌面运行程序。原先它是为 Web/HTTP 测试而设计的,但是它已经扩展以支持各种各样的测试模块。它和用于 HTTP 和 SQL 数据库(使用 JDBC)的模块一起运送。它可以用来测试静止资料库或者活动资料库中的服务器的运行情况,可以用来模拟对服务器或者网络系统加以重负荷以测试它的抵抗力,或者用来分析不同负荷类型下的所有运行情况。它也提供了一个可替换的界面用来定制数据显示,测试同步及测试的创建和执行。
3、Load Runner
LoadRunner,是一种预测系统行为和性能的负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner 能够对整个企业架构进行测试。企业使用 LoadRunner 能最大限度地缩短测试时间,优化性能和加速应用系统的发布周期。 LoadRunner 可适用于各种体系架构的自动负载测试,能预测系统行为并评估系统性能。
发现瓶颈,怎么办?
先去操作系统,操作系统的报告。看看操作系统的 CPU 利用率
,看看 内存使用率
,看看 操作系统的 IO
,还有 网络的 IO
,网络链接数
,等等。通过了解操作系统的性能,我们才知道性能的问题,比如:带宽不够,内存不够,TCP 缓冲区不够,等等,很多时候,不需要调整程序的,只需要调整一下硬件或操作系统的配置就可以了。说这些是为了提醒你,不要急着去修改你的代码。
如果到了非要动代码的地步,瓶颈这东西也可以根据 2:8 原则来说,20% 的代码耗了你 80% 的性能,找到那 20% 的代码,你就可以优化那 80% 的性能。所以,紧紧锁定那不到 20% 的代码。
(三)性能调优的常见手段
常见的互联网架构中,一般都能看到 Spring + MyBatis + MySQL + Redis搭配的身影。一般来说,应用内部的接口都是直接调用的,所谓的面向接口编程,应用间的调用直接调或者通过类似 Dubbo 之类的服务框架来执行,数据格式往往采用 JSON,即统一也方便各数据间做转换和取值,缓存一般使用 Redis 或 Memcached,存储一些对象或 JSON 格式的字符串。对外提供的接口,一般都需要进行压力测试,以便估算其性能,并为后续的调优提供指导方向,以下接口便是在压测过程中出现的各种“奇怪现象”,所谓奇怪,指的是从表象上看与我们正常的逻辑思路不符,但其本质还是我们对压力下程序的表现出来的特征不熟悉,用惯用的知识结构试图去解释,这根本是行不通的。下文是我在一次全面压测过程后对数据进行的分析汇总,其中的现象是很多压测常见的,里面的分析过程及改进措施我认为有很大的参考意义。具体内容如下:(部分接口为了安全我省略了其名称,但不影响我们的分析,另外形如 1N3T
之类的表示的是 1 台 Nginx,3 台 Tomcat,具体的 TPS 数值只是为了说明优化前后的比照,没有实际意义)
1、名词解释
TPS
每秒钟处理完的事务次数,一般 TPS 是对整个系统来讲的。一个应用系统 1s 能完成多少事务处理,一个事务在分布式处理中,可能会对应多个请求,对于衡量单个接口服务的处理能力,用 QPS 比较多。
QPS
每秒钟处理完请求的次数;注意这里是处理完。具体是指发出请求到服务器处理完成功返回结果。可以理解在 Server 中有个 Counter,每处理一个请求加 1,1 秒后 Counter = QPS。
RT
响应时间,处理一次请求所需要的平均处理时间
并发量
系统能同时处理的请求数
2、真实调优案例
a、接口:获取列表
压测现象:单台 TPS 700 多,应用 CPU 高负载
问题分析
旧框架,平均响应时间长,应用 CPU 高,程序内部有大量的 BEAN 到 MAP 到 JSON 之间的转换,修改数据库连接数后,TPS 没有提升。
改进措施
重构系统,用 MyBatis 替代之前的 DAO 操作,减少 BEAN - MAP - JSON 之间的内部数据转换,减少程序内部的无用操作。
改进效果
TPS 改进后能到 3000 左右,有较大提升,但压测时应用 CPU 几乎跑满,还有改善空间。
压测现象:数据库资源利用率高
问题分析
单台应用,数据库资源 CPU 都能到 50%,10 台 TOMCAT 在 1万 并发下数据库 CPU 跑满,LOAD 值 700 多,但 DB 的 QPS 也不过 11554,并不算多,因此怀疑是 SQL 执行耗费了 CPU,可能是某条 SQL 没有按索引查找或者索引失效。
改进措施
查看 SQL 文件发现如下 sql:select count(1) from orders where order_status_id !=40
,将其改为 select order_id from orders
然后通过程序把 order_status_id != 40
的过滤掉。通过 list.size() 来获取。order_status_id 即使加了索引,由于是 !=
比较,所以不会去按索引查找,导致 CPU 高
改进效果
相同环境下(1台 Nginx,10 台 Tomcat,1000 并发),TPS 由 3000 变成 3727,略有增长,但是 DB 的 CPU 明显下降,变为 30%,效果明显
压测现象:1N15T,TPS 4552;10N15T,TPS 9608
问题分析
后端都是 15 台 Tomcat,前端 1 台 Nginx 时 TPS 为 4552,通过 LVS 挂 10 台 Nginx 时为 9608,增长不明显,其 Nginx 和 Tomcat 都压力不大,集群结果不合理,怀疑是 Nginx 转发配置的问题;
改进措施
未进一步改进:可能是需要调整 Nginx 的参数,之前发现过 Nginx 不同的配置对后端集群环境的 TPS 影响很大
改进效果
无
b、接口:信息查询
压测现象:单台 TPS 2000 多,应用 CPU 高,DB 的 QPS 15000 左右
问题分析
旧框架,程序内部有很多 Bean - Map - Json 相互的转换
改进措施
删除冗余代码、更换连接池包,使用 MyBatis
改进效果
TPS 由 2000 多增长为 8000 多,DB 的 QPS 为 9000 左右,优化后压测应用的 CPU 占用高,几乎跑满。
压测现象:数据库无压力,应用增加多台后 TPS 不变
问题分析
1N1T 和 1N10T 的 TPS 一样,都为 5000,增大并发时错误数增多,应用 CPU 耗费 70%,DB 无压力,Nginx 单台通过 ss –s
发现端口占满,即 Nginx 到 Tomcat 之间转发的连接端口 time-wait
状态 6 万多。Nginx 存在瓶颈。
改进措施
调优 Nginx 参数,将短连接改为长连接
改进效果
1N3T 的 TPS 能到 17376,Tomat 的 CPU 压力 84%,DB 的 QPS 18000,CPU 69%,应用的资源基本使用到量。
c、接口:获取详情
压测现象:单台应用 TPS 2600,10 台 Tomcat 才 3700
问题分析
增加应用服务器,TPS 增长不明显,且 Nginx、Tomcat、DB 的负载都不高,说明服务器本身不是瓶颈,考虑是不是网络的问题,通过监控网卡包流量发现网络数据跑满,因为此接口会有大量数据的输出,因此瓶颈在网络上。另外,测试过程中发现 Redis 有报错,Redis 服务器是虚机,可能服务能力有限。
改进措施
开启 Tomcat 的 gzip 压缩。
改进效果
同等并发下(1 台 Nginx,10 台 Tomcat,1000 并发),TPS 由 3727 增长到 10022,增长了近 3 倍,效果显著。
压测现象:1N10T 集群下 Nginx 参数调优对 TPS 提升效果明显
问题分析
经过 Tomcat 的启用 gzip 后,1N10T 下 TPS 为 10022,需进一步提升。
改进措施
优化 Nginx:
- Nginx 日志关闭
- Nginx 进程数量 worker,由
24
改为16
- nginx keepalive 数量由
256
改为2048
改进效果
TPS 由 10022 提升为 13270。
压测现象:1N5T 和 1N10T 的 TPS 相差不大
问题分析
1N10T 的 TPS 为 1万3千多,1N5T 的 TPS 为 1万2千多,相差不大,应用的 Tomcat 资源利用没满,CPU 为 65%,DB 的 QPS 已经到 2万多了,单台服务器 DB 基本上到量了,因此再增加应用也没效果,只会导致响应的时间变长。
改进措施
单台 DB 已经无法改进了,要不提升服务器硬件,要不读写分离。
改进效果
无
d、接口:促销
压测现象:通过 Redis 存取数据,TPS 才 1000 多,CPU 有压力
问题分析
此接口通过 Redis 取数据,TPS 不高才 1000 多,但 CPU 占用了 80%,说明程序内部有大量序列化反序列化的操作,可能是 JSON 序列化的问题。
改进措施
将 net.sf.json
改成 alibaba
的 fastjson
改进效果
同等并发条件下 TPS 由 1000 多提升为 5000 多,提高了近5倍。
压测现象:参数多时 TPS 下降明显
问题分析
此接口根据参数从 Redis 中获取数据,每个参数与 Redis 交互一次,当一组参数时 TPS 5133,五组参数时 TPS 1169,多次交互影响了处理性能。
改进措施
将从 Redis 获取数据的 get 改为 mget,减少交互次数。
改进效果
五组参数时 1N3T 压测 TPS 9707,据此估算即使是单台 Tomcat,TPS 也能有三四千,性能比单次 get 的调用方式提升了 3,4 倍。
压测现象:1N3T TPS 1万多,在增大 Tomcat 可能 TPS 增长不会明显
问题分析
此处说的是可能,因为 Nginx 服务器的 CPU 虽然不高,但 QPS 已经 8000 多,此时应该是 Nginx 的服务器网络流量成为了瓶颈。(只是猜测)
改进措施
可以增加多台 Nginx 负载,前端加 LVS
e、接口:追踪接口
压测现象:1N10T 的 TPS 低于 1N3T 的 TPS
问题分析
1N3T 在 2000 并发下 TPS 为 9849,此时 DB 的 QPS 为 90000,CPU 80%,将 Tomcat 增到 10 台,5000 并发下,TPS 为 7813,DB 的 QPS 为 19000,CPU 75%,load 1,说明压力增大情况下 DB 的压力反而下来了,注意到 Nginx 服务器的网卡流量达到 885M,说明是压力过大情况下,网络满了,发生丢包,导致 DB 端压力反而下来了。
改进措施
注意压测情况下部分接口由于数据量传输较大,会出现网络瓶颈。
f、接口:回填接口
压测现象:TPS 不到 500,DB 的 QPS 3500
问题分析
虽然缺少应用的 CPU 及 DB 的 CPU 利用率数据,较低的 TPS 应该是应用的瓶颈,且需要关注是不是 DB 在处理查询的时候缓慢。
改进措施
- 连接池由
DBCP
改为HIKAR
- 减少了日志打印输出
- SQL 优化,将部分条件过滤改为在 Java 代码中执行
改进效果
TPS 由不到 500 增长为 1300 多
g、接口:券查询
压测现象:集群结果与单台应用结果相比不合理
问题分析
查看是否存在瓶颈资源,可以看到 5 台 Tomcat 集群下,TPS 为 9952,但 DB 的 QPS 为 5-6 万,CPU 利用率为 37%,说明对数据库进行了大量的主键或索引查询,一般单台 DB 的 QPS 也就 4万左右,再增加应用的集群数量,对 TPS 也不会有太大影响。
改进措施
可以考虑分库
h、接口:推荐
压测现象:Nginx 长短连接差异
问题分析
18 台 Nginx,2 Tomcat 时 TPS 8100,此时应用服务器的端口数满,一般来说,Nginx 短连接在高并发下容易导致端口占满的问题。
改进措施
将 Nginx 改为长连接
改进效果
TPS 增长为 10733,TPS 稳定,起伏减少,但是 CPU 耗尽。说明 CPU 打满了,此时如果还要优化就的进行代码调优了。
i、接口:查询
压测现象:18N20T 的 TPS 才 6842
问题分析
18 台 Nginx,20 台 Tomcat,TPS 才 6842,此时应用 CPU 利用率 85%,说明 CPU 存在瓶颈,但检查此接口并未做大计算量的工作,有可能是日志的级别问题,CPU 在频繁的打日志。
改进措施
将日志级别由 DEBUG 级改为 INFO 级
改进效果
同等环境 TPS 由 6842 增长为 23592
转自:有梦想的咸鱼