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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;通过函…