qube

package module
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 27, 2023 License: MIT Imports: 25 Imported by: 0

README

qube

build Go Report Card

qube is a DB load testing tool.

Installation

brew install winebarrel/qube/qube

Usage

Usage: qube --data-file=STRING --dsn=STRING

Flags:
  -h, --help                Show help.
      --[no-]force          Do not abort test on error. (default: disabled)
  -f, --data-file=STRING    NDJSON file path of queries to execute.
      --key="q"             Key name of the query field in the test data. e.g. {"q":"SELECT ..."}
      --[no-]loop           Return to the beginning after reading the test data. (default: enabled)
      --[no-]random         Randomize the starting position of the test data. (default: disabled)
      --commit-rate=UINT    Number of queries to execute "COMMIT".
  -d, --dsn=STRING          DSN to connect to.
                              - MySQL: https://github.com/go-sql-driver/mysql#examples
                              - PostgreSQL: https://github.com/jackc/pgx/blob/df5d00e/stdlib/sql.go
      --[no-]noop           No-op mode. No actual query execution. (default: disabled)
  -n, --nagents=1           Number of agents.
  -r, --rate=FLOAT-64       Rate limit (qps). "0" means unlimited.
  -t, --time=DURATION       Maximum execution time of the test. "0" means unlimited.
      --[no-]progress       Show progress report.
      --version
$ echo '{"q":"select 1"}' > data.jsonl
$ echo '{"q":"select 2"}' >> data.jsonl
$ echo '{"q":"select 3"}' >> data.jsonl

$ qube -d 'root@tcp(127.0.0.1:13306)/' -f data.jsonl -n 5 -t 10s
00:05 | 5 agents / exec 95788 queries, 0 errors (23637 qps)
...
{
  "ID": "b1e23c00-1601-46eb-ad2b-fdf01154243d",
  "StartedAt": "2023-11-12T12:08:29.296154+09:00",
  "FinishedAt": "2023-11-12T12:08:39.297268+09:00",
  "ElapsedTime": "10.001173875s",
  "Options": {
    "Force": false,
    "DataFile": "data.jsonl",
    "Key": "q",
    "Loop": true,
    "Random": false,
    "CommitRate": 0,
    "DSN": "root@tcp(127.0.0.1:13306)/",
    "Driver": "mysql",
    "Noop": false,
    "Nagents": 5,
    "Rate": 0,
    "Time": "10s"
  },
  "GOMAXPROCS": 10,
  "QueryCount": 238001,
  "ErrorQueryCount": 0,
  "AvgQPS": 23797,
  "MaxQPS": 24977,
  "MinQPS": 21623,
  "MedianQPS": 24051.5,
  "Duration": {
    "Time": {
      "Cumulative": "49.569869935s",
      "HMean": "200.366µs",
      "Avg": "208.275µs",
      "P50": "199.75µs",
      "P75": "222.042µs",
      "P95": "288.875µs",
      "P99": "363.375µs",
      "P999": "594.208µs",
      "Long5p": "349.679µs",
      "Short5p": "142.483µs",
      "Max": "2.796209ms",
      "Min": "98.709µs",
      "Range": "2.6975ms",
      "StdDev": "54.681µs"
    },
    "Rate": {
      "Second": 4801.323875008872
    },
    "Samples": 238001,
    "Count": 238001,
    "Histogram": [
      {
        "98µs - 368µs": 235807
      },
      {
        "368µs - 638µs": 2008
      },
      {
        "638µs - 907µs": 117
      },
      {
        "907µs - 1.177ms": 19
      },
      {
        "1.177ms - 1.447ms": 9
      },
      {
        "1.447ms - 1.717ms": 4
      },
      {
        "1.717ms - 1.986ms": 2
      },
      {
        "1.986ms - 2.256ms": 3
      },
      {
        "2.256ms - 2.526ms": 12
      },
      {
        "2.526ms - 2.796ms": 20
      }
    ]
  }
}

Test

docker compose up -d
make testacc

Tools to convert logs to NDJSON

Documentation

Index

Constants

View Source
const (
	InterimReportIntvl = 1 * time.Second
)
View Source
const (
	RecIntvl = 1 * time.Second
)

Variables

View Source
var (
	// End of data
	EOD = errors.New("EOD")
)

Functions

This section is empty.

Types

type Agent

type Agent struct {
	*AgentOptions
	ID string
	// contains filtered or unexported fields
}

func NewAgent

func NewAgent(taskID string, agentNum uint64, options *Options, rec *Recorder, limiter *rate.Limiter) (*Agent, error)

func (*Agent) Start

func (agent *Agent) Start(ctx context.Context) error

type AgentOptions

type AgentOptions struct {
	Force bool `kong:"negatable,default='false',help='Do not abort test on error. (default: disabled)'"`
}

type DBConfig

type DBConfig struct {
	DSN       string    `` /* 184-byte string literal not displayed */
	Driver    DBDriver  `kong:"-"`
	Noop      bool      `kong:"negatable,default='false',help='No-op mode. No actual query execution. (default: disabled)'"`
	NullDBOut io.Writer `json:"-" kong:"-"`
}

func (*DBConfig) OpenDBWithPing added in v0.3.0

func (config *DBConfig) OpenDBWithPing(autoCommit bool) (DBIface, error)

type DBDriver added in v0.2.0

type DBDriver string
const (
	DBDriverMySQL      DBDriver = "mysql"
	DBDriverPostgreSQL DBDriver = "pgx"
)

type DBIface

type DBIface interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
	Close() error
}

type Data

type Data struct {
	*DataOptions
	// contains filtered or unexported fields
}

func NewData

func NewData(options *Options) (*Data, error)

func (*Data) Close

func (data *Data) Close() error

func (*Data) Next

func (data *Data) Next() (string, error)

type DataOptions

type DataOptions struct {
	DataFile   string `kong:"short='f',required,help='NDJSON file path of queries to execute.'"`
	Key        string `kong:"default='q',help='Key name of the query field in the test data. e.g. {\"q\":\"SELECT ...\"}'"`
	Loop       bool   `kong:"negatable,default='true',help='Return to the beginning after reading the test data. (default: enabled)'"`
	Random     bool   `kong:"negatable,default='false',help='Randomize the starting position of the test data. (default: disabled)'"`
	CommitRate uint   `kong:"help='Number of queries to execute \"COMMIT\".'"`
}

type DataPoint

type DataPoint struct {
	Time     int64
	Duration time.Duration
}

type DataPointWithErr added in v1.0.0

type DataPointWithErr struct {
	DataPoint
	IsError bool
}

type JSONDuration

type JSONDuration time.Duration

func (JSONDuration) MarshalJSON

func (jd JSONDuration) MarshalJSON() (b []byte, err error)

type NullDB

type NullDB struct {
	// contains filtered or unexported fields
}

func (*NullDB) Close

func (db *NullDB) Close() error

func (*NullDB) Exec

func (db *NullDB) Exec(query string, args ...interface{}) (sql.Result, error)

func (*NullDB) ExecContext

func (db *NullDB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

type Options

type Options struct {
	AgentOptions
	DataOptions
	DBConfig
	Nagents  uint64        `kong:"short='n',default='1',help='Number of agents.'"`
	Rate     float64       `kong:"short='r',help='Rate limit (qps). \"0\" means unlimited.'"`
	Time     time.Duration `json:"-" kong:"short='t',help='Maximum execution time of the test. \"0\" means unlimited.'"`
	X_Time   JSONDuration  `json:"Time" kong:"-"` // for report
	Progress bool          `json:"-" kong:"negatable,help='Show progress report.'"`
}

type Progress

type Progress struct {
	// contains filtered or unexported fields
}

func NewProgress

func NewProgress(w TTY, noop bool) *Progress

func (*Progress) Close added in v0.1.1

func (progress *Progress) Close()

func (*Progress) IncrDead

func (progress *Progress) IncrDead()

func (*Progress) Start

func (progress *Progress) Start(ctx context.Context, rec *Recorder)

type QPSSet

type QPSSet []float64

func NewQPSSet

func NewQPSSet(dps []DataPoint) QPSSet

func (QPSSet) Stats

func (qpsSet QPSSet) Stats() (minQPS float64, maxQPS float64, medianQPS float64)

type Recorder

type Recorder struct {
	*Options
	ID string

	StartedAt  time.Time
	FinishedAt time.Time
	// contains filtered or unexported fields
}

func NewRecorder

func NewRecorder(id string, options *Options) *Recorder

func (*Recorder) Add

func (rec *Recorder) Add(dpes []DataPointWithErr)

func (*Recorder) Close

func (rec *Recorder) Close()

func (*Recorder) CountAll added in v1.0.0

func (rec *Recorder) CountAll() int

func (*Recorder) CountSuccess added in v1.0.0

func (rec *Recorder) CountSuccess() int

func (*Recorder) DataPoints

func (rec *Recorder) DataPoints() []DataPoint

func (*Recorder) ErrorQueryCount

func (rec *Recorder) ErrorQueryCount() int

func (*Recorder) Report

func (rec *Recorder) Report() *Report

func (*Recorder) Start

func (rec *Recorder) Start()

type Report

type Report struct {
	ID              string
	StartedAt       time.Time
	FinishedAt      time.Time
	ElapsedTime     JSONDuration
	Options         *Options
	GOMAXPROCS      int
	QueryCount      int
	ErrorQueryCount int
	AvgQPS          float64
	MaxQPS          float64
	MinQPS          float64
	MedianQPS       float64
	Duration        *tachymeter.Metrics
}

func NewReport

func NewReport(rec *Recorder) *Report

func (*Report) JSON added in v1.0.0

func (report *Report) JSON() string

type TTY added in v1.0.3

type TTY interface {
	io.Writer
	Fd() uintptr
}

type Task

type Task struct {
	*Options
	ID string
}

func NewTask

func NewTask(options *Options) *Task

func (*Task) Run

func (task *Task) Run() (*Report, error)

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL