随便测了青岛OJ的docker,好不容易跑完压力测试,一看Analysis给我整晕了。就这?
合并就是两个y轴叠一起,关联就是一个y轴当x,一个y轴当y,这分析个锤子。
不会真有人拿这个来进行性能分析吧?不会吧不会吧?(逃
果断换R。
linux安装rstat,教程很多。Controller在Unix Resource Graph增加measurement,选择全部指标。用SSH连接机器即可。这样就能获取远程服务器的性能了。
我测得是同学部署的免费阿里云学生机,性能已经很渣渣了,但是50个虚拟用户还是很难跑满,于是OJ的程序就设定是循环输出100万个1,模拟复杂的OJ题目(反正跑起来都是RE)
在Analysis里把所有图合并,然后点击右侧的graphData,导出数据格式为csv格式。因为导出的列名太乱,手动编辑一下,只保留最核心的名字。
首先我们要找出什么指标彼此之间相关性高,因为如果我们想要确定真正的瓶颈,必须要找到那些彼此影响的因素,并从中找出主导者。否则我们找到的瓶颈很可能并不是瓶颈,而是因为其他地方先瓶颈而连累的受害者。
首先先导入数据(在?知乎你这代码框为什么没有R支持),因为R只支持Date类型,不支持时分秒,因此我用int代替时间,将Time设置为运行后的秒数
setwd("D:\\Rdata")
df<-read.csv("Stressload.csv",header=1)
df$Time = seq.int(from = 0,by =8,length.out=53)
由于部分服务器数据因为采样频率或者压力测试而搞崩了,所以去除na的行以表尊敬。另外,有的数据列是全0的,它们的相关性无法计算,因此也剔除。
nonnadf<-na.omit(df)
nonzero<-nonnadf[,which(colSums(nonnadf)>0)]
然后使用R的相关矩阵库,进行计算,同时标注显著性,不显著的打X
library(ggcorrplot)
corr <- round(cor(nonzero), 1)
p.mat <- cor_pmat(nonzero)
ggcorrplot(corr,
hc.order = TRUE,
p.mat = p.mat
)
根据相关性和实际含义,从下向上对指标聚类,可以分为四类
1.Client
均为客户端的最终性能相关。
2. Network
均为经过服务器前的网络状态
也就是经过服务器后的网络状态
3. CPU
这是服务器的CPU指标
4.内存
是服务器的内存指标
现在我们有了聚类分析告诉我们哪些指标一起分析,就不需要再像无头苍蝇一样导出乱Merge了。这是相关分析的好处。
客户端分析
ggplot(df)+
geom_bar(stat="identity",aes(Time,Throughput,color=ResponseTime,alpha=Fail))+
scale_color_gradient(low = "green",high = "red")
df$FailPercentage = df$Fail/(df$Fail+df$Pass)
ggplot(df)+geom_line(aes(Time,FailPercentage),color="black")
负载增加,失败率和时延增加很正常,因此我们只关注几个异常点:
50s的时候时延这么低,为啥失败率反而高;另外150s峰值,之后为啥瞬间变成0呢?
带着这几个疑问继续分析。
网络分析
ggplot(nonnadf)+
geom_bar(stat="identity",aes(Time,Interrupt),color="black",fill="white")+
geom_bar(stat="identity",aes(Time,Hits,alpha=Hits),fill="black")+
geom_line(aes(Time,IncomingPackets),color="green")+
geom_line(aes(Time,OutgoingPackets),color="Red")+
scale_alpha_continuous(range=c(0.1,1))
Interrupt很稳定,说明网卡没挂,但是CPU处理不过来了。
红线和绿线代表收发包速率,可以看出来,有两个低谷,恰好就是50s+和150s+对应的两个点,在他们之前都是峰值。
也就是说,一瞬间的压力过大把服务器弄垮了,需要时间进行恢复?
带着这个问题继续分析。
内存分析
ggplot(nonnadf)+
geom_line(aes(Time,Paging),color="black")+
geom_line(aes(Time,Run),color="red",linetype="dashed")+
geom_point(aes(Time,DiskTraffic,alpha = DiskTraffic),color="Blue")+
annotate(geom="text",x=56,y=55,label="stress test")
负载增大的那一刻,瞬间产生大量的Paging out,这说明什么?Linux会将被淘汰的页放在硬盘上,因此才会有Disk Traffic,如果这么多页被淘汰,说明有很多页被创建。原因可能是因为内存不足么?
带着这个问题继续分析。
CPU分析
ggplot(nonnadf)+
geom_line(aes(Time,CPU,color=ContextSwitch))+
geom_line(aes(Time,SystemCPU,color=ContextSwitch))+
geom_point(aes(Time,CPU,alpha=Swap.out,size=10))+
guides(alpha=F)+
geom_point(aes(Time,CPU,size=AverageLoad),alpha=0.4, color="red")+
scale_color_gradient(low = "green",high = "red")+
scale_size_continuous(range = c(0,2))+
annotate(geom="text",x=56,y=105,label="swap out")
首先单纯考虑CPU指标之间的影响,可以看见,等待的进程数目最高可高达10,并且每秒钟进行40次进程切换,这就给下方的内核态带来了巨大的开销(大约10%)。
另外,高负载时,CPU的利用率却进入了两个谷底,这不得不说很奇怪。可以联系其他类的指标猜想一下。
先看50s,果然,这个时候发生了重要的事,25次swap-out。
swap-out和page-out就没法比了,swap-out指的是整个进程空间的所有页全部迁移到硬盘上,说明此时的物理内存严重不足,直接被突如其来的高负载击穿了。CPU直接被这种异常拖胯。之后客户端知道服务端出了问题,hit频率不再那么高了,这才稳定下来(这个时候的Hit = 60+,之后维持在30左右)
然而,150s的时候,并没有发生什么内存相关的事,这又是为什么呢?
观察网络的信息,在50s后的短暂时间内,通过限制CPU收发包并且进行疯狂丢包,服务质量总算是稍微好了点,于是hit又开始增加了。一下子请求又给上去了。
Linux里面存储网络包是通过skb队列进行的,中断的时候需先进队列,之后再通过软中断慢慢进行Bottom Half解码。
具体原因我也不太清楚,只能猜想一下:
随便查了一下,据说极端情况下收包中断可能会一直抢占CPU造成软中断无法运行,收包队列得不到处理,进而造成大量丢包。这就是所谓的receive-livelock。
skb队列满了,但是一直来新的请求,那么就会直接丢包,等包全丢完了等下再来处理软中断,发现没包可处理了,结果就是CPU利用率短暂下滑。但是可以肯定的是肯定和请求频率有关,频率一高就容易丢包。
之后通过一系列的负反馈,客户端和服务器也相对知根知底了一点,请求频率相对平稳,虽然因为资源本身的限制响应时延还是很离谱。
可以看出,主要问题在于突然出现的高压直接摧垮了内存和网络,连带着CPU一起拉胯。CPU跑到100%不是事,明明有负载却没跑到100%才有问题,跑到100%大不了就升级呗。
目标应该是如何平复这种高压,就像是水库蓄水一样。
因为Docker是个黑盒,所以并不知道具体实现是啥,只能随口胡诌几句了。反正我这种重复执行同一段代码的,OJ优化好一点估计一点压力都没有。