性能测试思路及常遇到的问题分析

开始性能测试前需要了解的内容:


1、项目具体需求及测试范围:测哪些功能,哪些接口,存在哪些场景。


2、指标:响应时间,并发数,tps,总tps,稳定性交易总量多少,事务成功率,交易波动范围,稳定运行时长,资源利用率等


3、环境:生产环境服务器数量,测试环境服务器数量,按照资源配比得出测试指标。


4、协议:系统用什么协议进行通讯。


5、压力机数量:如果并发用户数太多,需要把压力发到不同的压力机,不然可能会存在压力机瓶颈问题,导致tps和响应时间抖动。


6、交易占比:分析线上日志得出tps占比。


7、系统架构:请求流经过哪些环节,压测时监控这些环节。

 

测试:


1、基准:一个用户迭代100次,关注响应时间,事务成功率100%。


2、负载:10个用户跑10分钟,关注响应时间,事务成功率100%。


3、容量:估算一个总tps,根据公式计算出每个交易的pacing和vu,获取系统最大处理能力(最优容量),再令外测出三个梯度作为对比(两组小于最优容量,一组大于最优容量),四组容量VU等差,tps等差,对比每组容量实际占比和测试占比(越接近越能模拟真实场景),关注响应时间,总tps,tps,事务成功率,AP cpu利用率,DB cpu利用率,线程死锁,数据库死锁。


其中响应时间应小于负载测试时间,总tps应约等于预估总tps(相差不超过10是正常的),每个交易的tps应接近预估总tps*占比,事务成功率100%,AP cpu小于60%,DB cpu小于80%。dump线程栈检测是否有线程死锁,查看数据库日志看是否有数据库死锁。


4、稳定性:采取最优容量的80%作为压力持续运行24小时,观察系统长时间运行的性能表现,关注响应时间,tps,总tps,事务成功率,交易总数,观察是否有内存溢出(堆溢出,栈溢出,持久代溢出),cpu利用率是否达标,mem是否不持续增长,是否能正常触发fullgc,gc时间,gc频率, fullgc时间,fullgc频率(重点关注,JVM调优就是为了减少fullgc频率)。

      

监控:


容量测试和稳定性测试时启动nmon监控。

 

压测中遇到的性能问题及解决办法:


一、容量测试过程中cpu过高


1、用vmstat实时监控cpu使用情况。很小的压力AP cpu却到了80%多,指标是不能超过60%。


2、分析是use cpu过高还是sys cpu过高,常见的是use cpu使用过高。


3、如果是sys cpu使用过高,先把消耗cpu最多的进程找出来(top命令),再找到该线程下消耗cpu过高的是哪几个线程,再把该线程转换成16进制,再用jstack命令来dump线程栈,看这个线程栈在调用什么东西导致use cpu过高。

      

二、内存溢出(堆溢出、栈溢出、持久代溢出)


1、堆内存溢出


1)稳定性压测一段时间后,LR报错,日志报java.lang.OutOfMemoryError.Java heap space。


2)用jmap -histo pid命令dump堆内存使用情况,查看堆内存排名前20个对象,看是否有自己应用程序的方法,从最高的查起,如果有则检查该方法是什么原因造成堆内存溢出。


3)如果前20里没有自己的方法,则用jmap -dump来dump堆内存,在用MAT分析dump下来的堆内存,分析导出内存溢出的方法。


4)如果应用程序的方法没有问题,则需要修改JVM参数,修改xms,xmx,调整堆内存参数,一般是增加堆内存。


2、栈内存溢出


1)稳定性压测一段时间后,LR报错,日志报Java.Lang.StackOverflowError。


2)修改jvm参数,将xss参数改大,增加栈内存。


3)栈溢出一定是做批量操作引起的,减少批处理数据量。

 

3、持久代溢出


1)稳定性压测一定时间后,日志报Java.Lang.OutOfMenoryError.PermGen Space。


2)这种原因是由于类、方法描述、字段描述、常量池、访问修饰符等一些静态变量太多,将持久代占满导致持久代溢出。


3)修改jvm配置,将XX:MaxPermSize=256参数调大。尽量减少静态变量。

 

三、线程死锁


1、容量测试压测一段时间后,LR报连接超时。


2、造成这种现象的原因很多,比如带宽不够,中间件线程池不够用,数据库连接池不够,连接数占满等都会造成连接不上而报超时错误。


3、jstack命令dump线程栈,搜索线程栈里有没有block,如果有的话就是线程死锁,找到死锁的线程,分析对应的代码。

 

四、数据库死锁


1、容量测试压测一段时间后,LR报连接超时。


2、造成这种现象的原因很多,比如带宽不够,中间件线程池不够用,数据库连接池不够,连接数占满等都会造成连接不上而报超时错误。


3、数据库日志中搜索block,能搜到block的话就是存在数据库死锁,找到日志,查看对应的sql,优化造成死锁的sql。

 

五、数据库连接池不释放


1、容量测试压测一段时间后,LR报连接超时。


2、造成这种现象的原因很多,比如带宽不够,中间件线程池不够用,数据库连接池不够,连接数占满等都会造成连接不上而报超时错误。


3、去数据库查看应用程序到数据库的连接有多少个( show full processlist),假如应用程序里面配置的数据库连接为30,在数据库查看应用程序到数据库的连接也是30,则表示连接池占满了。


将配置改成90试试,去数据库看如果连接到了90,则可以确定是数据库连接池不释放导致的。查看代码,数据库连接部分是不是有创建连接但是没有关闭连接的情况。基本就是这种情况导致的,修改代码即可。

 

六、TPS上不去


1、压力大的时候tps频繁抖动,导致总tps上不去。查看是否有fullgc(tail -f gc_mSrv1.log | grep full)。


2、pacing设置太小也会导致tps上不去,对抖动大的交易多增加点用户即可。


3、tps抖动,单压抖动大的交易,发现很平稳,这时怀疑是不是压力太大导致,所以发容量的时候把压力最大的那只交易分到其他压力机,然后发现tps不抖动了。注意:多台压力机只影响tps抖动,不会影响服务器的cpu。


4、看响应时间有没有超时,看用户数够不够。

 

七、服务器压力不均衡(相差1%-2%是正常的)


1、跑最优容量的时候,四台AP只有一台cpu超过60%,其他三台都在60%以下。

2、查看服务器是否有定时任务。

3、查看是否存在压力机瓶颈。

4、是否存在带宽瓶颈(局域网不存在此问题)。

5、查看部署的版本,配置是否一样。

6、可能别人也在用这些AP,因为同一台物理机上有很多虚拟机,因为别人先用,资源被别人先占了。

 

八、fullgc时间太长


1、跑容量和稳定性的时候,出现LR报请求超时错误,查看后台日志是fullgc了,看LR几点报的错和日志里fullgc的时间是否对应,fullgc会暂停整个应用程序,导致LR前端没响应,所以报错,这时可以减少old代内存,从而减少fullgc时间,减少fullgc时间LR就不会报错,让用户几乎感觉不到应用程序暂停。


2、四台AP轮流着full gc(部分server fullgc,其他server也会fullgc),这时可以制定策略让不同的server不同时fullgc,或者等夜间交易量少时写定时任务重启服务。

 

注意:

服务器日志为error下测试。

服务启动后几分钟内发压压力会很大,最好是服务启动两三分钟后再开始跑压力。

  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
垃圾分类是一个非常重要的环保问题,深度学习可以帮助我们解决这个问题。下面是一些实现垃圾分类数据训练的代码以及问题解决的思路: 1. 数据收集和准备 首先,我们需要收集垃圾分类的数据集。可以从开源数据集收集,也可以自己拍照收集。然后将数据集分为训练集和测试集,以便评估模型的性能。 2. 数据增强 为了增强模型的泛化能力和减少过拟合,我们可以对数据集进行一些数据增强操作,如旋转、缩放、翻转等。 3. 模型选择 根据垃圾分类的特点,我们可以选择一些经典的深度学习模型,如AlexNet、VGG、ResNet等。也可以使用迁移学习,将预训练模型的参数进行微调。 4. 模型训练 使用训练集对模型进行训练,并使用测试集进行验证。可以使用交叉熵作为损失函数,使用Adam等优化器进行优化。可以使用学习率衰减等技巧来提高模型的性能。 5. 模型评估 使用测试集对模型进行评估,计算准确率、精确率、召回率等指标。也可以使用混淆矩阵来分析模型的性能。 下面是一个基于PyTorch的垃圾分类模型训练的代码示例: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transforms import torchvision.datasets as datasets # 数据集路径 train_path = "./data/train" test_path = "./data/test" # 数据增强 transform_train = transforms.Compose([ transforms.RandomResizedCrop(224), # 随机裁剪 transforms.RandomHorizontalFlip(), # 随机翻转 transforms.ToTensor(), # 转为张量 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 归一化 ]) transform_test = transforms.Compose([ transforms.Resize(256), # 调整大小 transforms.CenterCrop(224), # 心裁剪 transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 数据集加载 train_dataset = datasets.ImageFolder(train_path, transform=transform_train) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) test_dataset = datasets.ImageFolder(test_path, transform=transform_test) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) # 模型定义 class GarbageNet(nn.Module): def __init__(self, num_classes=10): super(GarbageNet, self).__init__() self.features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(128), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ) self.avgpool = nn.AdaptiveAvgPool2d((7, 7)) self.classifier = nn.Sequential( nn.Linear(256 * 7 * 7, 512), nn.ReLU(inplace=True), nn.Linear(512, num_classes), ) def forward(self, x): x = self.features(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.classifier(x) return x # 模型初始化 model = GarbageNet(num_classes=10) model = model.cuda() # 损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 训练 for epoch in range(10): train_loss = 0.0 train_correct = 0 train_total = 0 for inputs, labels in train_loader: inputs = inputs.cuda() labels = labels.cuda() optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() train_loss += loss.item() _, predicted = outputs.max(1) train_total += labels.size(0) train_correct += predicted.eq(labels).sum().item() train_acc = 100. * train_correct / train_total train_loss /= len(train_loader) # 测试 test_loss = 0.0 test_correct = 0 test_total = 0 with torch.no_grad(): for inputs, labels in test_loader: inputs = inputs.cuda() labels = labels.cuda() outputs = model(inputs) loss = criterion(outputs, labels) test_loss += loss.item() _, predicted = outputs.max(1) test_total += labels.size(0) test_correct += predicted.eq(labels).sum().item() test_acc = 100. * test_correct / test_total test_loss /= len(test_loader) # 输出训练和测试结果 print('Epoch [%d/%d], Train Loss: %.4f, Train Acc: %.2f%%, Test Loss: %.4f, Test Acc: %.2f%%' % (epoch + 1, 10, train_loss, train_acc, test_loss, test_acc)) ``` 上面的代码使用了一个简单的卷积神经网络进行垃圾分类。具体的训练过程可以参考代码注释。 在实际训练,可能会遇到一些问题,如过拟合、梯度消失等。可以采取一些技巧来解决这些问题,如增加数据集、使用正则化等。另外,也可以使用一些预训练模型来提高模型的性能,如使用ResNet、Inception等模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值