性能测试资源占用问题排查及解决
- 运行压测前资源消耗
- 运行压测时(10个并发用户)时资源消耗
- 压测数据丢失,从压测报告中发现有大量的测试数据丢失,导致数据不完整
- 通过日志分析,启动压测时大量运行python插件,通过进程管理,goland下挂着N多的python程序,还好每次运行插件的目录是同一个,否则就可以看到运行时生成N多的debugtalk.py文件
问题排查
- 根据日志得出,有大量开始运行python插件的信息,根据
start to prepare python plugin
查到initPlugin
下调用了BuildPlugin
- 在
NewCaseRunner
的时候调用了initPlugin
- boomer中有2个地方调用了
NewCaseRunner
函数
解决问题思路及优缺点
- 在用例运行结束时停止
plugin
的操作- 优点:不用太多操作,不用考虑线程问题
- 缺点:每个并发数都会运行一个plugin,循环运行,如果一千个用户,那么运行就会有一千个python进程,从上面看,每个python进程需要13M,大约需要13G内存,如果一万个用户需要
130G
内存,显然也不是很好
- 修改
NewCaseRunner
,在调用initPlugin
时增加限制,一个debugtalk只运行一次- 优点:一次并发只运行一次
- 缺点:会造成plugin压力比较大,一万个用户同时操作可能会导致问题
综合考虑考虑下,采用2
方式会更加稳妥,缺点可以采用分布式压测做分流问题,分布式压测后续可以通过k8s部署多个工作节点
解决方案
- 每次运行时有个唯一值,以此来确定是否需要执行initPlugin,好在之前的设计的 debugtalk path 是唯一值,这次不用改动到其他代码
- 通过单例设计模式实现,因为是多线程运行,所以需要加锁
- 通过map实现可以同时运行多个实例,主要是兼容接口测试,否则不同项目访问到的可能是同一个plugin实例
// Package hrp NewCaseRunner 方法下把initPlugin修改成cheetahInitPlugin
package hrp
func (r *HRPRunner) NewCaseRunner(testcase *TestCase) (*CaseRunner, error) {
caseRunner := &CaseRunner{
testCase: testcase,
hrpRunner: r,
parser: newParser(),
}
// init parser plugin
//plugin, err := initPlugin(testcase.Config.Path, r.venv, r.pluginLogOn)
//压测运行时会同时运行多个plugin,用单例方式控制每次压测任务只能运行一个plugin
plugin, err := cheetahInitPlugin(testcase.Config.Path, r.venv, r.pluginLogOn)
if err != nil {
return nil, errors.Wrap(err, "init plugin failed")
}
if plugin != nil {
caseRunner.parser.plugin = plugin
caseRunner.rootDir = filepath.Dir(plugin.Path())
}
// ... 省略其他代码
}
// Package hrp 增加 cheetahInitPlugin 函数
package hrp
import (
"github.com/httprunner/funplugin"
"github.com/pkg/errors"
"sync"
)
var cheetahPlugin = make(map[string]*funplugin.IPlugin)
var mutex sync.Mutex
func cheetahInitPlugin(path, venv string, logOn bool) (plugin funplugin.IPlugin, err error) {
plugins := cheetahPlugin[path]
if plugins == nil {
mutex.Lock()
defer mutex.Unlock()
if plugins == nil {
plugin, err = initPlugin(path, venv, logOn)
if err != nil {
return nil, errors.Wrap(err, "init plugin failed")
}
cheetahPlugin[path] = &plugin
plugins = &plugin
}
}
return *plugins, nil
}
解决后效果
- 数据不再丢失
- cpu、内存数据正常
往期文档
- cheetah 自动化测试平台开源项目
- 了解如何接入httprunner
- 测试平台接入 HttpRunner V4(一)基本功能接入
- 测试平台接入 HttpRunner V4(二)使用 config 实现用例之间的参数传递