练习Go语言-HTTP压力测试.md


2019年6月14日星期五补充错误信息.

2017年10月20日星期五 7:26
##设计
压力测试HTTP服务端。比如看看你的电脑能同时建立多少长连接。
算是我的第一个Go程序。
熬夜了。

主要运用了:

  • 参数处理
  • channel通讯
  • 整合了CPU和内存统计代码

协程和通讯的事都让Go做了,我就是来验证它的性能的。

步骤

创建一个目录 tmp 先,不然服务器因为没有地方写诊断信息 会报错:

2019/06/14 16:38:56 open ./tmp/cpu.prof: The system cannot find the path specified.

解决方案:

mkdir tmp

该服务端 和 客户端 我在最近版本的GoLang已经测试.

用法是:
默认是5万连接.

  1. 运行服务端
    看到提示:
  2. 运行客户端
    一段时间后.
  3. 在服务端窗口 输入回车结束.
  4. 分析诊断文件
    产生了 CPU 和 内存统计文件 在./tmp/文件夹下:
    怎么分析?诊断文件看这里: https://www.cnblogs.com/yjf512/archive/2012/12/27/2835331.html
    主要是 CPU的不同函数上的信息,以及内存占用的信息.

想测试别的网站就: 把客户端的 网址改成该网站. 但注意可能搞坏…

服务端

servic.go

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm() //解析参数
	if openLog {
		fmt.Println(r.Form)
		fmt.Println("path", r.URL.Path)
		fmt.Println("scheme", r.URL.Scheme)
		fmt.Println(r.Form["url_long"])
	}
	if openLog {
		for k, v := range r.Form {
			fmt.Println("key:", k)
			fmt.Println("val:", strings.Join(v, ""))
		}
	}

	io.WriteString(w, "Hello,Test Me!")
	fmt.Fprintf(w, "Hello!")

	My_Mem_Prof()
	/*
	   不退出测试长连接性能
	*/
	chLongLink <- true
	<-chExitThreads
}

var chExitThreads chan bool
var chLongLink = make(chan bool, 1000*100)

func openService() {
	http.HandleFunc("/MyWeb", helloHandler)
	err := http.ListenAndServe(":8686", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err.Error())
	}
}

const openLog bool = false

var ch_sync chan bool

func calc() {
	number := 0
	for {
		_, ok := <-chLongLink
		if !ok {
			break
		}
		number++
		if (number % 100) == 0 {
			fmt.Println("now long link:", number)
		}
	}
	fmt.Println("All long link number is:", number)
	close(ch_sync)
	fmt.Println("End")
}
func My_Mem_Prof() {
	fm, err := os.OpenFile("./tmp/mem.out", os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
	}
	pprof.WriteHeapProfile(fm)
	fm.Close()
}

func My_Cpu_Prof() {
	f, err := os.OpenFile("./tmp/cpu.prof", os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	pprof.StartCPUProfile(f)
	defer pprof.StopCPUProfile()
	<-chExitThreads
	pprof.StopCPUProfile()
	fmt.Println("End CPU Prof")
	f.Close()
	close(chExitProf)
}

var chExitProf chan bool

func main() {
	/*初始化channel通知*/
	chExitThreads = make(chan bool)
	ch_sync = make(chan bool)
	chExitProf = make(chan bool)

	runtime.GOMAXPROCS(runtime.NumCPU() * 2)
	fmt.Println("CPU Number:", runtime.NumCPU())
	fmt.Println("Thread Number:", runtime.NumCPU()*2)
	go My_Cpu_Prof()

	exp := `Please visit:  
	"http://localhost:8686/MyWeb"
	`
	/
	fmt.Println(exp)
	go calc()
	go openService()

	/*
		直到用户输入才开始退出协程
	*/
	input := make([]byte, 1024)
	os.Stdin.Read(input)
	close(chLongLink)
	<-ch_sync
	fmt.Println("OK")
	close(chExitThreads)
	<-chExitProf
}

客户端

client.go

// client.go
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"runtime"
	"time"
)

func client(exit_ch chan int, webPath string) {

	var err error

	resp, err := http.Get(webPath)
	if err != nil {
		// handle error
		fmt.Println(err.Error())
		goto threadEnd
	}

	/*body*/
	_, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
		fmt.Println(err.Error())
		goto threadEnd
	}
	defer resp.Body.Close()
	//fmt.Println(string(body))
threadEnd:
	exit_ch <- 1

}

func main() {
	var webPath string
	flag.StringVar(&webPath, "webpath", http://localhost:8686/MyWeb", "Tested Web Path")
	test_time_work := flag.Int("time", 50000, "Test times")
	flag.Parse()
	fmt.Println(webPath)
	runtime.GOMAXPROCS(runtime.NumCPU() * 2)

	exit_ch := make(chan int)

	test_time := time.Now()

	for i := 0; i < *test_time_work; i++ {
		go client(exit_ch, webPath)
	}

	for i := 0; i < *test_time_work; i++ {
		<-exit_ch
		fmt.Println("Success time!:", i+1)
	}
	test_time_end := time.Since(test_time)
	fmt.Println("End*******************")
	fmt.Println("CPU Number:", runtime.NumCPU())
	fmt.Println(test_time_end)
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值