基于 Go 语言设计的一款高精度 QPS 统计系统,适用于高并发场景的实时请求频率统计,支持百万级 QPS 场景下的精确统计。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
mantis
V2EX    Go 编程语言

基于 Go 语言设计的一款高精度 QPS 统计系统,适用于高并发场景的实时请求频率统计,支持百万级 QPS 场景下的精确统计。

  •  
  •   mantis 278 天前 2616 次点击
    这是一个创建于 278 天前的主题,其中的信息可能已经有所发展或是发生改变。

    高精度 QPS 统计系统,适用于高并发场景的实时请求频率统计。基于 Go 语言实现的高性能计数器,支持百万级 QPS 场景下的精确统计。

    Github

    核心特性

    • 双引擎架构( Lock-Free/Sharded ),支持百万级 QPS 实时统计
    • 智能分片策略(基于 CPU 核心数的动态分片,10 秒间隔 QPS 监控)
    • 时间窗口滑动算法( 1s 窗口,100ms 精度)
    • 自适应负载均衡( QPS 变化率超 30%自动调整)
    • 增强的优雅关闭机制(请求完整性保障,超时控制,强制关闭)
    • 令牌桶限流保护(可动态调整速率,支持突发流量,自适应限流)
    • Prometheus 监控集成( QPS 、内存、CPU 、请求延迟等指标)
    • 健康检查端点支持(/healthz )
    • 资源使用监控指标(内存阈值自适应,自动分片调整)
    • 高性能设计(原子操作、细粒度锁、请求计数与统计)
    • HTTP 服务器双模式支持(标准 net/http 和高性能 fasthttp )

    架构设计

    +-------------------+ +-----------------------+ | HTTP Server | | Adaptive Sharding | | (net/http,fasthttp)| +-----------------------+ +-------------------+ ↓ ↓ +---------------+ +------------------------+ | Lock-Free 引擎 | | Sharded 计数器集群 | | (CAS 原子操作) | | (动态分片) | +---------------+ +------------------------+ +------------------------------------------------+ | 动态分片管理器 | | 10 秒间隔监控 QPS 变化率(±30%触发调整) | | 分片数自动伸缩(最小 CPU 核心数,最大 CPU 核心数*8 )| | 内存使用监控(自动调整分片以优化内存使用) | +------------------------------------------------+ +------------------+ +------------------+ +------------------+ | 限流保护层 | | 监控指标层 | | 优雅关闭机制 | | (令牌桶+自适应) | | (Prometheus 集成) | | (请求完整性保障) | +------------------+ +------------------+ +------------------+ 

    技术实现

    Lock-Free 引擎

    基于原子操作( CAS )实现的无锁计数器,适用于中等流量场景:

    • 使用atomic.Int64实现无锁计数,避免高并发下的锁竞争
    • 时间窗口滑动算法,保证统计精度和实时性
    • 自动清理过期数据,避免内存泄漏

    Sharded 计数器

    分片设计的高性能计数器,适用于超高并发场景:

    • 基于 CPU 核心数的自动分片,默认为runtime.NumCPU() * 4
    • 细粒度锁设计,每个时间槽独立锁,最大化并行性
    • 哈希算法确保请求均匀分布到各分片

    自适应分片管理

    • 实时监控 QPS 变化率,当变化超过±30%时触发分片调整
    • 增长时增加 50%分片数,下降时减少 30%分片数
    • 分片数范围控制在 CPU 核心数到 CPU 核心数*8 之间,避免资源浪费
    • 内存使用监控,当接近阈值时自动调整分片数量
    • 综合考量 QPS 变化率(60%)和内存使用情况(40%)进行智能调整

    令牌桶限流器

    • 基于令牌桶算法实现高效限流,支持突发流量处理
    • 动态调整限流速率,适应系统负载变化
    • 自适应限流模式,根据系统资源使用情况自动调整限流参数
    • 精确统计被拒绝请求,提供限流指标监控

    监控指标系统

    • 集成 Prometheus ,提供丰富的系统运行指标
    • 实时监控 QPS 、内存使用、CPU 使用率、Goroutine 数量
    • 请求延迟分布统计,支持 P99 等性能分析
    • 可配置的指标收集间隔,优化性能与精度平衡

    增强的优雅关闭机制

    • 请求完整性保障,确保进行中的请求能够完成处理
    • 多级超时控制,包括软超时和硬超时机制
    • 实时状态报告,提供关闭过程的可观测性
    • 强制关闭保护,防止系统长时间无法退出

    配置说明

    server: port: 8080 read_timeout: 5s write_timeout: 10s server_type: fasthttp # HTTP 服务器类型( standard/fasthttp ) counter: type: "lockfree" # 计数器类型( lockfree/sharded ) window_size: 1s # 统计时间窗口 slot_num: 10 # 窗口分片数量 precision: 100ms # 统计精度 limiter: enabled: true # 是否启用限流 rate: 1000000 # 每秒允许的请求数 burst: 10000 # 突发请求容量 adaptive: true # 是否启用自适应限流 metrics: enabled: true # 是否启用指标收集 interval: 5s # 指标收集间隔 endpoint: "/metrics" # 指标暴露端点 shutdown: timeout: 30s # 优雅关闭超时时间 max_wait: 60s # 最大等待时间 logger: level: info format: json file_path: "/var/log/qps-counter/app.log" max_size: 100 max_backups: 3 max_age: 7 

    性能指标

    服务器类型 并发量 平均延迟 P99 延迟 QPS
    standard 10k 1.8ms 4.5ms 850k
    fasthttp 10k 1.2ms 3.5ms 950k

    高负载场景测试结果: | 服务器类型 | 并发量 | 平均延迟 | P99 延迟 | QPS | |------------|--------|---------|--------|--------| | standard | 100k | 2.5ms | 6.5ms | 1.05M | | fasthttp | 100k | 1.2ms | 3.5ms | 1.23M |

    快速开始

    安装

    go get github.com/mant7s/qps-counter 

    基本使用

    package main import ( "github.com/mant7s/qps-counter/counter" "log" ) func main() { // 创建计数器实例 cfg := counter.DefaultConfig() counter, err := counter.NewCounter(cfg) if err != nil { log.Fatal(err) } // 增加计数 counter.Increment() // 获取当前 QPS qps := counter.GetQPS() log.Printf("Current QPS: %d", qps) } 

    监控指标

    系统通过/metrics端点暴露 Prometheus 格式的监控指标:

    • qps_counter_requests_total: 总请求计数
    • qps_counter_current_qps: 当前 QPS 值
    • qps_counter_memory_usage_bytes: 内存使用量
    • qps_counter_cpu_usage_percent: CPU 使用率
    • qps_counter_goroutines: Goroutine 数量
    • qps_counter_request_duration_seconds: 请求处理时间分布

    开发指南

    环境要求

    • Go 1.18+
    • Make

    本地开发

    1. 克隆仓库
    git clone https://github.com/mant7s/qps-counter.git cd qps-counter 
    1. 安装依赖
    go mod download 
    1. 运行测试
    make test 
    1. 构建项目
    make build 
    6 条回复    2025-03-17 12:44:36 +08:00
    faceair
        1
    faceair  
       278 天前 via iPhone
    没看懂,直接用 prometheus sdk 有啥问题
    lesisal
        2
    lesismal  
       278 天前   1
    atomic.AddUint64 1ns 级别的,1s 百万也没什么压力的,shards slots 的计算量比简单 atomic 浪费的 cpu 多多了,我觉得是多余的设计。
    如果需要保存一段时间内数据、就用 len=时长/interval ,[len]uint64 ,起个协程每个 interval 更新下 index=(index+1)%numSlots ,qps 的地方 atomic.AddUint64(&slots[index], 1)就可以了,没必要搞那么多有锁无锁的炫技,脱离实际的炫技会带来负优化
    zzhirong
        3
    zzhirong  
       278 天前   5
    项目有很浓的 AI 味,我花了半小时看了下,有几个疑问:
    自适应分区究竟有什么用?我只看到分区调整,好像并未真正应用;
    自适应限流似乎并未实现,只见一个 adaptive 字段,却看不到任何实际使用;
    这个项目的意义何在?仅仅是统计 QPS 吗?(既然都用 Prometheus ,为何不直接上报,而要绕一个弯路)或者是作为中心限流器?(我的理解这个一般在流量入口(负载均衡或网关)处就做掉了吧) 。
    令牌桶已有 golang.org/x/time/rate 这样稳定的实现了,没必要再造轮子了吧。
    总结:一个项目把所有后端爆款关键字都用上了(“百万”,“精确”,“高性能”,“优雅”,“自适应”,“智能”...),我的感觉就是一个( AI )炼手的项目。
    唉,我的时间。
    daimaosix
        4
    daimaosix  
       277 天前
    @zzhirong 哈哈哈哈哈哈
    daimaosix
        5
    daimaosix  
       277 天前
    @zzhirong 大佬,没写过后,注意到你描述的前两段,Go 编译器不会检测无用的代码吗?我写 Rust 是会检测并警告
    zzhirong
        6
    zzhirong  
       277 天前   1
    @daimaosix 不是大佬。关于你的问题,如何界定“无用”?如果定义了一个本地变量但没有使用,这种情况很容易界定,因为该变量仅在其所在范围内生效;但对于其他函数、变量或类型,编译器很难判断它们是否“无用”,可能你只是想编写一个供外部调用的库,而并非在自己的程序中使用它们,这也是合理的。如果你确实想知道哪些代码没有被使用,直接查看代码覆盖情况即可(`gool tool cover`)。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1023 人在线   最高记录 6679       Select Lnguage
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 18:28 PVG 02:28 LAX 10:28 JFK 13:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86