编写一个接口压测工具
前言
前段时间有个项目即将上线,需要对其中的核心接口进行压测;由于我们的接口是 gRPC
协议,找了一圈发现压测工具并不像 HTTP
那么多。
最终发现了 ghz 这个工具,功能也非常齐全。
事后我在想为啥做 gRPC
压测的工具这么少,是有什么难点嘛?为了验证这个问题于是我准备自己写一个工具。
特性
前前后后大概花了个周末的时间完成了相关功能。
https://github.com/crossoverJie/ptg/
也是一个命令行工具,使用起来效果如上图;完整的命令如下:
NAME:
ptg - Performance testing tool (Go)USAGE:
ptg [global options] command [command options] [arguments...]COMMANDS:
help, hShows a list of commands or help for one commandGLOBAL OPTIONS:
--thread value, -t value-t 10 (default: 1 thread)
--Request value, --proto value-proto http/grpc (default: http)
--protocol value, --pf value-pf /file/order.proto
--fully-qualified value, --fqn value-fqn package.Service.Method
--duration value, -d value-d 10s (default: Duration of test in seconds, Default 10s)
--request value, -c value-c 100 (default: 100)
--HTTP value, -M value-m GET (default: GET)
--bodyPath value, --body value-body bodyPath.json
--header value, -H valueHTTP header to add to request, e.g. "-H Content-Type: application/json"
--target value, --tg valuehttp://gobyexample.com/grpc:127.0.0.1:5000
--help, -hshow help (default: false)
考虑到受众,所以同时支持
HTTP
与 gRPC
接口的压测。做
gRPC
压测时所需的参数要多一些:ptg -t 10 -c 100 -proto grpc-pf /xx/xx.proto -fqn hello.Hi.Say -body test.json-tg "127.0.0.1:5000"
比如需要提供
proto
文件的路径、具体的请求参数还有请求接口的全路径名称。目前只支持最常见的 unary call 调用,后续如果有需要的话也可以 stream。同时也支持压测时间、次数两种压测方式。
安装 想体验度朋友如果本地有 go 环境那直接运行:
go get github.com/crossoverJie/ptg
没有环境也没关系,可以再 release 页面下载与自己环境对应的版本解压使用。
文章图片
https://github.com/crossoverJie/ptg/releases
设计模式 整个开发过程中还是有几个点想和大家分享,首先是设计模式。
因为一开始设计时就考虑到需要支持不同的压测模式(次数、时间;后续也可以新增其他的模式)。
所以我便根据压测的生命周期定义了一套接口:
type (
Model interface {
Init()
Run()
Finish()
PrintSate()
Shutdown()
}
)
从名字也能看出来,分别对应:
- 压测初始化
- 运行压测
- 停止压测
- 打印压测信息
- 关闭程序、释放资源
文章图片
文章图片
然后在两个不同的模式中进行实现。
这其实就是一个典型的依赖倒置原则。
程序员要依赖于抽象接口编程、不要依赖具体的实现。其实大白话就是咱们
Java
里常说的面向接口编程;这个编程技巧在开发框架、SDK或是多种实现的业务中常用。好处当然是显而易见:
当接口定义好之后,不同的业务只需要根据接口实现自己的业务就好,完全不会互相影响;维护、扩展都很方便。
支持
HTTP
和 gRPC
也是同理实现的:type (
Client interface {
Request() (*Response, error)
}
)
文章图片
文章图片
当然前提得是前期的接口定义需要考虑周全、不能之后频繁修改接口定义,这样的接口就没有意义了。
goroutine 另外一点则是不得不感叹
goroutine+select+channel
这套并发编程模型真的好用,并且也非常容易理解。很容易就能写出一套并发代码:
func (c *CountModel) Init() {
c.wait.Add(c.count)
c.workCh = make(chan *Job, c.count)
for i := 0;
i < c.count;
i++ {
go func() {
c.workCh <- &Job{
thread:thread,
duration: duration,
count:c.count,
target:target,
}
}()
}
}
比如这里需要初始化 N 个
goroutine
执行任务,只需要使用 go
关键字,然后利用 channel 将任务写入。当然在使用
goroutine+channel
配合使用时也得小心 goroutine
泄露的问题;简单来说就是在程序员退出时还有 goroutine
没有退出。比较常见的例子就是向一个无缓冲的
channel
中写数据,当没有其他 goroutine
来读取数时,写入的 goroutine
就会被一直阻塞,最终导致泄露。总结 有
gRPC
接口压测需求的朋友欢迎试用,提出宝贵意见;当然 HTTP
接口也可以。【编写一个接口压测工具】源码地址:
https://github.com/crossoverJie/ptg/
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 一个人的旅行,三亚
- 一个小故事,我的思考。
- 一个人的碎碎念
- 七年之痒之后
- 我从来不做坏事
- 异地恋中,逐渐适应一个人到底意味着什么()
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- 迷失的世界(二十七)
- live|live to inspire 一个普通上班族的流水账0723