ultron

package module
v2.0.0-...-8b94259 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2022 License: Apache-2.0 Imports: 43 Imported by: 0

README

Ultron

Go Report Card codecov GoDoc Ultron CI CodeQL

a http load testing tool in go

Requirements

Go 1.16+

Install

go get github.com/wosai/ultron/v2

Example

LocalRunner
package main

import (
	"net/http"
	"time"

	"github.com/wosai/ultron/v2"
)

func main() {
	task := ultron.NewTask()
	attacker := ultron.NewHTTPAttacker("google")
	attacker.Apply(
		ultron.WithPrepareFunc(func() (*http.Request, error) { // 压测事务逻辑实现
			return http.NewRequest(http.MethodGet, "https://www.google.com/ncr", nil)
		}),
		ultron.WithCheckFuncs(ultron.CheckHTTPStatusCode),
	)
	task.Add(attacker, 1)

	plan := ultron.NewPlan("google homepage")
	plan.AddStages(
		&ultron.V1StageConfig{
			Duration:        10 * time.Minute,
			ConcurrentUsers: 200,
			RampUpPeriod:    10,
		}
	)

	runner := ultron.NewLocalRunner()
	runner.Assign(task)   

	if err := runner.Launch(); err != nil {
		panic(err)
	}

	if err := runner.StartPlan(plan); err != nil {
		panic(err)
	}

	block := make(chan struct{}, 1)
	<-block
}
SlaveRunner
package main

import (
	"net/http"

	"github.com/wosai/ultron/v2"
	"google.golang.org/grpc"
)

func main() {
	task := ultron.NewTask()
	attacker := ultron.NewHTTPAttacker("google")
	attacker.Apply(
		ultron.WithPrepareFunc(func() (*http.Request, error) { // 压测事务逻辑实现
			return http.NewRequest(http.MethodGet, "https://www.google.com/ncr", nil)
		}),
		ultron.WithCheckFuncs(ultron.CheckHTTPStatusCode),
	)
	task.Add(attacker, 1)

	// 启动runner
	runner := ultron.NewSlaveRunner()
	runner.Assign(task)
	runner.SubscribeResult(nil)                                          // 订阅单次压测结果
	if err := runner.Connect(":2021", grpc.WithInsecure()); err != nil { // 连接master的grpc服务
		panic(err)
	}

	// 阻塞当前goroutine,避免程序推出
	block := make(chan struct{}, 1)
	<-block
}
MasterRunner
ultron

master

Web Portal

plan

stats

Report

Terminal Table

stats report

JSON Format
{
    "first_attack": "2021-11-02T03:09:08.419359417Z",
    "last_attack": "2021-11-02T03:09:21.209236204Z",
    "total_requests": 139450,
    "total_tps": 10903.15429322517,
    "full_history": true,
    "reports": {
        "benchmark": {
            "name": "benchmark",
            "requests": 139450,
            "min": 10000253,
            "max": 40510983,
            "median": 10000000,
            "average": 11869156,
            "tps": 10903.15429322517,
            "distributions": {
                "0.50": 10000000,
                "0.60": 10000000,
                "0.70": 10000000,
                "0.80": 10000000,
                "0.90": 20000000,
                "0.95": 21000000,
                "0.97": 26000000,
                "0.98": 29000000,
                "0.99": 30000000,
                "1.00": 40510983
            },
            "full_history": true,
            "first_attack": "2021-11-02T03:09:08.419359417Z",
            "last_attack": "2021-11-02T03:09:21.209236204Z"
        }
    },
    "extras": {
        "plan": "benchmark test"
    }
}
Grafana Dashboard
scripts/grafana/dashboard.json

Enhancements

Module Type Description
github.com/wosai/ultron/attacker/fastattacker/v2 Attacker Another http attacker implemented by fasthttp
github.com/wosai/ultron/attacker/jsonrpc/v2 Attacker A attacker used for jsonrpc protocol
github.com/wosai/ultron/handler/influxdbv1/v2 Handler A handler that save attack result and report in InfluxDB v1

Documentation

Index

Constants

View Source
const (
	KeyPlan     = "plan"
	KeyAttacker = "attacker"
)

Variables

View Source
var (
	ErrPlanClosed = errors.New("plan was finished or interrupted")
)
View Source
var (
	// Logger 全局日志
	Logger *zap.Logger
)

Functions

func BuildStage

func BuildStage() *stage

func CheckHTTPStatusCode

func CheckHTTPStatusCode(_ context.Context, res *http.Response, body []byte) error

CheckHTTPStatusCode 检查状态码是否>=400, 如果是则视为请求失败

func ClearContext

func ClearContext(ctx context.Context)

func FromContext

func FromContext(ctx context.Context, key string) (interface{}, bool)

func FromContextAll

func FromContextAll(ctx context.Context) (map[string]interface{}, bool)

func NewPlan

func NewPlan(name string) *plan

func NewTask

func NewTask() *task

func StoreInContext

func StoreInContext(ctx context.Context, key string, value interface{}) bool

Types

type AttackStrategy

type AttackStrategy interface {
	Spawn() []*RampUpStep
	Switch(next AttackStrategy) []*RampUpStep
	Split(int) []AttackStrategy
	Name() string
}

AttackStrategy 压测策略描述

type AttackStrategyCommander

type AttackStrategyCommander interface {
	Open(context.Context, Task) <-chan statistics.AttackResult
	Command(AttackStrategy, Timer)
	ConcurrentUsers() int
	Close()
}

AttackStrategyCommander 压测策略

type Attacker

type Attacker interface {
	Name() string
	Fire(context.Context) error
}

Attacker 事务接口

type ExitConditions

type ExitConditions interface {
	NeverStop() bool
	Check(ExitConditions) bool
}

ExitCondition 阶段退出条件

type FixedConcurrentUsers

type FixedConcurrentUsers struct {
	ConcurrentUsers int `json:"concurrent_users"`         // 并发用户数
	RampUpPeriod    int `json:"ramp_up_period,omitempty"` // 增压周期时长
}

FixedConcurrentUsers 固定goroutine/线程/用户的并发策略

func (*FixedConcurrentUsers) Name

func (fx *FixedConcurrentUsers) Name() string

func (*FixedConcurrentUsers) Spawn

func (fc *FixedConcurrentUsers) Spawn() []*RampUpStep

Spawn 增压、降压

func (*FixedConcurrentUsers) Split

func (fx *FixedConcurrentUsers) Split(n int) []AttackStrategy

Split 切分配置

func (*FixedConcurrentUsers) Switch

func (fc *FixedConcurrentUsers) Switch(next AttackStrategy) []*RampUpStep

Switch 转入下一个阶段

type GaussianRandomTimer

type GaussianRandomTimer struct {
	StdDev      float64 `json:"std_dev"`      // 标准差
	DesiredMean float64 `json:"desired_mean"` // 期望均值
}

GaussianRandomTimer 高斯分布

func (*GaussianRandomTimer) Name

func (grt *GaussianRandomTimer) Name() string

func (*GaussianRandomTimer) Sleep

func (grt *GaussianRandomTimer) Sleep()

type HTTPAttacker

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

HTTPAttacker 内置net/http库对Attacker的实现

func NewHTTPAttacker

func NewHTTPAttacker(name string, opts ...HTTPAttackerOption) *HTTPAttacker

func (*HTTPAttacker) Apply

func (ha *HTTPAttacker) Apply(opts ...HTTPAttackerOption)

func (*HTTPAttacker) Fire

func (ha *HTTPAttacker) Fire(ctx context.Context) error

func (*HTTPAttacker) Name

func (ha *HTTPAttacker) Name() string

type HTTPAttackerOption

type HTTPAttackerOption func(*HTTPAttacker)

HTTPAttackerOption HTTPAttacker配置项

func WithCheckFuncs

func WithCheckFuncs(checks ...HTTPCheckFunc) HTTPAttackerOption

func WithClient

func WithClient(client *http.Client) HTTPAttackerOption

func WithDisableKeepAlives

func WithDisableKeepAlives(disbale bool) HTTPAttackerOption

func WithPrepareFunc

func WithPrepareFunc(prepare HTTPPrepareFunc) HTTPAttackerOption

func WithProxy

func WithProxy(proxy func(*http.Request) (*url.URL, error)) HTTPAttackerOption

func WithTimeout

func WithTimeout(t time.Duration) HTTPAttackerOption

type HTTPCheckFunc

type HTTPCheckFunc func(context.Context, *http.Response, []byte) error

HTTPCheckFunc http.Response校验函数,可由调用方自定义,如果返回error,则视为请求失败

type HTTPPrepareFunc

type HTTPPrepareFunc func(context.Context) (*http.Request, error)

HTTPPrepareFunc 构造http.Request函数,需要调用方定义,由HTTPAttacker来发送

type LocalRunner

type LocalRunner interface {
	Launch() error
	Assign(Task)
	SubscribeReport(...ReportHandleFunc)
	SubscribeResult(...ResultHandleFunc)
	StartPlan(Plan) error
	StopPlan()
}

func NewLocalRunner

func NewLocalRunner() LocalRunner

type LoggerOption

type LoggerOption struct {
	Level      string `default:"info" yaml:"level,omitempty" json:"level,omitempty" toml:"level"`
	FileName   string `yaml:"filename,omitempty" json:"filename,omitempty" toml:"filename"`
	MaxSize    int    `default:"100" yaml:"max_size,omitempty" json:"max_size,omitempty" toml:"max_size"`
	MaxBackups int    `default:"30" yaml:"max_backups,omitempty" json:"max_backups,omitempty" toml:"max_backups"`
}

type MasterRunner

type MasterRunner interface {
	Launch(...grpc.ServerOption) error   // 服务启动
	StartPlan(Plan) error                // 开始执行某个测试计划
	StopPlan()                           // 停止当前计划
	SubscribeReport(...ReportHandleFunc) // 订阅聚合报告
}

func NewMasterRunner

func NewMasterRunner() MasterRunner

type NonstopTimer

type NonstopTimer struct{}

NonstopTimer 不中断

func (NonstopTimer) Name

func (ns NonstopTimer) Name() string

func (NonstopTimer) Sleep

func (ns NonstopTimer) Sleep()

type Option

type Option struct {
	Server ServerOption
	Logger LoggerOption
}

type Plan

type Plan interface {
	Name() string
	AddStages(...Stage)
	Stages() []Stage
	Current() (int, Stage)
	Status() PlanStatus
}

Plan 定义测试计划接口

type PlanStatus

type PlanStatus int

PlanStatus 定义测试计划状态

const (
	// StatusReady 测试计划尚未执行
	StatusReady PlanStatus = iota
	// StatusRunning 测试计划执行中
	StatusRunning
	// StatusFinished 测试执行执行完成
	StatusFinished
	// StatusInterrupted 测试计划执行被中断
	StatusInterrupted
)

type RampUpStep

type RampUpStep struct {
	N        int           // 增、降的数量,>0 为加压, <0为降压
	Interval time.Duration // 间隔时间
}

RampUpStep 增/降压描述

type ReportHandleFunc

type ReportHandleFunc func(context.Context, statistics.SummaryReport)

ReportHandleFunc 聚合报告处理函数

type ResultHandleFunc

type ResultHandleFunc func(context.Context, statistics.AttackResult)

ResultHandleFunc 请求结果处理函数

type ServerOption

type ServerOption struct {
	HTTPAddr string `default:":2017" yaml:"http_addr,omitempty" json:"http_addr,omitempty" toml:"http_addr"`
	GRPCAddr string `default:":2021" yaml:"grpc_addr,omitempty" json:"grpc_addr,omitempty" toml:"grpc_addr"`
}

type SlaveAgent

type SlaveAgent interface {
	ID() string
	Extras() map[string]string
}

SlaveAgent 定义master侧的slave对象

type SlaveRunner

type SlaveRunner interface {
	Connect(string, ...grpc.DialOption) error // 连接master
	SubscribeResult(...ResultHandleFunc)      // 订阅Attacker的执行结果
	Assign(Task)                              // 指派压测任务
}

func NewSlaveRunner

func NewSlaveRunner() SlaveRunner

type Stage

type Stage interface {
	GetTimer() Timer
	GetExitConditions() ExitConditions
	GetStrategy() AttackStrategy
}

Stage 描述一个压测阶段,需要包含并发策略、延时器、退出条件

type Task

type Task interface {
	Add(Attacker, uint32)
	PickUp() Attacker
}

type Timer

type Timer interface {
	Sleep()
}

Timer 延时器

type UniformRandomTimer

type UniformRandomTimer struct {
	MinWait time.Duration `json:"min_wait,omitempty"`
	MaxWait time.Duration `json:"max_wait,omitempty"`
}

UniformRandomTimer 平均随机数

func (*UniformRandomTimer) Name

func (urt *UniformRandomTimer) Name() string

func (*UniformRandomTimer) Sleep

func (urt *UniformRandomTimer) Sleep()

type UniversalExitConditions

type UniversalExitConditions struct {
	Requests uint64        `json:"requests,omitempty"` // 请求总数,不严格控制
	Duration time.Duration `json:"duration,omitempty"` // 持续时长,不严格控制
}

exitConditions 通用的退出条件

func (*UniversalExitConditions) Check

func (sec *UniversalExitConditions) Check(actual ExitConditions) bool

Check 是否满足退出条件

func (*UniversalExitConditions) NeverStop

func (sec *UniversalExitConditions) NeverStop() bool

type V1StageConfig

type V1StageConfig struct {
	Requests        uint64        `json:"requests,omitempty"`
	Duration        time.Duration `json:"duration,omitempty"`
	ConcurrentUsers int           `json:"concurrent_users"`
	RampUpPeriod    int           `json:"ramp_up_period"` // 单位秒
	MinWait         time.Duration `json:"min_wait,omitempty"`
	MaxWait         time.Duration `json:"max_wait,omitempty"`
}

func (*V1StageConfig) GetExitConditions

func (v1 *V1StageConfig) GetExitConditions() ExitConditions

func (*V1StageConfig) GetStrategy

func (v1 *V1StageConfig) GetStrategy() AttackStrategy

func (*V1StageConfig) GetTimer

func (v1 *V1StageConfig) GetTimer() Timer

Directories

Path Synopsis
cmd
example
pkg

Jump to

Keyboard shortcuts

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