Bootstrap

第7周作业

压测工具

写一个web压测工具。

输入

  • url

  • 请求总次数

  • 并发数

输出

  • 平均响应时间

  • 95%响应时间

测试

  • 10并发

  • 100请求

  • 压测:http://www.baidu.com

package main

import (
	"fmt"
	"net/http"
	"sort"
	"sync"
	"sync/atomic"
	"time"
)

func main() {
	results := pressure("http://www.baidu.com", 100, 10)
	items, errors := getItemsAndErrors(results)
	fmt.Printf("avg:%f, pct95:%d, errors:%d", avg(items), pct95(items), errorCount(errors))
}

type result struct {
	ms int64
	ok bool
}

func pressure(url string, counts, concurrent int) []result {
	var wg sync.WaitGroup
	var c uint64
	wg.Add(concurrent)
	ch := make(chan result, concurrent)
	for i := 0; i < concurrent; i++ {
		go func() {
			wg.Wait()
			for ; atomic.AddUint64(&c, 1) <= uint64(counts); {
				ms, ok := getUrl(url)
				ch <- result{ms: ms, ok: ok}
			}
		}()
		wg.Done()
	}
	results := make([]result, 0, counts)
	for r := range ch {
		results = append(results, r)
		if len(results) == counts {
			break
		}
	}
	return results
}

func getUrl(url string) (ms int64, ok bool) {
	start := time.Now()
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
		return 0, false
	}
	defer resp.Body.Close()
	//fmt.Println(resp)
	return time.Since(start).Milliseconds(), err == nil
}

func avg(items []int64) float64 {
	sum := int64(0)
	for _, i := range items {
		sum += i
	}
	return float64(sum) / float64(len(items))
}

func pct95(items []int64) int64 {
	ints := make([]int, len(items))
	for i, item := range items {
		ints[i] = int(item)
	}
	sort.Ints(ints)
	pct95Position := len(items) * 95 / 100
	return int64(ints[pct95Position])
}

func errorCount(oks []bool) int {
	count := 0
	for _, ok := range oks {
		if !ok {
			count++
		}
	}
	return count
}

func getItemsAndErrors(results []result) ([]int64, []bool) {
	items, errors := make([]int64, len(results)), make([]bool, len(results))
	for i, r := range results {
		items[i] = r.ms
		errors[i] = r.ok
	}
	return items, errors
}