一个对网络库进行压测统计qps的小程序

该程序实现了一个对TCP网络库进行压力测试的工具,通过生成并发送数据包,统计接收到的响应时间,计算QPS(每秒查询率)以及平均延迟。程序包括发送工作、接收工作和处理工作三个主要部分,用于生成数据包、发送数据、接收数据和检查性能指标。同时,程序还具备错误检查和性能统计功能,如最大延迟和平均延迟的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个对网络库进行压测统计qps的小程序

参考:https://gist.github.com/Tsiannian/137b722f1b5dcebea0830a9e12720de0

package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"net"
	"os"
	"time"
)

func timeStamp() uint64 {
	return uint64(time.Now().UnixNano())
}

func encode(index uint64, stamp uint64) []byte {
	sendData := make([]byte, 128)
	binary.LittleEndian.PutUint64(sendData[0:64], index)//发送序列号
	binary.LittleEndian.PutUint64(sendData[64:128], stamp)//发送时间
	return sendData
}

func decode(buff []byte) (uint64, uint64) {
	index := binary.LittleEndian.Uint64(buff[0:64])//解析发送序列号
	stamp := binary.LittleEndian.Uint64(buff[64:128])//发送时间
	return index, stamp
}

func handleWork(recv chan []byte, send chan []byte) {
	fmt.Println("begin to handle")
	defer fmt.Println("end to handle")

	countChan := make(chan uint64, 10240)

	go func() {
		var index uint64
		for {
			index++
			now := timeStamp()
			data := encode(index, now)//生成data
			send <- data//放到发送通道
			countChan <- index//index放到count通道
		}
	}()

	for {
		inIndex := <-countChan//发送index
		tcppacket := <-recv//收包的通道
		now := timeStamp()
		outindex, stamp := decode(tcppacket)//解析返回的数据index,时间
		check(inIndex, outindex, now-stamp)//检查发送index到返回index,时间差
	}
}

var couter, latency, begin int64
var max_latency uint64

func check(inIndex, outindex, delay uint64) {//检查发送index到返回index,时间差
	if inIndex != outindex {//不相等,中间有出错,未返回
		fmt.Println("index error", inIndex, outindex)
		os.Exit(-1)
	}
	timeNow := time.Now().Unix()

	couter++
	latency += int64(delay)//总时间差

	if delay > max_latency {
		max_latency = delay
	}

	if begin < timeNow-1 {//1秒
		fmt.Println("ops", couter, "all latency", latency, "max", max_latency, "avg lantency", latency/couter)
		begin = timeNow
		couter = 0
		latency = 0
		max_latency = 0
	}
}

func sendWorker(data chan []byte, nc net.Conn) {
	fmt.Println("begin to send")
	defer fmt.Println("end to send")
	for {
		temp := <-data
		remain := len(data)
		for i := 0; i < remain; i++ {
			left := <-data
			temp = append(temp, left...)
		}
		size, err := nc.Write(temp)
		if size != len(temp) || err != nil {
			fmt.Println("send work error", size, err)
			return
		}
	}
}

func recvWorker(data chan []byte, nc net.Conn) {
	fmt.Println("begin to recv")
	defer fmt.Println("end to recv")

	reader := bufio.NewReaderSize(nc, 8192)
	buff := make([]byte, 4096)
	send := []byte{}
	for {
		size, err := reader.Read(buff)
		if err != nil {
			fmt.Println("recv work err", size, err)
			return
		}
		send = append(send, buff[0:size]...)
		for len(send) >= 128 {
			data <- send[0:128]
			send = send[128:]
		}
	}
}

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:3050")
	if err != nil {
		fmt.Println(err)
		return
	}

	sendChan := make(chan []byte, 10240)
	recvChan := make(chan []byte, 10240)

	go recvWorker(recvChan, conn)
	go sendWorker(sendChan, conn)

	go handleWork(recvChan, sendChan)

	q := make(chan int)
	<-q
	fmt.Print("client exist")
}

 

### 自定义 QPS 的概念及其应用场景 #### 什么是自定义 QPS? 自定义 QPS(Queries Per Second)是指根据特定业务需求或技术架构设计,人为设定的服务每秒可接受的最大请求数。这种设置通常用于控制系统的负载能力,防止因突发流量而导致服务不可用的情况发生。通过调整 QPS 值,可以优化资源利用率和服务性能。 在实际应用中,QPS 的大小取决于多个因素,括但不限于硬件配置、软件框架效率以及后端处理逻辑复杂度等。例如,在固定并发数的情况下,如果 TP99(第 99 百分位延迟)较低,则意味着大部分请求能够在较短时间内完成处理,从而支持更高的 QPS[^1]。 #### 应用场景分析 以下是几个典型的自定义 QPS 使用场景: 1. **微服务架构中的限流保护** 微服务体系下,各模块间相互调用频繁,一旦某个下游服务出现问题可能引发连锁反应甚至整个系统瘫痪。因此可以通过引入线程池等方式实现对上游请求量的有效管理,确保核心功能正常运行的同时减少不必要的失败尝试次数。 2. **基于 Prometheus 和 Grafana 的实时监控与告警机制构建** 对于现代云原生环境而言,利用开源工具链如 Micrometer 结合 Prometheus 存储数据并通过可视化平台 Grafana 展现出来变得尤为重要。这些仪表盘能够提供关于服务器健康状况的关键信息,比如 CPU 利用率、磁盘 I/O 性能指标等等;同时也涵盖了更高级别的统计维度——像 HTTP 接口的成功率分布曲线图或者平均响应耗时柱状图之类的内容都可以被轻松绘制出来供运维人员参考决策之需[^2]。 3. **试脚本定制化开发** 当执行大规模分布式任务之前往往需要先编写好相应的客户端模拟程序来发起连续不断的访问操作直至达到预期目标为止。此时便涉及到如何灵活指定每次迭代过程中所携带的数据格式参数选项等问题了。以 Lua 编写的轻量化网络基准量工具 `wrk`为例,它允许开发者通过对全局变量赋值的方式快速切换不同的提交方法类型(GET/POST),同时附加额外载荷内容作为实体主体部分传递给远程主机解析验证合法性后再返回结果状态码等一系列动作序列组合而成的整体流程描述如下所示: ```lua -- 设置默认行为为 POST 请求,并附带 JSON 数据体及相应头部声明 wrk.method = "POST" wrk.body = '{"key":"value"}' wrk.headers["Content-Type"] = "application/json" ``` 上述代码片段展示了怎样简单几行语句即可满足基本需求的前提下进一步扩展其功能性边界范围至无限可能性领域之中去探索未知世界奥秘所在之处[^3]! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值