preface

Some time ago, a project was about to go online, and the core interface needed to be tested. Since our interface is gRPC protocol, we found that there are not as many pressure tools as HTTP after looking around.

Eventually, I found a tool called GHZ, which has a lot of features.

Afterwards, I was wondering why there are so few tools for gRPC pressure measurement. Is there any difficulty? To test this question I decided to write a tool of my own.

features

It took about a weekend to complete the function.

Github.com/crossoverJi…

It is also a command line tool that looks like the image 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 - the value http://gobyexample.com/grpc:127.0.0.1:5000 -- help, -h show a help (default: false)Copy the code

Considering the audience, both HTTP and gRPC interfaces are supported.

Do gRPC pressure measurement required more parameters:

PTG -t 10 -c 100 -proto grpc-pf /xx/xx.proto -fqn hello.hi.say -body test.json -tg "127.0.0.1:5000"Copy the code

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

Currently, only the most common unary call calls are supported, and streams can be used later if needed.

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

The installation

Want to experience degree friends if there is a local GO environment that directly run:

go get github.com/crossoverJie/ptg
Copy the code

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

Github.com/crossoverJi…

Design patterns

There are a few points I’d like to share with you throughout the development process, starting with design patterns.

This is because of the need to support different pressure measurement modes (frequency, time; Other modes can be added later).

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

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

As can be seen from the name, they correspond to:

  • Pressure test initialization
  • Operating pressure measurement
  • Stop the pressure test
  • Prints pressure measurement information
  • Close the program and release resources

Then implement it in two different patterns.

This is a classic dependency inversion principle.

Programmers rely on abstract interfaces, not concrete implementations.

In fact, the plain language is we often said in Java interface programming; This programming technique is commonly used in developing frameworks, SDKS, or businesses with multiple implementations.

The benefits are obvious: once the interface is defined, different businesses only need to implement their own services according to the interface, without affecting each other at all. Easy to maintain and expand.

Support for HTTP and gRPC is implemented in the same way:

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

Of course, the premise is that the interface definition needs to be considered in the early stage, and can not be changed frequently later, so that the interface is meaningless.

goroutine

The other thing is that the Goroutine + Select + Channel concurrent programming model works really well and is easy to understand.

It’s easy to write a set of concurrent code:

func (c *CountModel) Init(a) {
	c.wait.Add(c.count)
	c.workCh = make(chan *Job, c.count)
	for i := 0; i < c.count; i++ {
		go func(a) {
			c.workCh <- &Job{
				thread:   thread,
				duration: duration,
				count:    c.count,
				target:   target,
			}
		}()
	}
}
Copy the code

For example, we need to initialize N Goroutines to perform tasks. We just need to use the go keyword and write the tasks using channel.

Of course, when using goroutine+channel, you should also be careful about goroutine leakage. Simply put, goroutine doesn’t quit when the programmer quits.

A common example is writing data to an unbuffered channel. When there is no other Goroutine to read the number, the goroutine will block and leak.

conclusion

GRPC interface pressure test needs friends welcome to try, put forward valuable advice; Of course the HTTP interface can also be used.

Source code address: github.com/crossoverJi…