前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零开始用golang编写一个分布式测试工具

从零开始用golang编写一个分布式测试工具

原创
作者头像
王磊-字节跳动
发布2019-05-24 18:26:57
1.2K0
发布2019-05-24 18:26:57
举报
文章被收录于专栏:01ZOO01ZOO

起源

当开发http 接口的时候,往往我们会关心开发的server能承受多少压力,这时候一个比较常用的工具是 apache bench。一部分情况下ab工具确实能满足需求,但是很多时候并不能,需要分布式式测试工具。

压力测试比较关心的是产生压力获取测试对象的如TPS、响应时延等性能数据主机资源如cpu,memory消耗数据以定位性能瓶颈,简单的单机测试工具并不能很好的满足这些需求。

我们可以选择云平台的分布式测试工具,比如腾讯的wetest,阿里云也有类似产品。但是这种产品往往收费不菲。也可以选择类似的开源产品,比如locust。但是调研发现,这种开源产品往往比较简单,或者过于陈旧。google官网有一个压力测试例子,用的就是locust。大家可以看一下这个工具,基于python,功能非常简陋,master,slave模式,不支持在线编辑脚本,修改测试要重启。

如何设计这样的压力测试工具

k8s是目前比较流行的容器编排系统,是否可以在k8s上自己做一个分布式测试工具呢。当然可以用google推荐的做法,在k8s上运行master slave 模式的locust,又或者自己动手做一个。

既然运行在k8s上,那么这个测试工具实际上关心的事就比较简单了:k8s已经实现了调度,资源监控,我们的工具只需要定义脚本,运行脚本,统计测试结果,收集测试过程的资源消耗。

需要说明的是,测试工具运行在k8s上只是为了利用k8s的基础设施,简化工具设计,事实上测试的对象可以是运行在k8s上或者在k8s外的任何服务。

使用golang做测试脚本

选择golang作为测试脚本的原因一是语言成熟,语法简单,二是goroutine很方便,很容易把压力打上去,三是即有编译型语言的高性能,同时又像脚本一样能够快速运行(编译很快)。

golang本身是编译型语言,不是脚本语言,运行要先编译,但是因为编译很快,实际上很容易当成一个脚本来执行,比如这个例子。或者显式的运行go build,go run,像docker/distribution项目的dockerfile这样。那么要实现一个"动态"运行golang的工具要做的就是:定义一种类型的任务,用户的测试脚本只要实现这种任务的interface,客户端就可以装载这种脚本编译运行。具体举例如下。

代码语言:txt
复制
// 1. 定义一个TTask作为interface
type TTask interface {
	Name() string
	Run() int
}

// 2. 用户的测试脚本实现这个interface
// New ....
func newhello() task.TTask {
	return &hellotask{}
}

type hellotask struct {
}

func (h *hellotask) Name() string {
	return "task"
}

func (h *hellotask) Run() int {
	time.Sleep(time.Microsecond * 10)
	return 0
}

// 3. 实现一种注册式的插件机制,让用户的任务注册进来
var tasksets = make(map[string]NewFunc, 0)
func Register(newfunc NewFunc) {
	t := newfunc()
	_, registered := tasksets[t.Name()]
	if registered {
		panic(fmt.Sprintf("TTask named %s already registered", t.Name()))
	}
	tasksets[t.Name()] = newfunc
}

// 用户脚本中要注册他的脚本
Register(task.NewFunc(newhello))

// 4. 测试客户端不关心用户脚本的实现细节,运行tasksets里面TTask就可以了
func main() {
    for _, f := range tasksets {
        f().Run()
        ...
    }
}

一个更复杂一点的例子在这里

使用k8s的基础设施

首先实现测试任务,使用job是很合适不过的,设置parallelism并发运行。

其次要实现任务的动态添加和挂载,可以使用k8s的configmap来实现。使用configmap来保存用户的脚本,运行agent的时候将脚本自动挂载到agent的容器对应路径,容器启动脚本中加入build流程,这样就能很方便的实现一种"动态"的运行golang脚本的效果了。

当压力测试使用多个节点的时候,我们往往需要同时观测测试客户端和服务端的cpu等资源监控,因为客户端已经天然的运行在k8s上了,可以直接使用k8s的监控设施。

另外测试工具的设计并没有局限在测试运行在k8s上的server,但是如果刚好,被测试的对象也运行在k8s上,那么也可以很方便的或者server的宿主机metrics,如果不是,那么server端就需要装一个收集metric的deamon实现同样的效果了。

效果

dashboard支持查看测试任务,每个任务有一个最近运行的记录和创建时间。

编辑一个测试项目,测试脚本是用golang编辑的,需要实现一个TTaskSet 的interface。支持设置任务的goroutine和运行时间,权重,设置权重之后goroutine数量会在多个taskset之间分配,一个taskset又可以添加多个task。taskset并发运行,一个taskset中的task串行运行,这样设计的好处是可以满足用户并发,串行,带context的串行多种需求,非常灵活。任务可以选择运行的节点,多个节点并发测试。

运行完测试的效果,目前还没有加入测试中的client,server资源监控,但是简单的测试统计已经有了。如图是测试的一个运行在1G虚拟机的nginx容器的测试结果。测试结果同时有各个节点的运行结果和汇总结果,同时绘制latency的百分位图。

完整项目地址在 https://github.com/arlert/ymir 欢迎拍砖。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 起源
  • 如何设计这样的压力测试工具
  • 使用golang做测试脚本
  • 使用k8s的基础设施
  • 效果
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档