最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Go語言實現一個壓測工具

 更新時間:2025年01月28日 10:10:55   作者:海綿寶寶de派小星  
這篇文章主要為大家詳細介紹了基于Go語言實現一個簡單的壓測工具,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

本篇主要是基于Go來實現一個壓測的工具,關于壓測的內容可以參考其他的文章,這里默認了解壓測的基本概念

基于Golang實現的壓測工具

整體架構

整體系統(tǒng)架構比較簡單

通用數據處理模塊

Http請求響應數據處理

本項目支持http協議、websocket協議、grpc協議、Remote Authentication Dial-In User Service協議,因此需要構造出一個通用的http請求和響應的結構體,進行一個通用的封裝:

// Request 請求數據
type Request struct {
	URL       string            // URL
	Form      string            // http/webSocket/tcp
	Method    string            // 方法 GET/POST/PUT
	Headers   map[string]string // Headers
	Body      string            // body
	Verify    string            // 驗證的方法
	Timeout   time.Duration     // 請求超時時間
	Debug     bool              // 是否開啟Debug模式
	MaxCon    int               // 每個連接的請求數
	HTTP2     bool              // 是否使用http2.0
	Keepalive bool              // 是否開啟長連接
	Code      int               // 驗證的狀態(tài)碼
	Redirect  bool              // 是否重定向
}

這當中值得注意的是驗證的方法,這里是因為在進行壓測中,要判斷返回的響應是否是正確的響應,因此要進行判斷響應是否正確,所以要進行相應的函數的注冊,因此對于一個請求,是有必要找到一個對應的請求方法來判斷這個請求正確,之后進行記錄

這個model的核心功能,就是生成一個http請求的結構體,來幫助進行存儲

// NewRequest 生成請求結構體
// url 壓測的url
// verify 驗證方法 在server/verify中 http 支持:statusCode、json webSocket支持:json
// timeout 請求超時時間
// debug 是否開啟debug
// path curl文件路徑 http接口壓測,自定義參數設置
func NewRequest(url string, verify string, code int, timeout time.Duration, debug bool, path string,
	reqHeaders []string, reqBody string, maxCon int, http2, keepalive, redirect bool) (request *Request, err error) {
	var (
		method  = "GET"
		headers = make(map[string]string)
		body    string
	)
	if path != "" {
		var curl *CURL
		curl, err = ParseTheFile(path)
		if err != nil {
			return nil, err
		}
		if url == "" {
			url = curl.GetURL()
		}
		method = curl.GetMethod()
		headers = curl.GetHeaders()
		body = curl.GetBody()
	} else {
		if reqBody != "" {
			method = "POST"
			body = reqBody
		}
		for _, v := range reqHeaders {
			getHeaderValue(v, headers)
		}
		if _, ok := headers["Content-Type"]; !ok {
			headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
		}
	}
	var form string
	form, url = getForm(url)
	if form == "" {
		err = fmt.Errorf("url:%s 不合法,必須是完整http、webSocket連接", url)
		return
	}
	var ok bool
	switch form {
	case FormTypeHTTP:
		// verify
		if verify == "" {
			verify = "statusCode"
		}
		key := fmt.Sprintf("%s.%s", form, verify)
		_, ok = verifyMapHTTP[key]
		if !ok {
			err = errors.New("驗證器不存在:" + key)
			return
		}
	case FormTypeWebSocket:
		// verify
		if verify == "" {
			verify = "json"
		}
		key := fmt.Sprintf("%s.%s", form, verify)
		_, ok = verifyMapWebSocket[key]
		if !ok {
			err = errors.New("驗證器不存在:" + key)
			return
		}
	}
	if timeout == 0 {
		timeout = 30 * time.Second
	}
	request = &Request{
		URL:       url,
		Form:      form,
		Method:    strings.ToUpper(method),
		Headers:   headers,
		Body:      body,
		Verify:    verify,
		Timeout:   timeout,
		Debug:     debug,
		MaxCon:    maxCon,
		HTTP2:     http2,
		Keepalive: keepalive,
		Code:      code,
		Redirect:  redirect,
	}
	return
}

之后是對于對應的響應的封裝,結構體定義為:

// RequestResults 請求結果
type RequestResults struct {
	ID            string // 消息ID
	ChanID        uint64 // 消息ID
	Time          uint64 // 請求時間 納秒
	IsSucceed     bool   // 是否請求成功
	ErrCode       int    // 錯誤碼
	ReceivedBytes int64
}

Curl參數解析處理

對于這個模塊,本項目中實現的邏輯是根據一個指定的Curl的文件,對于文件中的Curl進行解析,即可解析出對應的Http請求的參數,具體代碼鏈接如下

https://gitee.com/zhaobohan/stress-testing/blob/master/model/curl_model.go

客戶端模塊

Http客戶端處理

在該模塊中主要是對于Http客戶端進行處理,對于普通請求和Http2.0請求進行了特化處理,支持根據客戶端ID來獲取到指定的客戶端,建立映射關系

具體的核心成員為:

var (
    mutex sync.RWMutex
    // clients 客戶端
    // key 客戶端id - value 客戶端
    clients = make(map[uint64]*http.Client)
)

再具體的,對于客戶端的封裝,主要操作是,對于Client的構造

// createLangHTTPClient 初始化長連接客戶端參數
// 創(chuàng)建了一個配置了長連接的 HTTP 客戶端傳輸對象
func createLangHTTPClient(request *model.Request) *http.Client {
    tr := &http.Transport{
        // 使用 net.Dialer 來建立 TCP 連接
        // Timeout 設置為 30 秒,表示如果連接在 30 秒內沒有建立成功,則超時
        // KeepAlive 設置為 30 秒,表示連接建立后,如果 30 秒內沒有數據傳輸,則發(fā)送一個 keep-alive 探測包以保持連接
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
        MaxIdleConns:        0,                // 最大連接數,默認0無窮大
        MaxIdleConnsPerHost: request.MaxCon,   // 對每個host的最大連接數量(MaxIdleConnsPerHost<=MaxIdleConns)
        IdleConnTimeout:     90 * time.Second, // 多長時間未使用自動關閉連接
        // InsecureSkipVerify 設置為 true,表示不驗證服務器的 SSL 證書
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    if request.HTTP2 {
        // 使用真實證書 驗證證書 模擬真實請求
        tr = &http.Transport{
            DialContext: (&net.Dialer{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
            }).DialContext,
            MaxIdleConns:        0,                // 最大連接數,默認0無窮大
            MaxIdleConnsPerHost: request.MaxCon,   // 對每個host的最大連接數量(MaxIdleConnsPerHost<=MaxIdleConns)
            IdleConnTimeout:     90 * time.Second, // 多長時間未使用自動關閉連接
            // 配置 TLS 客戶端設置,InsecureSkipVerify 設置為 false,表示驗證服務器的 SSL 證書
            TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
        }
        // 將 tr 配置為支持 HTTP/2 協議
        _ = http2.ConfigureTransport(tr)
    }

    client := &http.Client{
        Transport: tr,
    }

    // 禁止 HTTP 客戶端自動重定向,而是讓客戶端在遇到重定向時停止并返回最后一個響應
    if !request.Redirect {
        client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        }
    }

???????    return client
}

https://gitee.com/zhaobohan/stress-testing/blob/master/server/client/http_client.go

Grpc客戶端處理

對于Grpc的構造來說,主要實現的功能是建立連接等,這些操作是較為簡單的操作,因此這里不具體講述

// GrpcSocket grpc
type GrpcSocket struct {
    conn    *grpc.ClientConn
    address string
}

conn和Address主要都是借助于兩個類的成員函數來完成,解析地址和建立連接

其余模塊可在代碼中查看,這里不進行過多講述

https://gitee.com/zhaobohan/stress-testing/blob/master/server/client/grpc_client.go

Websocket客戶端處理

// WebSocket webSocket
type WebSocket struct {
    conn       *websocket.Conn
    URLLink    string
    URL        *url.URL
    IsSsl      bool
    HTTPHeader map[string]string
}

其余模塊可在代碼中查看,這里不進行過多講述

https://gitee.com/zhaobohan/stress-testing/blob/master/server/client/websocket_client.go

連接處理模塊

Grpc

對于Grpc的測試,這里模擬了一個rpc調用,執(zhí)行了一個Hello World的函數,之后填充相應的數據作為請求的響應,最后將結果返回

// grpcRequest 請求
func grpcRequest(chanID uint64, ch chan<- *model.RequestResults, i uint64, request *model.Request,
    ws *client.GrpcSocket) {
    var (
        startTime = time.Now()
        isSucceed = false
        errCode   = model.HTTPOk
    )
    // 獲取連接
    conn := ws.GetConn()
    if conn == nil {
        errCode = model.RequestErr
    } else {
        c := pb.NewApiServerClient(conn)
        var (
            ctx = context.Background()
            req = &pb.Request{
                UserName: request.Body,
            }
        )
        // 發(fā)送請求,獲得響應
        rsp, err := c.HelloWorld(ctx, req)
        if err != nil {
            errCode = model.RequestErr
        } else {
            // 200 為成功
            if rsp.Code != 200 {
                errCode = model.RequestErr
            } else {
                isSucceed = true
            }
        }
    }
    requestTime := uint64(helper.DiffNano(startTime))
    requestResults := &model.RequestResults{
        Time:      requestTime,
        IsSucceed: isSucceed,
        ErrCode:   errCode,
    }
    requestResults.SetID(chanID, i)
    ch <- requestResults
}

Http

對于Http的測試,效果也基本類似,原理也基本相同

// HTTP 請求
func HTTP(ctx context.Context, chanID uint64, ch chan<- *model.RequestResults, totalNumber uint64, wg *sync.WaitGroup,
	request *model.Request) {
	defer func() {
		wg.Done()
	}()
	for i := uint64(0); i < totalNumber; i++ {
		if ctx.Err() != nil {
			break
		}

		list := getRequestList(request)
		isSucceed, errCode, requestTime, contentLength := sendList(chanID, list)
		requestResults := &model.RequestResults{
			Time:          requestTime,
			IsSucceed:     isSucceed,
			ErrCode:       errCode,
			ReceivedBytes: contentLength,
		}
		requestResults.SetID(chanID, i)
		ch <- requestResults
	}

	return
}

統(tǒng)計數據模塊

下面來看計算統(tǒng)計數據模塊

統(tǒng)計原理

這里需要統(tǒng)計的數據有以下:

耗時、并發(fā)數、成功數、失敗數、qps、最長耗時、最短耗時、平均耗時、下載字節(jié)、字節(jié)每秒、狀態(tài)碼

其中這里需要注意的,計算的數據有QPS,其他基本都可以經過簡單的計算得出

那QPS該如何進行計算呢?這里來這樣進行計算:

QPS = 服務器每秒鐘處理請求數量 (req/sec 請求數/秒)

定義:單個協程耗時T, 所有協程壓測總時間 sumT,協程數 n

如果:只有一個協程,假設接口耗時為 2毫秒,每個協程請求了10次接口,每個協程耗總耗時210=20毫秒,sumT=20

QPS = 10/201000=500

如果:只有十個協程,假設接口耗時為 2毫秒,每個協程請求了10次接口,每個協程耗總耗時210=20毫秒,sumT=2010=200

QPS = 100/(200/10)*1000=5000

上訴兩個示例現實中總耗時都是20毫秒,示例二 請求了100次接口,QPS應該為 示例一 的10倍,所以示例二的實際總QPS為5000

除以協程數的意義是,sumT是所有協程耗時總和

實現過程

這個模塊主要是定時進行一個統(tǒng)計壓測的結論并進行打印的工作,依賴的函數是

// calculateData 計算數據
func calculateData(concurrent, processingTime, requestTime, maxTime, minTime, successNum, failureNum uint64,
	chanIDLen int, errCode *sync.Map, receivedBytes int64) {
	if processingTime == 0 {
		processingTime = 1
	}
	var (
		qps              float64
		averageTime      float64
		maxTimeFloat     float64
		minTimeFloat     float64
		requestTimeFloat float64
	)
	// 平均 QPS 成功數*總協程數/總耗時 (每秒)
	if processingTime != 0 {
		qps = float64(successNum*concurrent) * (1e9 / float64(processingTime))
	}
	// 平均時長 總耗時/總請求數/并發(fā)數 納秒=>毫秒
	if successNum != 0 && concurrent != 0 {
		averageTime = float64(processingTime) / float64(successNum*1e6)
	}
	// 納秒=>毫秒
	maxTimeFloat = float64(maxTime) / 1e6
	minTimeFloat = float64(minTime) / 1e6
	requestTimeFloat = float64(requestTime) / 1e9
	// 打印的時長都為毫秒
	table(successNum, failureNum, errCode, qps, averageTime, maxTimeFloat, minTimeFloat, requestTimeFloat, chanIDLen,
		receivedBytes)
}

以上就是基于Go語言實現一個壓測工具的詳細內容,更多關于Go壓測工具的資料請關注腳本之家其它相關文章!

相關文章

  • golang 如何通過反射創(chuàng)建新對象

    golang 如何通過反射創(chuàng)建新對象

    這篇文章主要介紹了golang 通過反射創(chuàng)建新對象的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言利用compress/gzip庫實現高效壓縮解決方案詳解

    Go語言利用compress/gzip庫實現高效壓縮解決方案詳解

    在數據存儲與傳輸領域,Gzip作為一種廣泛應用的無損壓縮格式,以其高效的壓縮比和跨平臺兼容性成為行業(yè)標準,下面我們就來看看Go語言如何利用該庫實現高效的數據壓縮與解壓縮吧
    2025-07-07
  • golang的基礎語法和常用開發(fā)工具詳解

    golang的基礎語法和常用開發(fā)工具詳解

    這篇文章主要介紹了golang的基礎語法和常用開發(fā)工具,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • go使用mapstructure解析json的實現實例

    go使用mapstructure解析json的實現實例

    本文主要介紹了go使用mapstructure解析json的實現實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-11-11
  • 使用Go語言開發(fā)任務待辦清單Web應用

    使用Go語言開發(fā)任務待辦清單Web應用

    在學習 Go 的過程中,一個非常適合入門的 Web 項目就是 TodoList(任務待辦清單),本文將為大家詳細介紹一下具體實現方法,希望對大家有所幫助
    2025-09-09
  • Golang Gin局部和全局中間件使用詳解

    Golang Gin局部和全局中間件使用詳解

    中間件是放在客戶端和服務端的中間,當你的客戶端對某個接口發(fā)起一個請求,但是在到達接口2之前,這里是有一層中間件的處理。本文詳細介紹了Golang Gin局部、全局中間件使用方法,感興趣的同學可以閱讀本文
    2023-04-04
  • GoLand安裝與環(huán)境配置的完整步驟

    GoLand安裝與環(huán)境配置的完整步驟

    作為一個go語言程序員,覺得自己有義務為go新手開一條更簡單便捷的上手之路,下面這篇文章主要給大家介紹了關于GoLand安裝與環(huán)境配置的完整步驟,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • Go語言Swagger實現為項目生成 API 文檔

    Go語言Swagger實現為項目生成 API 文檔

    Swagger 是一個基于 OpenAPI 規(guī)范設計的工具,用于為 RESTful API 生成交互式文檔,下面小編就來介紹一下如何在 Go 項目中集成 Swagger,特別是結合 Gin 框架生成 API 文檔
    2025-03-03
  • Go?Gin框架優(yōu)雅重啟和停止實現方法示例

    Go?Gin框架優(yōu)雅重啟和停止實現方法示例

    Web應用程序中,有時需要重啟或停止服務器,無論是因為更新代碼還是進行例行維護,這時需要保證應用程序的可用性和數據的一致性,就需要優(yōu)雅地關閉和重啟應用程序,即不丟失正在處理的請求和不拒絕新的請求,本文將詳解如何在Go語言中使用Gin這個框架實現優(yōu)雅的重啟停止
    2024-01-01
  • 使用Go語言實現Yaml編碼和解碼的方法詳解

    使用Go語言實現Yaml編碼和解碼的方法詳解

    在這篇文章中,我們將介紹如何使用Go語言編寫代碼來實現Yaml編碼和解碼,文中有詳細的代碼示例供大家參考,對大家的學習和工作有一定的幫助,需要的朋友可以參考下
    2023-11-11

最新評論

乡城县| 高尔夫| 宜良县| 昂仁县| 奉化市| 若羌县| 邢台县| 名山县| 新昌县| 焦作市| 周宁县| 兴山县| 湖北省| 大余县| 乐清市| 怀来县| 会理县| 蒙山县| 嘉善县| 云林县| 旬邑县| 南部县| 尚志市| 华亭县| 莒南县| 馆陶县| 南昌县| 祥云县| 桦川县| 定安县| 肃宁县| 贵溪市| 城口县| 武清区| 珲春市| 璧山县| 贞丰县| 买车| 崇义县| 福海县| 平潭县|