高并发应用中客户端等待、响应时间的推算,及RT/QPS概念辨析
对于一个网站,已知服务端的服务线程数和处理单个请求所需的时间时,该如何算出高并发时用户从点击链接到收到响应的时间?注意这个时间并不等于服务端处理单个请求的时间,因为高并发时,很多用户请求需要排队等待,你要把这个额外的等待时间算进去。
这个问题很重要,因为它的结果直接影响你的网站的用户体验。这篇文章就是来帮你算这个时间的。你可以使用本文附带的程序来算,也可以通过本文提炼出的公式来算。
另外还有一个问题:所谓RT(响应时间)和QPS,究竟要不要考虑用户请求的排队等待时间? 本文认为,对于RT我们应该区分出“服务器眼中的RT”和“客户端眼中的RT”,但对于QPS却不必区分。
后文会辨析这些概念,同时还会给出不同场景下,RT和QPS随着并发数变化而变化的曲线图。你可以通过比较不同的曲线,获得一些收获。
下面先推演一个最简单的场景,通过这个场景,你可以了解到本文在计算时使用的基本思路。
最简单的场景:服务端线程数=1,客户端并发=2
如果服务端只有1个服务线程,每处理1个请求需要1个ms; 当客户端在同一瞬间提交两个请求时,各项性能指标是怎样的?
为了解这个题,可以想象一下每个请求被处理的过程:
请求1被立即处理;由于服务线程只有一个,请求2需要等待请求1完结后才能被处理。
据此算出各项性能指标:
|
性能指标 |
指标值 |
说明 |
|
服务端响应所有请求的时间 |
1ms + 1ms = 2ms |
上图中紫色时间之和 |
|
服务端响应每个请求的平均时间 |
服务端处理所有请求的时间/2 = 1ms |
|
|
客户端所有请求的等待、响应时间 |
1ms + (1ms + 1ms) = 3ms |
第1个请求直接处理 = 1ms 第2个请求先等待后处理 = 1ms + 1ms |
|
客户端每个请求的平均等待、响应时间 |
客户端所有请求的等待、响应时间/2 = 1.5 ms |
看上面高亮的这些字,你应该已经了解了时间推算的基本思路了;后文其他场景中会使用相同的模式来推算。
再来观察一下客户端每个请求的平均等待、响应时间。它的值是1.5ms,大于服务端响应每个请求的平均时间1ms.
不同角度有不同的看法,
- 服务端站在自己的角度来看:并发为2时,处理每个请求消耗了自己1ms, RT = 1ms
- 客户端站在自己的角度来看:并发为2时,每个请求平均需要花1.5ms才能被完结,服务器的RT应用1.5ms ,比服务端宣称的1ms要高多了。
这两种说法都有道理。就像银行柜员一直在忙,没有偷懒,问心无愧;而排队的客户苦苦等待,牢骚漫天,其实也很无辜。
因此本文认为,RT应分为两种:
|
性能指标 |
指标值 |
说明 |
|
服务端眼中的RT |
1ms |
不计入客户端的等待时间 |
|
客户端眼中的RT |
1.5ms |
计入客户端的等待时间 |
顺便再算一下此时的QPS. 事实上无论在服务端眼里还是客户端眼里,QPS都是:
成功处理的请求数/(最后一个请求结束时间 – 第一个请求开始时间)= 2 / (2 – 0)ms = 1000
接下来再看看其它场景。
场景2:服务端线程数 > 1
上文说了服务端线程数=1的情况,如果服务端线程数超过1会怎么样? 比如,服务端线程数 = 3, 客户端并发 = 10:
|
性能指标 |
指标值 |
|
服务端响应所有请求的时间 |
1ms * 3 + 1ms * 3 + 1ms * 3 + 1ms = 10ms |
|
服务端响应每个请求的平均时间 |
服务端处理所有请求的时间/10 = 1ms |
|
客户端所有请求的等待、响应时间 |
1ms * 3 + 2ms * 3 + 3ms * 3 + 4ms = 22ms |
|
客户端每个请求的平均等待、响应时间 |
客户端所有请求的等待、响应时间/10 = 2.2 ms |
这个推算并不难,但如果总是需要这样手工推算就很烦了。因此,本文提供了一个程序来将推算步骤自动化。不过,在体验这个程序之前,我们先推演一下其他的场景。
场景3:无过载保护,服务器响应能力受并发数影响
以上的场景都假设系统有严格的“过载保护”:只提供有限的服务线程数,由于系统压力不会过载,所以每个线程都总是能以最高的速度来处理请求。
现实中,很多系统并没有这种做,相反:
- 没有过载保护,来一个请求启一个线程,直到系统崩溃
- 当客户端并发数超过一定阈值后,服务端处理单个请求的时间开始上升(原因很多,比如CPU、内存资源消耗过大,线程上下文切换过多等)
举个例子,一个应用在并发<=3时,处理单个请求只需1ms;当并发超过3时,处理单个请求的能力开始恶化,
3个并发 => 处理单个请求需1ms
4个并发 => 处理单个请求需要4ms
5个并发 => 处理单个请求需要5ms
…
10个并发 => 处理单个请求需要10ms
如果客户端并发=10,性能会是什么状况?
|
性能指标 |
指标值 |
|
服务端响应所有请求的时间 |
10 * 10ms = 100ms |
|
服务端响应每个请求的平均时间 |
服务端处理所有请求的时间/10 = 10ms |
|
客户端所有请求的等待、响应时间 |
10 * 10ms = 100ms |
|
客户端每个请求的平均等待、响应时间 |
客户端所有请求的等待、响应时间/10 = 10 ms |
没有过载保护时,所有请求都不用排队;这时推算性能的算法会比较简单。接下来再看最后一种场景。
场景4:弱过载保护
有很多应用,在过载保护方面是上面两种机制的折衷:
- 在客户端并发数低于某阈值时,单个请求的处理速度可以保持全速
- 当客户端并发数高于上述阈值但还不太高时,单个请求的处理速度有所下降,但仍可以接受,系统这时愿意容忍这种程度的并发,以换取更高的吞吐量(QPS)
- 当客户端并发数过大、高于另一个阈值时,单个请求的处理速度会迅速恶化,应该在这个点进行过载保护
本文把这种策略称作“弱过载保护”,场景2称作“强过载保护”,场景3则是“无过载保护”。
弱过载保护系统的性能该如何推算?
- 并发数低于第一个阈值时,所有请求不必等待。此时的计算方法跟“无过载保护”基本相同,只不过这时单个请求的处理时间是个常量。
- 并发数高于第一个阈值但低于第二个阈值时,所有请求仍不必等待,此时的计算方法跟“无过载保护”完全一致。
- 并发数高于第二个阈值时,有些请求开始等待,此时的计算方法跟“强过载保护”场景下的模型基本一致,只不过这时单个请求的处理时间 = 最高并发时的单个请求的处理时间。
另外,“强过载保护”和“无过载保护”可以视为“弱过载保护”的特殊情况。
- “强过载保护”也是一种“弱过载保护”,它的第二个阈值 = 第一个阈值
- “无过载保护”也是一种“弱过载保护”,它的二级阈值 = ∞
既然所有的场景都可以统一为同一种机制,我们可以搞出一个“统一的性能 - 并发数计算模型”。
统一的性能 - 并发数计算模型
输入:
|
符号 |
公式中的符号 |
||
|
服务器端处理能力 |
第1个线程数阈值 |
serverThreshold1 |
|
|
第1个线程数阈值前的单个请求处理时间 |
serverResponse1 |
||
|
第2个线程数阈值 |
serverThreshold2 |
||
|
两个阈值之间的单个请求处理时间函数 |
serverResponse2Func (clientConcurrency) |
s |
|
|
客户端压力 |
客户端并发数 |
clientConcurrency |
|
输出:
|
符号 |
公式中的符号 |
备注 |
||
|
服务器眼中的性能 |
服务器响应所有请求的时间 |
serverResponseSum |
||
|
服务器响应每个请求的平均时间 |
serverResponseAverage |
serverResponseSum/clientConsurrency |
||
|
客户端眼中的性能 |
客户端所有请求的等待、响应时间 |
clientWaitResponseSum |
||
|
客户端每个请求的平均等待、响应时间 |
clientWaitResponseAverage |
clientWaitResponseSum/clientConsurrency |
||
算法:
参照下图,推算出每个请求的处理时间和响应时间,然后分别求和、求平均.
通过程序自动化计算
按照上图的模式来手工推演性能会很烦的。本文提供了一个开源程序,以将推算过程自动化。
如果急于看效果,可以
- 下载http://how-long-to-wait.googlecode.com/files/how-long-to-wait-1.0.0-SNAPSHOT-jar-with-dependencies.jar
- 执行 java -jar how-long-to-wait-1.0.0-SNAPSHOT-jar-with-dependencies.jar 这个DEMO算出了serverThreshold =3, 并发=10的各项性能指标
想自定义参数,则可以:
- 下载http://how-long-to-wait.googlecode.com/files/how-long-to-wait-1.0.0-SNAPSHOT-project.zip
- 解压,作为Maven工程放到你的IDE里
- 模仿org.googlecode.hltwsample.single.ShowCase写你自己的代码
- 执行程序,并查看控制台输出
这个程序还会记录每个请求被执行的起止时间,你可以利用它来验算
…
默认情况下执行时间会被直接打印到控制台,但你也可以扩展实现自己的记录展现工具。具体方法是,
- 实现SingleAppSimulateEventListener接口
- 再把它注入到singleAppVisitSimulator.setEventListener()
通过公式计算
你也可以直接通过公式来计算性能。
服务端眼中的RT:
客户端眼中的RT:
若 ,
若 ,
则令, (整除), 且(取模)
得
性能-并发数曲线图
前面一直在做定量分析,现在可以搞一下定性分析了:从数据中找到可以辅助决策的结论。
我们可以让并发数持续升高,同时观察服务器/客户端眼中性能的差异,以及同一性能指标在不同过载保护机制下的差异。
服务端处理能力:
|
第1个线程数阈值 |
10 |
|
第1个线程数阈值前的单个请求处理时间 |
10ms |
|
第2个线程数阈值 |
20 |
|
单个请求处理时间函数 |
无过载保护时的性能趋势图
- 并发数超过一个极限之前,RT基本不变,但QPS会持续上升,表明系统的并发服务能力被利用得越来越充分
- 无过载保护时,当并发数超过一个极限后,系统性能会急剧下降
- 无过载保护时,所有请求会被服务端立即处理,没有等待时间,因此客户端和服务器的RT曲线完全吻合。
强过载保护时的性能趋势图
- 强过载保护时,服务器跟中的永远是条水平线,因为服务器一直处于最佳状态
- 强过载保护时,客户端眼中的系统性能在并发数经过一个阈值后逐渐恶化,实际上这只是排队时间在增多而已。
- 强过载保护时,QPS的变化比较平稳,因为服务器一直处于健康状态
弱过载保护时的性能趋势图
- 弱过载保护时,RT会先后经历两次较为平缓的性能下降。第一次是由于服务器本身性能下降,第二次则是因为客户端的排队时间增多。
- 弱过载保护时,QPS的变化仍算比较平稳
不同过载保护机制下的性能比较
放大下面两条曲线:
在服务器眼里,保护越强,则性能越好
放大下面两条曲线:
- 在客户端眼里,有过载保护比没有好
- 在上图中,弱过载保护时的性能比强过载保护时的RT要平一些,但这是因为本图里的函数本身比较平坦,使得系统能够在较高并发时仍以较好的速度处理请求,而且总体性能更好。 如果函数很陡的话,情况就会是另外一种样子了。所以,强过载保护好还是弱过载保护好,要具体案例具体分析。
- 无过载保护时,QPS超过一个极限后降到极低的水平
- 上图中,弱过载保护的QPS比强过载保护时要好一些,但这也跟函数本身的平坦度有关。
结语
本文给出的程序和公式可以帮助你在已知服务端性能的条件下,计算出客户端的平均等待、相应时间。
本文区别了服务器眼中的RT和客户端眼中的RT,并且通过曲线图介绍了不同过载保护机制下性能如何随并发数变化而变化。
不过,本文的推算剧本中,客户端只会发一次请求:若并发为10,则一次性提交10个请求。而现实中的客户端应该会持续不断的提交请求,这时候它们的平均等待、响应时间又是多少呢? 这个问题要结合客户端本身发送请求的速率来计算,我们以后再深入地看看。
高并发应用中客户端等待、响应时间的推算,及RT/QPS概念辨析的更多相关文章
- 如何在高并发分布式系统中生成全局唯一Id
月整理出来,有兴趣的园友可以关注下我的博客. 分享原由,最近公司用到,并且在找最合适的方案,希望大家多参与讨论和提出新方案.我和我的小伙伴们也讨论了这个主题,我受益匪浅啊…… 博文示例: 1. ...
- 如何在高并发分布式系统中生成全局唯一Id(转)
http://www.cnblogs.com/heyuquan/p/global-guid-identity-maxId.html 又一个多月没冒泡了,其实最近学了些东西,但是没有安排时间整理成博文, ...
- (转)如何在高并发分布式系统中生成全局唯一Id
又一个多月没冒泡了,其实最近学了些东西,但是没有安排时间整理成博文,后续再奉上.最近还写了一个发邮件的组件以及性能测试请看 <NET开发邮件发送功能的全面教程(含邮件组件源码)> ,还弄了 ...
- 高并发分布式系统中生成全局唯一(订单号)Id js返回上一页并刷新、返回上一页、自动刷新页面 父页面操作嵌套iframe子页面的HTML标签元素 .net判断System.Data.DataRow中是否包含某列 .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数
高并发分布式系统中生成全局唯一(订单号)Id 1.GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(D ...
- ql Server 高频,高并发访问中的键查找死锁解析
死锁对于DBA或是数据库开发人员而言并不陌生,它的引发多种多样,一般而言,数据库应用的开发者在设计时都会有一定的考量进而尽量避免死锁的产生.但有时因为一些特殊应用场景如高频查询,高并发查询下由于数据库 ...
- Sql Server 高频,高并发访问中的键查找死锁解析
死锁对于DBA或是数据库开发人员而言并不陌生,它的引发多种多样,一般而言,数据库应用的开发者在设计时都会有一定的考量进而尽量避免死锁的产生.但有时因为一些特殊应用场景如高频查询,高并发查询下由于数据库 ...
- 高并发分布式系统中生成全局唯一Id汇总
数据在分片时,典型的是分库分表,就有一个全局ID生成的问题.单纯的生成全局ID并不是什么难题,但是生成的ID通常要满足分片的一些要求: 1 不能有单点故障. 2 以时间为序,或者ID里包含时间 ...
- 高并发分布式系统中生成全局唯一(订单号)Id
1.GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与GUID组合 ...
- Java框架 高并发系列 1第1天:必须知道的几个概念
https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933019&idx=1&sn=3455877c451de9 ...
随机推荐
- git 项目初始化
1.在git服务器界面右上角“+” .create new project ,写上项目名字生成一个新的组 2.如果机器第一次与git 建立连接,需要让机器生成一个id_rsa和id_rsa.pub ...
- http://blog.csdn.net/pi9nc/article/details/23169357
http://blog.csdn.net/pi9nc/article/details/23169357
- http://blog.csdn.net/yangyuhan156/article/details/48899439
http://blog.csdn.net/yangyuhan156/article/details/48899439
- Advanced REST client的使用说明
1. 为什么要使用REST Client 在实际企业开发过程中经常会有这样的需求: 1.我当前开发的这个系统是需要调用其他系统的接口,也就是我们需要频繁的测试接口,尝试不同的入参参数去查看返回结果, ...
- Linux就这个范儿 第14章 身在江湖
Linux就这个范儿 第14章 身在江湖 “有人的地方就有江湖”,如今的计算机世界就像一个“江湖”.且不说冠希哥有多么无奈,把微博当QQ的局长有多么失败,就说如此平凡的你我什么时候就成了任人摆布的羔羊 ...
- ava获得当前文件路径
第一种: File f = new File(this.getClass().getResource("/").getPath()); System.out.println(f); ...
- 安装nodejs+ionic+cordova环境心得
1.安装node-v0.10.38-x64.msi版本(从nodejs中下载最稳定版本,最后安装ionic安不上,然后又安装node-v0.10.38-x64.msi,再安装ionicok了.不知道是 ...
- Demo4 Slides.js的使用
Slides.js挺好用的啊,把示例中的Demo调试通了.首先把css.img.js文件夹下的内容全部拷贝到Vs网站项目下的Scripts文件夹下. 代码主要修改了一些图片路径和网址链接. <! ...
- cocos2dx 3.x(多个按钮button执行同一事件的区分)
// // ATTGamePoker.hpp // MalaGame // // Created by work on 2016/10/18. // // #ifndef ATTGamePoker_h ...
- Android的LinearLayout中的权重android:layout_weight
当前EditText和Button部件只是适应了他们各自内容的大小,如下图所示: 这样设置对按钮来说很合适,但是对于文本框来说就不太好了,因为用户可能输入更长的文本内容.因此如果能够占满整个屏幕宽度会 ...