Hi, my name is Ivan and I am developing high-load solutions in Tarantool . I will tell you how and why we chose Pandora for load testing an application on Tarantool, as well as show an example of how to use it.
Description of the application under test
Let's test the sharded-queue distributed queue module for how quickly we can insert and retrieve queue tasks. The application API is based on a binary protocol that allows you to perform basic data operations, call functions (RPC), and execute custom lua code. In our case, these are two functions: queue.tube_name:put
and queue.tube_name:take
.
Choosing a testing tool
There are a lot of testing tools, but we need to choose the right ones among them. We will select according to the following criteria:
- You need to walk on a binary protocol. Therefore, you will have to write code in a programming language for which there is a connector to Tarantool. Jmeter, bfg, Pandora and Gatling are capable of this.
- . Phantom, wrk, Jmeter, Pandora Gatling.
- . , , . bfg, Pandora Gatling.
-
. . influxdb, , Jmeter Gatling. Taurus ( ). . Jmeter, Pandora, bfg Phantom. - . , — .
, : . Jmeter Pandora, Taurus Jmeter Gatling.
Jmeter Gatlling?
Java-, Java, Groovy Scala . , , , Go.
Pandora — , Go ..
Go — ?
Pandora — ?
Go.
. — ?
, , c , , , .
as code
, , .
?
, .
go get github.com/tarantool/go-tarantool \
github.com/spf13/afero \
github.com/yandex/pandora
: , .
:
type Ammo struct { Method string TubeName string Params map[string] interface {} }
. , .
: .
tnt_queue_ammo.json
:
{"Method": "put", "TubeName": "test-tube", "Params": {"data": "task"}} {"Method": "take", "TubeName": "test-tube"}
TubeName
— sharded-queue.
:
type GunConfig struct { Target []string `validate:"required"` User string `validate:"required"` Pass string `validate:"required"` }
yaml
- Pandoragun
:
gun: type: tnt_queue_gun target: - localhost:3301 - localhost:3302 user: admin pass: queue-app-cluster-cookie
.
type
.
:
type Gun struct { conn *tarantool.Connection conf GunConfig aggr core.Aggregator }
, ( Tarantool).
Bind
. . .
func (g *Gun) Bind(aggr core.Aggregator, deps core.GunDeps) error { conn, err := tarantool.Connect( g.conf.Target[rand.Intn(len(g.conf.Target))], tarantool.Opts{ User: g.conf.User, Pass: g.conf.Pass, }, ) if err != nil { log.Fatalf("Error: %s", err) } g.conn = conn g.aggr = aggr return nil }
Shoot
. . , , , .
queueCall
Tarantool go-tarantool:
func (g *Gun) Shoot(coreAmmo core.Ammo) { ammo := coreAmmo.(*Ammo) sample := netsample.Acquire(ammo.Method) code := 200 var err error startTime := time.Now() switch ammo.Method { case "put": _, err = g.queueCall(ammo.TubeName, "put", ammo.Params["data"]) case "take": _, err = g.queueCall(ammo.TubeName, "take") } sample.SetLatency(time.Since(startTime)) if err != nil { log.Printf("Error %s task: %s", ammo.Method, err) code = 500 } defer func() { sample.SetProtoCode(code) sample.AddTag(ammo.TubeName) g.aggr.Report(sample) }() }
:
- .
- ( HTTP).
- , .
: 20 . 25 . 60 . ( ) 1 .
rps:
duration: 60s
type: line
from: 20000
to: 25000
startup:
type: once
times: 1000
:
pandora:
enabled: true
package: yandextank.plugins.Pandora
pandora_cmd: ./tnt_queue_gun
config_file: ./tnt_queue_load.yaml
:
docker run -v $(pwd):/var/loadtest \
-v $SSH_AUTH_SOCK:/ssh-agent \
-e SSH_AUTH_SOCK=/ssh-agent \
--net host \
-it direvius/yandex-tank
:
Go- Tarantool, .
, queue.tube_name:ack
, ID . , InfluxDB Grafana- Overload.
For more information about the architecture and capabilities of Pandora, you can refer to the report of its creator on Heisenbug conference.