• 编写一个接口压测工具


    前言

    前段时间有个项目即将上线,需要对其中的核心接口进行压测;由于我们的接口是 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, h  Shows a list of commands or help for one command
    
    GLOBAL 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 value              HTTP header to add to request, e.g. "-H Content-Type: application/json"
       --target value, --tg value            http://gobyexample.com/grpc:127.0.0.1:5000
       --help, -h                            show help (default: false)
    

    考虑到受众,所以同时支持 HTTPgRPC 接口的压测。

    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或是多种实现的业务中常用。

    好处当然是显而易见:
    当接口定义好之后,不同的业务只需要根据接口实现自己的业务就好,完全不会互相影响;维护、扩展都很方便。

    支持 HTTPgRPC 也是同理实现的:

    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/

    作者: crossoverJie

    出处: https://crossoverjie.top

    欢迎关注博主公众号与我交流。

    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 如有问题, 可邮件(crossoverJie#gmail.com)咨询。

  • 相关阅读:
    Coin-row problem(1139)
    算法的稳定性
    折半查找的实现(1010)swust-oj
    判断回文(0315)SWUST-OJ
    逆置单链表(0957)swust-oj
    单链表上查找算法的实现(0955) swust-oj
    单链表的插入操作的实现(0952)SUWST-OJ
    单链表的链接(0954)swust-oj
    单链表的删除操作的实现(0953)swust-oj
    ASP.net core 2.0.0 中 asp.net identity 2.0.0 的基本使用(三)—用户账户及cookie配置
  • 原文地址:https://www.cnblogs.com/crossoverJie/p/15557448.html
Copyright © 2020-2023  润新知