压⼒测试分析
1.从压⼒说起
压⼒测试的理解,xxx的性能10w/s,对你有意义么?
没有那家卖⽠的会说⾃⼰家的不甜,同样,没有哪个开源项⽬愿意告诉你在对它条件最苛刻的时候压⼒情况是多少,⼀般官⽹号称给你看的性能指标都是在最理想环境下的,毫⽆参考意义。
举个栗⼦,官⽹压测的例⼦,256字节的读速度11w/s,写速度8.1w/s,都知道优点是多变的,string、List、hash、set、sortset,实际⼯作稍微复杂的环境往往都是各种结构混合使⽤,字符串长度各异,你需要的是真正在你的⼯作环境下,即:你混合使⽤的数据结构下,你的访问压⼒下,你的字符串长度下redis的x响应性能。这个值往往跟官⽅公布的差异很⼤。我的经验,我们是视频⾏业,相对字符串长度较长,在压缩序列化之后,主要使⽤String和List,性能在访问client=200-400左右,qps相应能到5w,超过这个client值,qps下降⽽且服务器负载上扬,容易引起服务器雪崩效应,这个5w,才是真正基于我们业务使⽤下redis的性能瓶颈。
我这个服务压⼒2000tps,你觉得很⽜逼?
看着很⽜逼对不对,好像tps值越⾼显得能⼒越强⼀样,其实很可笑,如果性能好只是⽐这个,那写⼀个1
+1=2的程序估计是⽆敌了吧。具体问题要具体分析,你⽜逼你要说明你⽜逼在哪⾥,在什么条件下,什么样⼦的背景,才能说你的tps是多少,这样才有意义。
反正线上没出现过问题,我们撑得住,你确定?
线上没出现过问题,不代表流量不会增加,流量不会增加不代表业务不会复杂,业务复杂性能下降是很有可能的,没有压⼒测试做保证,出问题就是⼤问题。
压⼒测试都是qa在做,有问题会反馈给我,你的服务极限到底在哪⾥?
你应该关注⼀下qa是怎么做压⼒测试的,⽆论从服务的⾓度还是从个⼈发展的⾓度。qa只能给你测试结果,不会告诉你性能瓶颈在哪⾥。
2.压⼒测试到底要关注什么
压测不是玩笑,你的4个9的指标呢
好的服务都会有⼀项指标,叫4个9,即99.99%得服务可靠性。这是衡量⼀个服务是否优秀的普世标准,压⼒测试的好坏最直观的影响4个9的保障。压⼒测试就是⽤来确保服务的稳定,给出服务稳定极限条件。稳定指的是服务负载,cpu利⽤率,接⼝的响应时长,⽹络的延迟,结果准确性等等都在你的标准之内。⽽这些指标⼜相互影响。
条件,⽤尽量多的已知去推测未知,模拟仿真,你要做的预测未来
硬件条件:服务器cpu核数、内存⼤⼩、⽹络条件、同宿主机下其他服务影响,软件条件:虚拟访问⽤户数、gc的稳定程度,响应时长要求,第三⽅依赖的可⽤程度、jdk的不同版本等都会严重影响压⼒测试的结果,造成你的压测结果上线之后达不到逾期。如果这些条件不注意,很可能你压测时按照达标条件tps=1000,其实线上tps才500的时候,服务已经崩溃了。压测的时候,最好保障压测环境与线上⼀致。你的结果才更有意义。
3.你想要的到底是个什么东西
tps只是结果,虚拟⽤户数,线程数,平均响应时长,错误数,90%的平均响应时长,服务器负载,结果准确性尽量⽤越来越多的点来评估你的服务。
tps:服务处理的吞吐量,每秒响应请求的数量,tps是压⼒测试最直观的结果,是衡量服务性能的⼀个结果性指标,⼀般说压⼒测试性能值就是tps值。最浅显直⽩的理解,统计access⽇志每秒的总数就是那⼀秒的tps值。
错误数:⼀般服务压⼒测试的时候是不允许出现错误的,即错误数:0%,但是复杂条件下,有的服务是允许出错率不超过x%的,看服务⽽定。
平均响应时长:移动互联⽹时代,你让⼀个⽤户打开app等你1s,⽤户早就跑了,打开app⽴刻看见内容是最起码的要求,⼀般好的app接⼝相应时间都是毫秒级别的,但是不同的场景不同的要求,我的上⼀家公司要求平均相应时长在20ms以内。可是上上家公司的接⼝,平均相应时长在100ms,不同的服务不同的要求,你需要到适合你⾃⼰的要求。
90%的平均响应时长:jmeter学来的,表⽰90%的事务,服务器的响应都维持在某个值附近。⽐如有三个时间:1秒、5秒、12秒,则平均时间为6秒,⽽另外⼀种情况:5秒、6秒、7秒,平均时间也为6秒,显然第⼆种⽐第⼀种要稳定多了。所以,我们在查看平均事务响应时间的时候,先看整体曲线⾛势,如果整体趋势⽐较平滑,没有忽上忽下的波动情况,取“Average Time”与“90 Percent Time”都可以,如果整体趋势毫⽆规律,波动⾮常⼤,我们就不⽤“Average Time”⽽使⽤“90 Percent Time”可能更真实些
结果准确性:多线程下访问下结果的正确性。这个在压测的时候往往容易被忽略。这个需要你在压⼒测试的时候抽查访问接⼝,查看结果是否正确,曾经碰到过qa测试通过的接⼝,上线之后发现返回结果不正确,内⽹回测正确,后来内⽹压⼒测试的时候成功复现,是由于使⽤了不安全的多线程代码导致的,其实压测的时候抽查看⼀眼,很容易看出来。
线程数:这个指标不在各⼤压⼒测试⼯具监控之内,但是这其实是压⼒测试⾮常重要的服务指标。根据经验,好多时候服务崩掉的时候,线程数已经满了,好多时候应⽤服务器的线程在某个范围之内,服务
是最健康的状态,超过某个范围,服务处于不稳定状态,处于有点⽹络抖动延迟都容易崩溃的临界点,所以熟悉这个值,你就⼼⾥清楚你的服务当前在什么状态下。
虚拟⽤户数(并发线程数):好多⼈容易把tps和虚拟⽤户数搞混,虚拟⽤户数表⽰当前正在访问你服务的⽤户数,就是说压⼒测试⼯具启动多少个线程来不停访问你的接⼝。但是实际上,哪个⽤户会像疯狗⼀样疯狂⼀直不间断的访问的你接⼝,对⽤户来说,访问你的接⼝,点进去看内容,好久不再访问才是常态(专业术语叫思考时间),可是这个值的⼤⼩,严重影响tps的值。那这个值多少合适呢?我知道的有2种做法,⼀种是求得tps的最⼤值,在压⼒测试的时候虚拟⽤户数不可测,那⼲脆不管,我就管好我服务的tps吞吐量,服务的吞吐量极限就是我的真实极限。做法就是⼀个tps最⾼时的虚拟⽤户数,记做压⼒测试的虚拟⽤户数指标,当然,这有个严重的问题,做过压⼒测试的就知道,有的服务虚拟⽤户很低时tps很⾼,但是虚拟⽤户⼀但稍有提升,性能下降的⾮常快,怎么弥补这种情况呢,策略是补区间,得到最好tps的虚拟⽤户之后,在这个虚拟⽤户数之上加减某个值(例如30),得到3个压⼒测试结果,3个压⼒测试结果的趋势作为服务的性能指标。第⼆种是估算,当前服务的tps是多少,⽤压测⼯具可以得到达到当前tps的并发线程数是多少,但这个值肯定也只是⼀个估计值⽽已。
多说⼀句,这个值为什么⼜可以不去管它:其实真正线上流量⼤的时候经常会有⼀种现象:服务直接重启撑不起来当前流量,调整前端流量分配(部分nginx摘除重启server等做法),慢慢启动就可以⽀持起线上流量,再打开所有流量,发现server⼜可以⽀持没问题了(ps:所以nginx有⼀个流量缓增的收费模块
就是⼲这个的),但是慢慢启动线上流量和⼀次打过来线上流量,其实在同⼀时刻虚拟⽤户数是差不多,斯以为这种现象是因为服务刚启动时流量全打过来时需要创建的可复⽤复⽤对象和线程很多,容易造成了服务的不稳定,那么其实压⼒测试时虚拟⽤户数重要么?它真的是不可代替的么?其实虚拟⽤户数只是⽤来探测服务性能的⼀个表现的总结⽽已,服务真正的健康情况其实反映在线程数,响应时长,服务器负载,性能瓶颈点(⽐如事务或者锁)等等,⽽虚拟⽤户数只是这些健康极限情况的表象总结⽽已。就是说,当压⼒测试总结的虚拟⽤户数在某⼀个范围值tps达到多少,其实内在真正描述的是在这个虚拟⽤户时,由于线程数是多少,负载是多少,平均相应时长是多少,线程数是多少,gc稳定程度是多少达到了tps值是多少。
4.⾯试总问的jvm调优到底是要⼲什么
请注意,jvm调优,调的是稳定,并不能带给你性能的⼤幅提升。服务稳定的重要性就不⽤多说了,保证服务的稳定,gc永远会是程序员需要考虑的不稳定因素之⼀。复杂和⾼并发下的服务,必须保证每次gc不会出现性能下降,各种性能指标不会出现波动,gc回收规律⽽且⼲净,到合适的jvm设置。详细了解jvm的话请看神书《深⼊理解java虚拟机》。说些题外话,⾯试发现,jvm调优很多⼈都没有经验,有⼈甚⾄怀疑这东西真正是否有⽤,有的公司统⼀jvm的设置贯穿所有服务。其实只是没碰到⽣产条件复杂的情况⽽已,举个简单例⼦:我曾经的公司,碰到过服务运⾏超过14h直接死机的问题,头天下午压测,第⼆天上午服务⾃动重启了,按照当时习惯,新服务需要压⼒测试满12h,原则上我的服务通过
测试,由于测试环境复杂,所有开发都可以登陆⽽且脚本很多,qa认为可能是有脚本误杀了,但是当时离上线deadline时间还早,于是决定再压⼒⼀次,成功复现,最后查看jvm发现每次fullgc之后o区总是会多⼀点,jmap打印内存栈发现char对象使⽤逐渐增⼤,最后撑满内存,最后定位到调⽤JNI发⽣内存泄露,解决了这个问题。这只是简单的⼀次,在那家公司,由于服务偏算法⽽且流量很⾼,碰到过很多这种问题。还有⼀次,压⼒测试loadrunner图像显⽰每隔⼀段时间的点上响应时间⽴刻下降,过2s⼜恢复正常,规律性很强,通过jstat发现频繁⽣成⼤对象直接进⼊⽼年代,⽼年代很快撑⼤触发full gc回收,回收时间过长造成服务暂停明显,⽴刻反应到压测的响应上。解决的办法是调⼤年轻代,让⼤对象可以在年轻代触发yong gc,调整⼤对象在年轻代的回收频次,尽可能保证⼤对象在年轻代回收,减⼩⽼年代缩短回收时间,服务果然稳定下来。当时这么调整下来会有⼀点性能损失,基本可以忽略不计,但是提升了服务的稳定性,这才是这次jvm调优最重要的。
5.常⽤的压⼒测试⼯具及命令
loadrunner,jmeter,⾃写jar包,tcpcopy等。
压⼒⼯具,⼤同⼩异,⽤什么都⾏,tcpcopy是拷贝线上流量,对于已有接⼝和服务做压⼒测试是个神器,jmeter和loadrunner是压⼒测
试⼯具,loandrunner压测结果更详细可视化不过笨重收费⽽且需要很多客户机,jmeter相对是平民版的l
oadrunner,胜在免费。之前也有由于数据需要实时从查询,⾃⼰写http的client,就需要辅助⼀些shell和awk命令统计相应指标。
jmap,jstack,jstat,详细的讲解推荐《深⼊理解java虚拟机》,其实不神秘但是特别实⽤,jstat查看内存回收概况,实时查看各个分区的分配回收情况,jmap查看内存栈,查看内存中对象占⽤⼤⼩,jstack查看线程栈,死锁,性能瓶颈,某个线程使⽤cpu过⾼导致服务整体慢等都可以通过在这些命令辅助命令看出来。
top,vmstat,sar,dstat,traceroute,ping,nc,netstat,tcpdump,ss等等具体请百度。
你的服务是跑在系统上的,是依赖第三⽅服务出问题了?是受别的服务影响还是⾃⼰利⽤资源过⾼?是⽹络抖动了?是⽹卡满了么?是cpu性能不够么?是写⼊磁盘瓶颈了?内核数据交换频繁?负载变⾼了?都需要linux命令才能看出来。
6.性能诊断到底难在哪⾥?
收到服务报警了,怎么办?打印的log⽇志都是连接不上memcache,难道是memcache的问题,⼿动客户端连接memcache没问题,难道是⽹络的问题,测试⽹络延迟很低,那到底怎么了?
其实服务类似于⼈体,有的⼈感冒的时候⿐⼦通⽓嗓⼦疼,有的⼈头疼,有的⼈流清涕,有的⼈流黄涕,
对症下药要治标治本。没有什么统⼀的答案,这就体现了经验的重要性。举个栗⼦:某天晚上突然收到报警,vpn登陆发现服务还正常返回,暂时没有报错,但是负载明显升⾼,resin线程数飙升到1000多(正常情况下该服务⾼峰期线程数500-700),cpu使⽤率偏⾼,排查:1.访问量激增?统计发现并没有。2.⽹络状况异常?通过访问服务器发现也没有,稍微慢些是因为负载稍⾼。3.程序有瓶颈?打印内存栈线程栈都没发现4.受其他同宿主服务影响?查看监控发现并没有。仔细观察发现流量稍有波动但是不明显。为什么负载⾼呢?最后排查发现是前端nginx带宽满了,带宽拥堵造成代理的后端服务⽆法及时返回数据,后端服务的句柄数拥堵造成服务器负载升⾼,服务器负载升⾼⼜使线程数和cpu利⽤率升⾼,造成服务的个别访问响应时长过长,触发报警。再严重些估计就会造成连接memcache超时,log打出连接memcache错误的⽇志。蝴蝶效应⽽已。想要快速抓住重点,其实跟医⽣⼀样,就需要你对服务⾜够了解,平时多关⼼服务状态⽽且经验真的很重要。
7.到底是加机器还是优化服务?
成本,加机器是⼀种成本,优化服务也是⼀种成本,很有可能你的服务很多依赖第三⽅,推动他们符合你的要求也是⼀种沟通成本,很多时候,⽼板的思路永远在于成本,如果他认为服务有很⼤的优化空间,那你他加机器他多半是不会同意的,所以这种要资源的事情,请考虑成本,也有⼀个问题,⼤公司往往会哭的才有奶吃,这也很现实,反正归根到底,对于我们这些搞服务端的来说,成就感不就应该是把硬件服务器资源压榨到底么?
程序员到底是干什么的转来的为了⾃⼰再看时好
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论