前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >R|数据分析|性能测试分析

R|数据分析|性能测试分析

作者头像
朝闻君
发布2021-11-22 10:25:48
7560
发布2021-11-22 10:25:48
举报
文章被收录于专栏:用户9199536的专栏

随便测了青岛OJ的docker,好不容易跑完压力测试,一看Analysis给我整晕了。就这?

合并就是两个y轴叠一起,关联就是一个y轴当x,一个y轴当y,这分析个锤子。

不会真有人拿这个来进行性能分析吧?不会吧不会吧?(逃

果断换R。


监控Linux服务器性能并收集数据

linux安装rstat,教程很多。Controller在Unix Resource Graph增加measurement,选择全部指标。用SSH连接机器即可。这样就能获取远程服务器的性能了。

我测得是同学部署的免费阿里云学生机,性能已经很渣渣了,但是50个虚拟用户还是很难跑满,于是OJ的程序就设定是循环输出100万个1,模拟复杂的OJ题目(反正跑起来都是RE)

在Analysis里把所有图合并,然后点击右侧的graphData,导出数据格式为csv格式。因为导出的列名太乱,手动编辑一下,只保留最核心的名字。

计算相关性,确定性能指标彼此影响

首先我们要找出什么指标彼此之间相关性高,因为如果我们想要确定真正的瓶颈,必须要找到那些彼此影响的因素,并从中找出主导者。否则我们找到的瓶颈很可能并不是瓶颈,而是因为其他地方先瓶颈而连累的受害者。

首先先导入数据(在?知乎你这代码框为什么没有R支持),因为R只支持Date类型,不支持时分秒,因此我用int代替时间,将Time设置为运行后的秒数

代码语言:javascript
复制
setwd("D:\\Rdata")
df<-read.csv("Stressload.csv",header=1)
df$Time = seq.int(from = 0,by =8,length.out=53)

由于部分服务器数据因为采样频率或者压力测试而搞崩了,所以去除na的行以表尊敬。另外,有的数据列是全0的,它们的相关性无法计算,因此也剔除。

代码语言:javascript
复制
nonnadf<-na.omit(df)
nonzero<-nonnadf[,which(colSums(nonnadf)>0)]

然后使用R的相关矩阵库,进行计算,同时标注显著性,不显著的打X

代码语言:javascript
复制
library(ggcorrplot)
corr <- round(cor(nonzero), 1)
p.mat <- cor_pmat(nonzero)
ggcorrplot(corr,
  hc.order = TRUE,
  p.mat = p.mat
)

根据相关性和实际含义,从下向上对指标聚类,可以分为四类

1.Client

  • ResponseTime客户端事务平均响应时间
  • Throughput客户端包吞吐量
  • Fail客户端事务失败概率
  • Run客户端运行的Vuser

均为客户端的最终性能相关。

2. Network

  • Interrupt是网卡发出中断的次数,也就是服务器端在网络未丢包情况下接受的请求
  • Hits是客户端发出的请求

均为经过服务器前的网络状态

  • IncomingPacket收包速率
  • OutgoingPacket发包速率

也就是经过服务器后的网络状态

3. CPU

  • CPU总CPU利用率
  • SystemCPU内核态
  • UserCPU用户态
  • ContextSwtich进程切换
  • AverageLoad是同时刻处于Ready状态的进程数目。

这是服务器的CPU指标

4.内存

  • Page.out是动态内存不足的情况下,将页交换到磁盘
  • Swap.out是整个进程空间的所有内存均,进行Swap说明物理内存严重不足,
  • DiskTraffic是磁盘的吞吐量可以反映交换的数目

是服务器的内存指标


关联分析

现在我们有了聚类分析告诉我们哪些指标一起分析,就不需要再像无头苍蝇一样导出乱Merge了。这是相关分析的好处。

客户端分析

代码语言:javascript
复制
ggplot(df)+
geom_bar(stat="identity",aes(Time,Throughput,color=ResponseTime,alpha=Fail))+
scale_color_gradient(low = "green",high = "red")
代码语言:javascript
复制
df$FailPercentage = df$Fail/(df$Fail+df$Pass)
ggplot(df)+geom_line(aes(Time,FailPercentage),color="black")

负载增加,失败率和时延增加很正常,因此我们只关注几个异常点:

  • 50s+的时候,失败率为什么这么高?
  • 150s+的时候,失败率为什么这么高?

50s的时候时延这么低,为啥失败率反而高;另外150s峰值,之后为啥瞬间变成0呢?

带着这几个疑问继续分析。

网络分析

代码语言:javascript
复制
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+对应的两个点,在他们之前都是峰值。

也就是说,一瞬间的压力过大把服务器弄垮了,需要时间进行恢复?

带着这个问题继续分析。

内存分析

代码语言:javascript
复制
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分析

代码语言:javascript
复制
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%大不了就升级呗。

目标应该是如何平复这种高压,就像是水库蓄水一样。

  1. 限制评测机最大连接数
  2. 外接消息队列服务,缓存消息,避免速率太快网卡接收不了直接丢包
  3. 扩大内存,避免swap out
  4. 评测机和服务器分离,这样服务器本身的其他操作延迟不会受到影响
  5. 缓存代码执行结果,同一段程序就别再运行了直接照搬完事儿
  6. 动态监控输出,输出过程中如果不匹配直接WA并停止,不要等待输出完成

因为Docker是个黑盒,所以并不知道具体实现是啥,只能随口胡诌几句了。反正我这种重复执行同一段代码的,OJ优化好一点估计一点压力都没有。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 监控Linux服务器性能并收集数据
  • 计算相关性,确定性能指标彼此影响
  • 关联分析
  • 优化思路
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档