文章目錄
- 一、代碼說明
- 1.1 主要功能
- 1.2 代碼示例
- 1.3 代碼解釋
- 1.4 執行流程
- 二、結果分析
- 三、參數解釋
- 3.1 numWorkers 和 numRequests 說明
- 3.2 使用場景
- 四、注意事項
最近搭建了一個TRON節點,同事不相信我的自建節點比官方更靠譜,咱們給他使用golang寫一個壓測腳本,測試一下。
本文檔詳細介紹了一個基于 Go 的并發 HTTP 請求工具,幫助你對 Tron 節點進行壓力測試。本文檔將從代碼簡介、環境配置、編譯運行以及結果分析等方面進行詳細說明。
一、代碼說明
該工具通過并發多個 HTTP 請求,對 Tron 節點的處理能力進行壓力測試。每個請求都會記錄響應時間,并將結果輸出。
1.1 主要功能
- 發送并發 HTTP 請求到指定 Tron 節點。
- 記錄每個請求的響應時間和狀態。
- 支持配置請求超時時間、并發 worker 數量和每個 worker 發送的請求數量。
1.2 代碼示例
package mainimport ("bytes""fmt""io/ioutil""net/http""sync""time"
)// worker 函數執行 HTTP 請求并記錄響應時間
func worker(id int, wg *sync.WaitGroup, url string, payload string, results chan<- string, numRequests int, timeout time.Duration) {defer wg.Done()client := &http.Client{Timeout: timeout,}for i := 0; i < numRequests; i++ {req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(payload)))if err != nil {results <- fmt.Sprintf("Worker %d: error creating request: %v", id, err)return}req.Header.Set("Content-Type", "application/json")start := time.Now()resp, err := client.Do(req)duration := time.Since(start)if err != nil {results <- fmt.Sprintf("Worker %d: error making request: %v", id, err)return}defer resp.Body.Close()if resp.StatusCode != http.StatusOK {body, _ := ioutil.ReadAll(resp.Body)results <- fmt.Sprintf("Worker %d: received non-OK status: %s, response body: %s", id, resp.Status, string(body))return}body, err := ioutil.ReadAll(resp.Body)if err != nil {results <- fmt.Sprintf("Worker %d: error reading response body: %v", id, err)return}results <- fmt.Sprintf("Worker %d: success in %v, response: %s", id, duration, string(body))}
}func main() {// Tron 節點的 URLurl := "http://節點地址:8090/wallet/getnowblock"// 替換為你的實際賬戶地址accountAddress := "your-account-address"payload := fmt.Sprintf(`{"address":"%s"}`, accountAddress)// 并發請求的 worker 數量numWorkers := 200// 每個 worker 發送的請求數量numRequests := 1// HTTP 請求的超時時間timeout := 3 * time.Secondvar wg sync.WaitGroupresults := make(chan string, numWorkers*numRequests)// 啟動 workerfor i := 0; i < numWorkers; i++ {wg.Add(1)go worker(i, &wg, url, payload, results, numRequests, timeout)}// 等待所有 worker 完成wg.Wait()close(results)// 輸出結果for result := range results {fmt.Println(result)}
}
1.3 代碼解釋
package mainimport ("bytes""fmt""io/ioutil""net/http""sync""time"
)
導入包
- bytes:用于處理字節緩沖區,構造 HTTP 請求的 body。
- fmt:用于格式化輸入輸出。
- ioutil:提供 I/O 實用函數,讀取 HTTP 響應的 body。
- net/http:用于發送 HTTP 請求。
- sync:提供同步原語,例如 WaitGroup。
- time:用于處理時間和定時器。
func worker(id int, wg *sync.WaitGroup, url string, payload string, results chan<- string, numRequests int, timeout time.Duration) {defer wg.Done()
- 參數:
- id:worker 的 ID,用于標識日志中的具體 worker。
- wg:WaitGroup,用于等待所有 worker 完成。
- url:HTTP 請求的目標 URL。
- payload:請求體數據。
- results:用于存儲結果的通道。
- numRequests:每個 worker 發送的請求數量。
- timeout:每個 HTTP 請求的超時時間。
- defer wg.Done():確保函數結束時調用 wg.Done(),通知 WaitGroup 當前 worker 已完成。
client := &http.Client{Timeout: timeout,}
創建 HTTP 客戶端
- 創建一個帶有超時設置的 HTTP 客戶端。
for i := 0; i < numRequests; i++ {req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(payload)))if err != nil {results <- fmt.Sprintf("Worker %d:error creating request: %v", id, err)return}req.Header.Set("Content-Type","application/json")
發送 HTTP 請求
- 循環發送 numRequests 個請求。
- 使用 http.NewRequest 創建新的 POST 請求。
- 設置請求頭 Content-Type 為 application/json。
start := time.Now()
resp, err := client.Do(req)
duration := time.Since(start)
記錄請求時間
- 記錄請求開始時間。
- 發送請求并接收響應。
- 計算請求的總持續時間。
if err != nil {results <- fmt.Sprintf("Worker %d: error making request: %v", id, err)return}defer resp.Body.Close()
處理請求錯誤和響應
- 如果請求錯誤,記錄錯誤信息并返回。
- 確保在函數結束時關閉響應體。
if resp.StatusCode != http.StatusOK {body, _ := ioutil.ReadAll(resp.Body)results <- fmt.Sprintf("Worker %d: received non-OK status: %s, response body: %s", id, resp.Status, string(body))return}
檢查響應狀態碼
- 檢查響應狀態碼是否為 200 (OK)。
- 如果不是 200,讀取響應體并記錄錯誤信息。
body, err := ioutil.ReadAll(resp.Body)if err != nil {results <- fmt.Sprintf("Worker %d: error reading response body: %v", id, err)return}
讀取響應體
- 讀取響應體,如果讀取錯誤,記錄錯誤信息。
results <- fmt.Sprintf("Worker %d: success in %v, response: %s", id, duration, string(body))}
}
記錄成功請求
- 將成功請求的結果、持續時間和響應體發送到結果通道。
func main() {// Tron 節點的 URLurl := "http://tron節點地址:8090/wallet/getnowblock"// 替換為你的實際賬戶地址accountAddress := "your-account-address"payload := fmt.Sprintf(`{"address":"%s"}`, accountAddress)
main 函數
- 定義 Tron 節點的 URL 和請求體數據。
// 并發請求的 worker 數量
numWorkers := 200
// 每個 worker 發送的請求數量
numRequests := 1
// HTTP 請求的超時時間
timeout := 3 * time.Second
配置參數
- numWorkers:并發 worker 的數量。
- numRequests:每個 worker 發送的請求數量。
- timeout:HTTP 請求的超時時間。
var wg sync.WaitGroup
results := make(chan string,numWorkers*numRequests)
初始化 WaitGroup 和結果通道
- 創建一個 WaitGroup,用于同步所有 worker。
- 創建一個結果通道,用于存儲每個請求的結果。
// 啟動 workerfor i := 0; i < numWorkers; i++ {wg.Add(1)go worker(i, &wg, url, payload, results, numRequests, timeout)}
啟動并發 worker
- 啟動 numWorkers 個并發 worker,每個 worker 在獨立的 goroutine 中運行。
// 等待所有 worker 完成wg.Wait()close(results)
等待所有 worker 完成
- 使用 wg.Wait() 等待所有 worker 完成。
- 關閉結果通道,表示所有結果已經寫入完成。
// 輸出結果for result := range results {fmt.Println(result)}
}
- 輸出結果
迭代結果通道,打印每個請求的結果。
1.4 執行流程
- 初始化和配置:導入必要的包并定義 worker 函數和 main 函數中的參數。
- 創建并啟動 worker:在 main 函數中,根據配置啟動并發的 worker。
- 發送請求:每個 worker 根據 numRequests 發送指定數量的請求。
- 處理響應:每個請求記錄開始時間、發送請求、接收響應并記錄結束時間。處理請求的錯誤和響應狀態碼,并讀取響應體。
- 記錄結果:將每個請求的結果、持續時間和響應體發送到結果通道。
- 等待完成:等待所有 worker 完成,并關閉結果通道。
- 輸出結果:迭代結果通道,打印每個請求的結果。
二、結果分析
程序的輸出包括每個請求的響應時間和響應內容。以下是輸出示例:
Worker 0: success in 150ms, response: {...}
Worker 1: success in 145ms, response: {...}
Worker 2: received non-OK status: 500 Internal Server Error, response body: {...}
...
Average request duration: 147ms
輸出說明
- Worker X: success in Yms, response: {…}:表示 worker X 成功發送了請求,響應時間為 Y 毫秒,響應內容為 {…}。
- Worker X: received non-OK status: …:表示 worker X 收到了非 200 狀態碼的響應,響應內容顯示在 {…} 中。
- Average request duration: …:表示所有請求的平均響應時間。
三、參數解釋
3.1 numWorkers 和 numRequests 說明
numWorkers
- 定義:numWorkers 代表并發執行的 worker 數量。
- 作用:控制并發請求的數量。每個 worker 是一個獨立的 goroutine,它會發送 HTTP 請求到指定的 URL。
- 作用機制:當程序運行時,會啟動 numWorkers 個并發的 goroutine,每個 goroutine 都會執行 worker 函數。
numRequests
- 定義:numRequests 代表每個 worker 需要發送的請求數量。
- 作用:控制每個 worker 發送的請求總數。一個 worker 會在一個循環中發送多個請求,直到達到numRequests 的數量。
- 作用機制:每個 worker 啟動后,會在一個循環中發送 numRequests 個 HTTP 請求。
兩個參數的關系
- 并發度:numWorkers 決定了程序的并發度。更多的 workers 意味著更多的并發請求。
- 總請求數:總的請求數由 numWorkers 和 numRequests 的乘積決定。總請求數 = numWorkers × numRequests。
關系示例
numWorkers = 200
numRequests = 10
那么:
- 將啟動 200 個并發的 worker。
- 每個 worker 發送 10 個請求。
- 總請求數為 200 × 10 = 2000 個請求。
3.2 使用場景
高并發測試
- 增大 numWorkers 可以增加并發請求的數量,用于測試服務器在高并發情況下的表現。
- 適用于需要模擬大量用戶同時訪問服務器的場景。
高負載測試
- 增大 numRequests 可以增加每個 worker 發送的請求總數,用于測試服務器在高負載情況下的表現。
- 適用于需要模擬少量用戶頻繁訪問服務器的場景。
可以調整 numWorkers 和 numRequests 來模擬不同的壓力場景。
- 如需模擬高并發但請求數少的情況,可以增加 numWorkers 并減少 numRequests。
- 如需模擬低并發但請求數多的情況,可以減少 numWorkers 并增加 numRequests。
通過合理配置 numWorkers 和 numRequests,可以有效地測試服務器在不同負載和并發條件下的性能表現。
四、注意事項
-
請確保 Tron節點可以處理大量并發請求,以避免節點過載。
-
調整超時時間以適應你的網絡環境,避免因網絡延遲導致的不必要錯誤。