项目作者: taoxinyi

项目描述 :
Fastest load generator in Go, comparable to wrk
高级语言: Go
项目地址: git://github.com/taoxinyi/rua.git
创建时间: 2021-01-01T03:22:31Z
项目社区:https://github.com/taoxinyi/rua

开源协议:Apache License 2.0

下载


Rua

Rua, written in Go, is the one of the fastest http(s) load generators (see Benchmark). Entirely inspired by wrk, rua can generate load as fast as wrk.

Rua is also intended to be one of the best load generator frameworks. You can design your own load configuration and start the load generation programmatically with only a few lines of code.

Rua by default supports its own optimized http implementation, as well as net/http , valyala/fasthttp client out of the box. It also has pluggable interface so that you can replace and configure your own http client as needed.

Benchmark

Rua has been benchmarked along with some of the most performant load generators with 6 different response types (short, medium and long response body & headers). In most situations it’s as fast as wrk and wrk2, which are written in C and considered to be the fastest for many years.

See Benchmark Details

RPS

Install

Get from go

  1. go get -u github.com/taoxinyi/rua

rua will inside $GOPATH/bin

Build from source

  1. git clone github.com/taoxinyi/rua
  2. cd rua
  3. go build

Basic Usage

The following command runs a benchmark for 5 seconds, using 2 threads, and using 10 connections(goroutines).

  1. $ rua -t 2 -c 10 -d 5s http://example.com
  2. Running 5s test @ http://example.com
  3. 2 threads and 10 connections
  4. ------------------------------------------------------------------------
  5. Connection Timeout Status
  6. Errors 0 0 0
  7. ------------------------------------------------------------------------
  8. Avg Min Max Stdev +/- Stdev
  9. Latency 12.010ms 10.915ms 31.974ms 1.210ms 95.347%
  10. ------------------------------------------------------------------------
  11. 50% 75% 90% 99% 99.9%
  12. Latency 11.999ms 12.021ms 13.000ms 18.003ms 22.030ms
  13. ------------------------------------------------------------------------
  14. Count Count/s Size Throughput
  15. Requests 4169 831.29 151 KiB 30 KiB/s
  16. Responses 4169 831.29 6.3 MiB 1.3 MiB/s
  17. 4169 responses received in 5.0151051s, 6.3 MiB read

Command Line Options

  1. Usage: rua <options> url
  2. Options:
  3. -d, --duration duration Duration of test (default 10s)
  4. -c, --connections int Number of connections (default 10)
  5. -t, --threads int Number of OS threads to be used (default 8)
  6. -H, --header string HTTP header to add to the request (default "map[]")
  7. -T, --timeout duration Timeout in seconds (default 1s)
  8. -B, --recvbuf int The buffer size in bytes for read. Should be large enough for status line and headers if raw is used (default 4096)
  9. -m, --method string The HTTP method to be used (default "GET")
  10. -b, --body string The file path containing the HTTP body to add to the request
  11. -C, --client string Use the underlying HTTP client using one of [raw fasthttp net] (default "raw")
  12. -v, --verbose Whether print verbose information

Framework Usage

The following code runs a benchmark for 5 seconds, using 2 threads, and using 10 connections(goroutines).

  1. package main
  2. import (
  3. "fmt"
  4. rua "github.com/taoxinyi/rua/framework"
  5. "github.com/taoxinyi/rua/framework/client"
  6. "os"
  7. "time"
  8. )
  9. func main() {
  10. config := &rua.LgConfig{
  11. RequestConfig: rua.RequestConfig{URL: "http://example.com"},
  12. Duration: 5 * time.Second,
  13. Connections: 10,
  14. }
  15. lg, err := rua.NewLoadGenerator(config, client.NewRawHttpClient())
  16. if err != nil {
  17. fmt.Println(err)
  18. os.Exit(-1)
  19. }
  20. stats, actualRunningTime := lg.Start()
  21. fmt.Printf("RPS: %.3f\n", float64(stats.ResponsesRecv)/actualRunningTime.Seconds())
  22. }

Implement Your Own Http Client

HttpClient and User interface can be implemented so that the framework can use your HttpClient for your workloads. e.g. HTTP/2, Redirect, customized configurations, etc.

See Client

Optimizations

Rua with customized raw HTTP client directly operates on TCP connections, which is optimized to send unchanged requests.

  1. Each goroutine has a dedicated a TCP connection, there’s no need to do any synchronization on them at all.

  2. In most scenarios, it’s not the load generator’s job to test the correctness of the response. There is no need to parse the headers and copy the body. We only need the status code, content length so that we know whether the response is complete or not.

  3. If the request will not change, then it’s immutable. There is no need to build them or convert them to bytes every time. Directly send the request bytes.

  4. Zero memory allocation during the load generation, avoid copy as much as possible.

Limitations

Rua’s optimized raw client is implemented in the following ways:

Read until reaches the first \r\n\r\n, then find Content-Length in the header. Then read until the body size equals Content-Length. Therefore HTTP pipelining is not supported. (I think it’s rarely used in practice.)

If you have extremely long headers, the recv buffer is full, and \r\n\r\n hasn’t reached yet, an error will be thrown. So you should increase the -B, --recvbuf receiver buffer size instead, so the size can at least large enough for the first \r\n\r\n

Content-Length must be present in the response, otherwise an error will be thrown since the parser doesn’t know the body size. Therefore, Connection: close is not supported, only keep-alive is supported. Also, Chunk is not supported since it only knows the body size. Use --client fasthttp instead if you need Connection: close or Chunk.

In summary, use --client fasthttp for reliable, use the default raw if you need extreme performance and your responses doesn’t have any corner cases.

Future Improvements

Rua is still in early stage and there are a lot of features to come. These Go APIs are subject to change.

I wonder if it’s the already reach the limit of Go in terms of speed and performance.

If you have any ideas to improve rua, welcome to submit a PR!

Acknowledgements

This project is entirely inspired by wrk, also thanks to other great projects like wrk2, go-wrk, fasthttp