golang分層測試之http壓測腳本編寫(2)

前言

  • 前一篇文已經(jīng)簡單講解怎么通過goroutines的能力編寫并發(fā)http壓測腳本降狠,但前文有提到過,主線程為了等待goroutine都運行完畢溜畅,不得不在程序的末尾使用time.Sleep() 來睡眠一段時間捏卓,等待其他線程充分運行。對于簡單的代碼,100個for循環(huán)可以在1秒之內(nèi)運行完畢怠晴,time.Sleep() 也可以達到想要的效果遥金,但是對于大多數(shù)真實業(yè)務(wù)和工作場景來說,1秒肯定會不夠的蒜田,并且大部分時候我們都無法預(yù)知for循環(huán)內(nèi)代碼運行時間的長短稿械。這時候就不能使用time.Sleep() 來完成等待操作了,這里我們就可以使用golang的一個類似于計數(shù)器的組件sync.WaitGroup

sync.WaitGroup模塊

  • WaitGroup 對象內(nèi)部有一個計數(shù)器冲粤,最初從0開始美莫,它有三個方法:Add(), Done(), Wait() 用來控制計數(shù)器的數(shù)量。Add(n) 把計數(shù)器設(shè)置為n 梯捕,Done() 每次把計數(shù)器-1 厢呵,wait() 會阻塞代碼的運行,直到計數(shù)器地值減為0傀顾,結(jié)合goroutines使用
import (
    "fmt"
    "sync"
)


func main() {
    wg := sync.WaitGroup{}
    wg.Add(20)
    for i := 0; i < 20; i++ {
        go func(i int) {
            fmt.Println(i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

可以執(zhí)行查看一些輸出

go run synctest.go
1
5
2
3
4
7
6
19
15
0
10
14
18
16
12
8
11
13
17
9
  • 這里首先把wg 計數(shù)設(shè)置為20襟铭, 每個for循環(huán)運行完畢都把計數(shù)器減一,主函數(shù)中使用Wait() 一直阻塞短曾,直到wg為0,也就是所有的20個for循環(huán)都運行完畢寒砖,WaitGroup 通過計數(shù)器的方式很好地控制了gorountines和主線程的執(zhí)行關(guān)系

sync.WaitGroup模塊編寫場景化的壓測腳本

  • 有了sync.WaitGroup提供的能力,我們可以更好的基于一些場景去編寫壓測腳本
  • 有這樣子的一個服務(wù)器
#! /usr/bin/env 
#coding=utf-8
import socket
import json
import requests

from flask import Flask, request,jsonify,g

app = Flask(__name__)

filename='demo.txt'

@app.route('/apisetdata', methods=['POST'])
def setdata():
        msg=request.json["msg"]
        print(msg)
        with open(filename, 'w') as f:
            f.write(str(msg))
            f.close()

        resp=jsonify({"code":200,"state":"set msg ok","msg":msg})
        resp.status_code=200
        return resp


@app.route('/apigetdata', methods=['GET'])
def getdata():
        f = open(filename, 'r')
        msg=f.read()
        resp=jsonify({"code":200,"state":"get msg ok","msg":msg})
        resp.status_code=200
        return resp


if __name__ == "__main__":
    app.run(debug=True)


  • msg保存著demo.txt的內(nèi)容嫉拐,通過apigetdata接口可以獲取內(nèi)容哩都,通過apisetdata接口可以修改demo.txt的內(nèi)容,我們現(xiàn)在需要對修改demo.txt的內(nèi)容后查詢這個場景進行壓測椭岩,這樣我們就可以獲得這樣的壓測腳本
package main

import (
    "fmt"
    "net/http"
    "sync"
    "time"
    "bytes"
    "encoding/json"
    "io/ioutil"
    simplejson "github.com/bitly/go-simplejson"
)


var (
    success = 0
    failure = 0
    useTime = 0.0 //記錄請求成功失敗數(shù)和使用時間
)

var (
    num =100 //要發(fā)送的請求數(shù)
    con =100 //并發(fā)數(shù)
)

type HttpData struct {

    Msg string `json:"msg"`

}

var wg sync.WaitGroup //創(chuàng)建一個計數(shù)器



func dotest(num int) { //場景化請求方法茅逮,在里面可以自定義需要編輯的內(nèi)容

    defer wg.Done() //進入到方法后計算器-1璃赡,標記創(chuàng)建了一個goroutine

    no := 0
    ok := 0
    url := "http://127.0.0.1:5000/apisetdata"
    url2:= "http://127.0.0.1:5000/apigetdata"
    contentType := "application/json;charset=utf-8"

    var httpdata HttpData
    httpdata.Msg = "terrychow"

    
    b ,err := json.Marshal(httpdata)
    if err != nil {
        fmt.Println("json format error:", err)
        return
    }

    body := bytes.NewBuffer(b)

    for i := 0; i < num; i++ {

        //修改內(nèi)容部分
        resp, err := http.Post(url, contentType, body) //通過apisetdata接口修改內(nèi)容

        if err != nil {
            no += 1
            fmt.Println("error failed:", err)
            continue 
        }

        defer resp.Body.Close()

        //讀取內(nèi)容部分
        resp2, err := http.Get(url2) //通過apigetdata接口獲取內(nèi)容
        if err != nil {
            no += 1
            fmt.Println("error failed:", err)
            continue 
        }

        defer resp2.Body.Close()
        body, err := ioutil.ReadAll(resp2.Body)
        res, err := simplejson.NewJson([]byte(string(body)))

        getmsg, err := res.Get("msg").String()


        if resp.StatusCode != 200 {
            no += 1
            continue
        }

        if getmsg!=httpdata.Msg{ //斷言修改的內(nèi)容
            no += 1
            continue        
        }

        ok += 1
        continue
    }

    success += ok
    failure += no

}       

// 主函數(shù)
func main() {
    startTime := time.Now().UnixNano()

    // 并發(fā)開始
    for i := 0; i < con; i++ {
        wg.Add(1)
        go dotest(num/con)
    }
    // fmt.Println("主程序開始wait")
    wg.Wait()
    endTime := time.Now().UnixNano()
    useTime = float64(endTime-startTime) / 1e9
    // 輸出結(jié)果
    fmt.Println()
    fmt.Println("Complete requests:", success)
    fmt.Println("Failed requests:", failure)
    // fmt.Println("SuccessRate:", fmt.Sprintf("%.2f", ((success/total)*100.0)), "%")
    fmt.Println("UseTime:", fmt.Sprintf("%.4f", useTime), "s")
    fmt.Println("場景每秒處理數(shù) sps:", fmt.Sprintf("%.4f", float64(num)/useTime))
    fmt.Println("請求每秒處理數(shù) qps:", fmt.Sprintf("%.4f", float64(num*2)/useTime))

}
  • 執(zhí)行一下查看效果
go run pertestgo.go
Complete requests: 100
Failed requests: 0
UseTime: 0.1738 s
場景每秒處理數(shù) sps: 575.4601
請求每秒處理數(shù) qps: 1150.9202
  • 這里的壓測腳本主要強調(diào)場景判哥,像ab等壓測工具,很多時候都是只有單接口的并發(fā)碉考,對于復(fù)雜接口和做一些自定義斷言的時候塌计,就相對比較復(fù)雜,類似python的locust就是按照場景化寫壓測腳本的方式實現(xiàn)侯谁,這里也是運用了同樣的思想

小結(jié)

  • 希望本文對于同學(xué)們在使用golang進行壓測的時候能夠起到作用锌仅,接下來的文章還會講述幾個golang的壓測工具和其他測試工具等,敬請期待
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末墙贱,一起剝皮案震驚了整個濱河市热芹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惨撇,老刑警劉巖伊脓,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異魁衙,居然都是意外死亡报腔,警方通過查閱死者的電腦和手機株搔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纯蛾,“玉大人纤房,你說我怎么就攤上這事》撸” “怎么了炮姨?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長米丘。 經(jīng)常有香客問我剑令,道長,這世上最難降的妖魔是什么拄查? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任吁津,我火速辦了婚禮,結(jié)果婚禮上堕扶,老公的妹妹穿的比我還像新娘碍脏。我一直安慰自己,他們只是感情好稍算,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布典尾。 她就那樣靜靜地躺著,像睡著了一般糊探。 火紅的嫁衣襯著肌膚如雪钾埂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天科平,我揣著相機與錄音褥紫,去河邊找鬼。 笑死瞪慧,一個胖子當(dāng)著我的面吹牛髓考,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弃酌,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼氨菇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妓湘?” 一聲冷哼從身側(cè)響起查蓉,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榜贴,沒想到半個月后豌研,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡央拖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年彭谁,在試婚紗的時候發(fā)現(xiàn)自己被綠了拇勃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片键俱。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡凡恍,死狀恐怖霹琼,靈堂內(nèi)的尸體忽然破棺而出点额,到底是詐尸還是另有隱情咪啡,我是刑警寧澤坷随,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布房铭,位于F島的核電站,受9級特大地震影響温眉,放射性物質(zhì)發(fā)生泄漏缸匪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一类溢、第九天 我趴在偏房一處隱蔽的房頂上張望凌蔬。 院中可真熱鬧,春花似錦闯冷、人聲如沸砂心。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辩诞。三九已至,卻和暖如春纺涤,著一層夾襖步出監(jiān)牢的瞬間译暂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工撩炊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留外永,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓衰抑,卻偏偏與公主長得像象迎,于是被迫代替她去往敵國和親荧嵌。 傳聞我的和親對象是個殘疾皇子呛踊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容