3
头图

Preface

Some time ago, a project was about to go online, and the core interface needs to be pressure tested; because our interface is the gRPC protocol, I found that there are not as many HTTP

Finally, I found the ghz , which is also very versatile.

Afterwards, I was wondering why gRPC stress testing. Is there any difficulty? In order to verify this problem, I am going to write a tool myself.

<!--more-->

characteristic

It probably took a weekend to complete the related functions.

https://github.com/crossoverJie/ptg/

It is also a command line tool, the effect is as shown above; the complete command is as follows:

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)

Considering the audience, it supports the pressure test of the HTTP and gRPC

gRPC are more parameters required for 06191aa1bc5fb0 pressure test:

ptg -t 10 -c 100 -proto grpc  -pf /xx/xx.proto -fqn hello.Hi.Say -body test.json  -tg "127.0.0.1:5000"

For example, you need to provide proto file, the specific request parameters, and the full path name of the request interface.

Currently, only the most common unary call is supported, and it can be streamed later if necessary.

At the same time, it also supports two pressure measurement methods: time and frequency.

Install

If you want to experience friends, if you have a go environment locally, run it directly:

go get github.com/crossoverJie/ptg

It doesn't matter if there is no environment, you can download the version corresponding to your environment from the release page and decompress it for use.


https://github.com/crossoverJie/ptg/releases

Design Patterns

There are still a few points to share with you throughout the development process, the first is the design pattern.

Because at the beginning of the design, it is considered to support different pressure test modes (number of times, time; other modes can be added later).

So I defined a set of interfaces based on the life cycle of stress testing:

type (
    Model interface {
        Init()
        Run()
        Finish()
        PrintSate()
        Shutdown()
    }
)    

It can also be seen from the name, respectively corresponding to:

  • Stress test initialization
  • Run pressure test
  • Stop pressure test
  • Print pressure test information
  • Close the program and release resources


Then implement it in two different modes.

This is actually a typical dependency inversion principle.

Programmers must rely on abstract interface programming, not on specific implementations.

In fact, the vernacular is the Java ; this programming technique is commonly used in development frameworks, SDKs, or multiple implementations of business.

The benefits are of course obvious:
After the interface is defined, different businesses only need to implement their own business based on the interface, and will not affect each other at all; maintenance and expansion are very convenient.

Support for HTTP and gRPC is also achieved in the same way:

type (
    Client interface {
        Request() (*Response, error)
    }
)    


Of course, the premise is that the interface definition in the early stage needs to be considered thoroughly, and the interface definition cannot be frequently modified later, so the interface is meaningless.

goroutine

Another point is that I have to sigh that the goroutine+select+channel really easy to use and easy to understand.

It is easy to write a set of concurrent code:

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,
            }
        }()
    }
}

For example, here you need to initialize N goroutine perform tasks, you only need to use the go keyword, and then use the channel to write the task.

Of course, when using goroutine+channel conjunction with the use, you must also be careful goroutine leakage of 06191aa1bc64c7; in simple terms, there is still goroutine does not exit when the programmer exits.

A more common example is to channel . When there is no other goroutine to read the data, the written goroutine will eventually lead to leakage.

Summarize

Friends with gRPC interface pressure test requirements are welcome to try it and provide valuable comments; of course, the HTTP interface is also available.

Source address:
https://github.com/crossoverJie/ptg/


crossoverJie
5.4k 声望4k 粉丝