两个小实例测试
ab压测
package main import ( "flag" "fmt" "log" "net/http" "os" "strings" "sync" "time" ) var usage = `Usage: %s [options] Options are: -n number Number of requests to perform -c concurrency Number of multiple requests to make at a time -t timeout Seconds to max. wait for each response -m method Method name ` var ( number int concurrency int timeout int method string url string ) func init() { flag.Usage = func() { fmt.Fprintf(os.Stderr, usage, os.Args[0]) } flag.IntVar(&number, "n", 1000, "") flag.IntVar(&concurrency, "c", 10, "") flag.IntVar(&timeout, "t", 1, "") flag.StringVar(&method, "m", "GET", "") if flag.NArg() != 1 { exit("Invalid url") } method = strings.ToUpper(method) url = flag.Args()[0] if method != "GET" { exit("Invalid method") } if number < 1 || concurrency < 1 { exit("-n and -c cannot be smaller than 1.") } if number < concurrency { exit("-n cannot be less than -c.") } } type benchmark struct { number int concurrency int timeout int method string url string duration chan time.Duration start time.Time end time.Time } func (b *benchmark) run() { b.duration = make(chan time.Duration, b.number) b.start = time.Now() b.runWorks() b.end = time.Now() b.report() } func (b *benchmark) runWorks() { var wg sync.WaitGroup wg.Add(b.concurrency) for i := 0; i < b.concurrency; i++ { go func() { defer wg.Done() b.runWork(b.number / b.concurrency) }() } wg.Wait() close(b.duration) } func (b *benchmark) runWork(num int) { client := &http.Client{ Timeout:time.Duration(b.timeout) * time.Second, } for i := 0; i < num; i++ { b.request(client) } } func (b *benchmark) request(client *http.Client) { req, err := http.NewRequest(b.method, b.url, nil) if err != nil { log.Fatal(req) } start := time.Now() client.Do(req) end := time.Now() b.duration <- end.Sub(start) } func (b *benchmark) report() { sum := 0.0 num := float64(len(b.duration)) for duration := range b.duration { sum += duration.Seconds() } rps := int(num / b.end.Sub(b.start).Seconds()) tpr := sum / num * 1000 fmt.Printf("rps: %d [#/sec]\n", rps) fmt.Printf("tpr: %.3f [ms]\n", tpr) } func exit(msg string) { flag.Usage() fmt.Fprintln(os.Stderr, "\n[ERROR] " + msg) os.Exit(1) } func main() { b := benchmark{ number: number, concurrency: concurrency, timeout: timeout, method: method, url: url, } b.run() }
数据库sql测试
package main import ( "database/sql" "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" "log" "os" "sync" "time" ) var db *sql.DB var number, concurrency int var cmd = &cobra.Command{ Use: "benchmark sql", Short: "a sql benchmark tool", Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { cmd.Usage() os.Exit(1) } return nil }, Run: func(cmd *cobra.Command, args []string) { b := benchmark{ sql:args[0], number:number, concurrency:concurrency, } b.run() }, } func init() { cobra.OnInitialize(config) cmd.Flags().IntVarP(&number, "number", "n", 100, "number") cmd.Flags().IntVarP(&concurrency, "concurrency", "c", 1, "concurrency") cmd.Flags().SortFlags = false } func config() { viper.AddConfigPath(".") viper.SetConfigName("db") viper.SetConfigType("toml") err := viper.ReadInConfig() if err != nil { log.Fatal(err) } driver := viper.GetString("driver") dsn := viper.GetString("dsn") db, err = sql.Open(driver, dsn) if err != nil { log.Fatal(err) } } type benchmark struct { sql string number int concurrency int duration chan time.Duration start time.Time end time.Time } func (b *benchmark) run() { b.duration = make(chan time.Duration, b.number) b.start = time.Now() b.runWorkers() b.end = time.Now() b.report() } func (b *benchmark) runWorkers() { var wg sync.WaitGroup wg.Add(b.concurrency) for i := 0; i < b.concurrency; i++ { go func() { defer wg.Done() b.runWorker(b.number / b.concurrency) }() } wg.Wait() close(b.duration) } func (b *benchmark) runWorker(num int) { for i := 0; i < num; i++ { start := time.Now() b.request() end := time.Now() b.duration <- end.Sub(start) } } func (b *benchmark) request() { if _, err := db.Exec(b.sql); err != nil { log.Fatalln(err) } } func (b *benchmark) report() { sum := 0.0 num := float64(len(b.duration)) for duration := range b.duration { sum += duration.Seconds() } qps := int(num / b.end.Sub(b.start).Seconds()) tpq := sum / num * 1000 fmt.Printf("qps: %d [#/sec]\n", qps) fmt.Printf("tpq: %.3f [ms]\n", tpq) }
轮子一堆,我们没必要面面俱到,当一个组装工也是不错的,说实话,我认为多数人的智商就不要自己写轮子,不如学点方法论。
两个都是学习自火丁笔记
https://blog.huoding.com/2017/06/09/623
https://blog.huoding.com/2019/08/21/768
end
一个没有高级趣味的人。
email:hushui502@gmail.com