go多線程壓測監控

實現了

  • go多協程壓力測試
  • 實現了Monitor,異步統計qps、時延、cpu(client端)等指標,周期printStat。只需要把單條執行func傳給Monitor即可
  • 命令行傳參
  • ctrl+c之后正常退出
  • (mock cpu 占用)

代碼見 https://gitee.com/bbjg001/golearning/tree/master/others/stress_monitor

執行

go run *.go -action w -routine 5 -duration 30s

效果

在這里插入圖片描述

更多的

可以把收集到的指標轉給/metrics接口,可以實現外部手機指標,提供給prometheus收集,接口grafana實現可視化監控展示

util.go

package mainimport ("context""fmt""math/rand""os""sync/atomic""time""github.com/rcrowley/go-metrics""github.com/shirou/gopsutil/v3/process"
)type SCMonitor struct {registry       metrics.Registryinterval       time.DurationstopChan       chan struct{}qpsCounter     metrics.CounterlatencyTimer   metrics.TimertotalRequests  uint64failedRequests uint64lastCompute    time.Time
}func NewSCMonitor(interval time.Duration) *SCMonitor {registry := metrics.NewRegistry()return &SCMonitor{registry:     registry,interval:     interval,stopChan:     make(chan struct{}),qpsCounter:   metrics.NewCounter(),latencyTimer: metrics.NewTimer(),}
}func (m *SCMonitor) Start() {// 注冊指標m.registry.Register("requests.qps", m.qpsCounter)m.registry.Register("requests.latency", m.latencyTimer)// CPU監控cpuGauge := metrics.NewGauge()m.registry.Register("system.cpu", cpuGauge)m.lastCompute = time.Now()go func() {p, err := process.NewProcess(int32(os.Getpid()))if err != nil {fmt.Printf("Failed to init process monitor: %v\n", err)return}ticker := time.NewTicker(m.interval)defer ticker.Stop()// fmt.Printf("time\tqps\tcpu\tlatency999\tlatency99\tlatency9\tlatencyMean\n")fmt.Printf("%-12s%-30s%-10s%-16s%-16s%-16s%-16s\n","time", "qps", "cpu", "latency999", "latency99", "latency9", "latencyMean")for {select {case <-m.stopChan:returncase <-ticker.C:// 更新CPU指標if percent, err := p.Percent(0); err == nil {cpuGauge.Update(int64(percent * 100))}// 打印周期報告m.PrintReport()}}}()
}func (m *SCMonitor) Monitor(ctx context.Context, work func() (duration time.Duration, succeed bool)) {for {select {case <-ctx.Done():returndefault:duration, succeed := work()m.RecordRequest(duration, succeed)}}
}func (m *SCMonitor) RecordRequest(latency time.Duration, succeed bool) {atomic.AddUint64(&m.totalRequests, 1)if !succeed {atomic.AddUint64(&m.failedRequests, 1)}m.qpsCounter.Inc(1)m.latencyTimer.Update(latency)
}func (m *SCMonitor) PrintReport() {now := time.Now().Format("15:04:05")// fmt.Printf("\n=== Metrics Report @ %s ===\n", now)fmt.Printf("%-12s", now)// QPS計算if qps := m.registry.Get("requests.qps"); qps != nil {counter := qps.(metrics.Counter)interval := time.Since(m.lastCompute).Milliseconds()rate := float64(counter.Count()*1000) / float64(interval)qpsStr := fmt.Sprintf("%.1f (Total: %d)", rate, atomic.LoadUint64(&m.totalRequests))fmt.Printf("%-30s", qpsStr)counter.Clear()}m.lastCompute = time.Now()// CPU使用率if cpu := m.registry.Get("system.cpu"); cpu != nil {cpuStr := fmt.Sprintf("%.1f%%\t", float64(cpu.(metrics.Gauge).Value())/100)fmt.Printf("%-10s", cpuStr)}// 時延統計if timer := m.registry.Get("requests.latency"); timer != nil {t := timer.(metrics.Timer)fmt.Printf("%-16.2f%-16.2f%-16.2f%-16.2f\n", t.Percentile(0.999)/1000000, t.Percentile(0.99)/1000000,t.Percentile(0.9)/1000000, t.Mean()/1000000)}
}func (m *SCMonitor) Stop() {close(m.stopChan)m.PrintReport() // 最終報告
}// 模擬cpu負載
func mockCpuLoad(loadPercentage int, durationSecond int) {workTime := time.Duration(loadPercentage) * time.MillisecondsleepTime := time.Duration(100-loadPercentage) * time.Millisecondctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(durationSecond))defer cancel()for {select {case <-ctx.Done():returndefault:start := time.Now()// 在工作時間內進行計算for time.Since(start) < workTime {// 執行一些計算密集型操作_ = rand.Intn(1000) * rand.Intn(1000)}time.Sleep(sleepTime)}}
}

main.go

package mainimport ("context""flag""fmt""math/rand""os""os/signal""syscall""time"
)var (testCfg = TConfig{}values  = make([]string, 1000)baseVal string
)type TConfig struct {routine  intaction   stringduration time.Duration
}func (c TConfig) String() string {return "=============測試參數\n" +fmt.Sprintf("routine: %d\n", c.routine) +fmt.Sprintf("action: %s\n", c.action) +fmt.Sprintf("duration: %v\n", c.duration)
}func init() {parseFlags()
}func parseFlags() {flag.IntVar(&testCfg.routine, "routine", 1, "線程數")flag.StringVar(&testCfg.action, "action", "r", "action, w|r")flag.DurationVar(&testCfg.duration, "duration", time.Minute, "測試時長")flag.Parse()
}func doWrite(uid int64) (time.Duration, bool) {// 此處uit只做傳參示例d := int(rand.Float64() * 10000)startTime := time.Now()time.Sleep(time.Microsecond * time.Duration(d))succeed := rand.Float64() < 0.002return time.Since(startTime), succeed
}func doRead(uid int64) (time.Duration, bool) {d := int(rand.Float64() * 5000)startTime := time.Now()time.Sleep(time.Microsecond * time.Duration(d))succeed := rand.Float64() < 0.0001return time.Since(startTime), succeed
}func main() {fmt.Println(testCfg.String())fmt.Println("可Ctrl+C退出")go mockCpuLoad(15, 12) // 模擬cpu負載start := time.Now()ctx, cancel := context.WithTimeout(context.Background(), testCfg.duration)defer cancel()signalCh := make(chan os.Signal, 1)signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)monitor := NewSCMonitor(3 * time.Second)monitor.Start()defer monitor.Stop()for i := 0; i < testCfg.routine; i++ {if testCfg.action == "w" {go monitor.Monitor(ctx, func() (duration time.Duration, succeed bool) { // 只需要傳入一個控制測試停止的Context和M一個單條條執行的func即可,其他的的交給Monitorreturn doWrite(int64(i))})} else if testCfg.action == "r" {go monitor.Monitor(ctx, func() (duration time.Duration, succeed bool) {return doRead(int64(i))})} else {panic(fmt.Sprintf("unsupport param action: %s", testCfg.action))}}select {case <-ctx.Done():fmt.Println("測試完成, 正在退出 ...")breakcase <-signalCh: // 收到退出信號,正常處理退出testCfg.duration = time.Since(start)fmt.Println("收到終止信號, 正在退出 ...")cancel()break}fmt.Println(testCfg.String())
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906853.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906853.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906853.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安卓無障礙腳本開發全教程

文章目錄 第一部分&#xff1a;無障礙服務基礎1.1 無障礙服務概述核心功能&#xff1a; 1.2 基本原理與架構1.3 開發環境配置所需工具&#xff1a;關鍵依賴&#xff1a; 第二部分&#xff1a;創建基礎無障礙服務2.1 服務聲明配置2.2 服務配置文件關鍵屬性說明&#xff1a; 2.3 …

閑時處理技術---CAD C#二次開發

在CAD C#二次開發中&#xff0c;使用閑時處理技術可以提高程序的響應性能和資源利用率。以下是一般的實現步驟&#xff1a; 1. 了解CAD的事件機制 CAD提供了一些事件&#xff0c;如 Idle 事件&#xff0c;當CAD應用程序處于空閑狀態時會觸發該事件。你可以訂閱這個事件來執行閑…

Git研究

以下命令在CentOS系統下執行 創建Git倉庫 git init git-example 監控.git目錄的變化情況&#xff1a; watch -n .5 tree .git 寫入文件內容&#xff0c;并把文件添加到Stage暫存區 echo 1 > t.txtgit add 1.txt 觀察結果如下&#xff1a;objects下多出了一個d00491fd…

野火魯班貓(arrch64架構debian)從零實現用MobileFaceNet算法進行實時人臉識別(四)安裝RKNN Toolkit Lite2

RKNN Toolkit Lite2 是瑞芯微專為RK系列芯片開發的NPU加速推理API。若不使用該工具&#xff0c;計算任務將僅依賴CPU處理&#xff0c;無法充分發揮芯片高達6TOPS的NPU算力優勢。 按照官方文檔先拉一下官方代碼庫&#xff0c;然后通過whl文件安裝&#xff0c;因為我是python3.1…

Vue3集成Element Plus完整指南:從安裝到主題定制下-實現后臺管理系統框架搭建

本文將詳細介紹如何使用 Vue 3 構建一個綜合管理系統&#xff0c;包括路由配置、頁面布局以及常用組件集成。 一、路由配置 首先&#xff0c;我們來看系統的路由配置&#xff0c;這是整個應用的基礎架構&#xff1a; import {createRouter, createWebHistory} from vue-rout…

【Oracle】創建公共數據連接

需求描述 兩個oracle數據庫&#xff0c;想從B數據庫創建視圖腳本訪問A數據庫相關表的數據&#xff0c;該怎么訪問呢&#xff1f; 解決方法 在Oracle數據庫中&#xff0c;創建公共數據庫鏈接&#xff08;Public Database Link&#xff09;可以允許數據庫中的任何用戶訪問遠程…

時序數據庫IoTDB的分片與負載均衡策略深入解析

一、引言 隨著數據庫服務的業務負載增加&#xff0c;擴展服務資源成為必然需求。擴展方式主要分為縱向擴展和橫向擴展。縱向擴展通過增加單臺機器的能力&#xff08;如內存、硬盤、處理器&#xff09;來實現&#xff0c;但受限于單臺機器的硬件能力。而橫向擴展則通過增加更多…

計算機網絡期末復習資料

我用夸克網盤分享了「計算機網絡」&#xff0c; 鏈接&#xff1a;https://pan.quark.cn/s/8aac2f0b840e 計算機網絡試題庫 1單項選擇題 1.1以下屬于物理層的設備是 ( A) A. 中繼器 B.以太網交換機 C. 橋 D. 網關 1.2在以太網中&#xff0c;是根據 (B) 地址來區分…

【IEEE 2025】低光增強KANT(使用KAN代替MLP)----論文詳解與代碼解析

【IEEE 2025】本文參考論文Enhancing Low-Light Images with Kolmogorov–Arnold Networks in Transformer Attention 雖然不是頂刊&#xff0c;但是有值得學習的地方 論文地址&#xff1a;arxiv 源碼地址&#xff1a;github 文章目錄 Part1 --- 論文精讀Part2 --- 代碼詳解形狀…

naivechain:簡易區塊鏈實現

naivechain&#xff1a;簡易區塊鏈實現 naivechain A naive and simple implementation of blockchains. 項目地址: https://gitcode.com/gh_mirrors/nai/naivechain 項目介紹 naivechain 是一個簡單且易于理解的區塊鏈實現項目。它使用 Go 語言編寫&#xff0c;以極簡…

Zabbix開源監控的全面詳解!

一、zabbix的基本概述 zabbix&#xff0c;這款企業級監控軟件&#xff0c;能全方位監控各類網絡參數&#xff0c;確保企業服務架構的安全穩定運行。它提供了靈活多樣的告警機制&#xff0c;幫助運維人員迅速發現并解決問題。此外&#xff0c;zabbix還具備分布式監控功能&#…

軟考軟件評測師——軟件工程之開發模型與方法

目錄 一、核心概念 二、主流模型詳解 &#xff08;一&#xff09;經典瀑布模型 &#xff08;二&#xff09;螺旋演進模型 &#xff08;三&#xff09;增量交付模型 &#xff08;四&#xff09;原型驗證模型 &#xff08;五&#xff09;敏捷開發實踐 三、模型選擇指南 四…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | Blurry Loading (毛玻璃加載)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— Blurry Loading 組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ ? 組件目標 實現一個加載進度條&#xff0c;隨著加載進度的…

WPF性能優化之延遲加載(解決頁面卡頓問題)

文章目錄 前言一. 基礎知識回顧二. 問題分析三. 解決方案1. 新建一個名為DeferredContentHost的控件。2. 在DeferredContentHost控件中定義一個名為Content的object類型的依賴屬性&#xff0c;用于承載要加載的子控件。3. 在DeferredContentHost控件中定義一個名為Skeleton的ob…

VLM-MPC:自動駕駛中模型預測控制器增強視覺-語言模型

《VLM-MPC: Model Predictive Controller Augmented Vision Language Model for Autonomous Driving》2024年8月發表&#xff0c;來自威斯康星大學的論文。 受視覺語言模型&#xff08;VLM&#xff09;的緊急推理能力及其提高自動駕駛系統可理解性的潛力的啟發&#xff0c;本文…

推薦系統里真的存在“反饋循環”嗎?

推薦系統里真的存在“反饋循環”嗎&#xff1f; 許多人說&#xff0c;推薦算法不過是把用戶早已存在的興趣挖掘出來&#xff0c;你本來就愛聽流行歌、買潮牌玩具&#xff0c;系統只是在合適的時間把它們端到你面前&#xff0c;再怎么迭代&#xff0c;算法也改變不了人的天性&a…

代碼混淆技術的還原案例

案例一 eval 混淆 特征 &#xff1a; 反常的 eval 連接了一堆數據 練習網站 https://scrape.center/ spa9 這個案例 基本的還原方法 但是這個代碼還是非常的模糊不好看 優化一下 &#xff1a; 當然還有更快捷的方法 &#xff1a; 好用的 js混淆還原的 web &#xf…

鴻蒙Flutter實戰:22-混合開發詳解-2-Har包模式引入

以 Har 包的方式加載到 HarmonyOS 工程 創建工作 創建一個根目錄 mkdir ohos_flutter_module_demo這個目錄用于存放 flutter 項目和鴻蒙項目。 創建 Flutter 模塊 首先創建一個 Flutter 模塊&#xff0c;我們選擇與 ohos_app 項目同級目錄 flutter create --templatemodu…

Go核心特性與并發編程

Go核心特性與并發編程 1. 結構體與方法&#xff08;擴展&#xff09; 高級結構體特性 // 嵌套結構體與匿名字段 type Employee struct {Person // 匿名嵌入Department stringsalary float64 // 私有字段 }// 構造函數模式 func NewPerson(name string, age int) *Pe…

Java 函數式接口(Functional Interface)

一、理論說明 1. 函數式接口的定義 Java 函數式接口是一種特殊的接口&#xff0c;它只包含一個抽象方法&#xff08;Single Abstract Method, SAM&#xff09;&#xff0c;但可以包含多個默認方法或靜態方法。函數式接口是 Java 8 引入 Lambda 表達式的基礎&#xff0c;通過函…