【Golang面试题】Go语言实现请求频率限制

Go语言实现请求频率限制:从计数器到令牌桶的完整指南

在实际开发中,接口被恶意刷请求是常见问题。本文将深入探讨Go语言中四种主流的请求限流方案,从简单到复杂逐步深入,助你构建高可用服务。

一、基础方案:计数器法(固定窗口)

适用场景:简单业务、低并发需求


type CounterLimiter struct {mu       sync.Mutexcount    intinterval time.DurationmaxReq   intlastReset time.Time
}func NewCounterLimiter(interval time.Duration, maxReq int) *CounterLimiter {return &CounterLimiter{interval:  interval,maxReq:    maxReq,lastReset: time.Now(),}
}func (c *CounterLimiter) Allow() bool {c.mu.Lock()defer c.mu.Unlock()// 检查是否需要重置计数器if time.Since(c.lastReset) > c.interval {c.count = 0c.lastReset = time.Now()}// 检查是否超过限制if c.count >= c.maxReq {return false}c.count++return true
}// HTTP中间件示例
func RateLimitMiddleware(limiter *CounterLimiter) func(http.Handler) http.Handler {return func(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {if !limiter.Allow() {w.Header().Set("Retry-After", "60")http.Error(w, "Too Many Requests", http.StatusTooManyRequests)return}next.ServeHTTP(w, r)})}
}

优点

  • 实现简单,内存占用低
  • 无第三方依赖

缺点

  • 窗口边界突发流量问题
  • 分布式场景不适用

二、进阶方案:Redis滑动窗口

适用场景:分布式系统、精确限流

const luaScript = `
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local max = tonumber(ARGV[3])redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local current = redis.call('ZCARD', key)if current >= max thenreturn 0
endredis.call('ZADD', key, now, now)
redis.call('EXPIRE', key, math.ceil(window/1000))
return 1
`type RedisLimiter struct {client   *redis.Clientscript   *redis.ScriptmaxReq   intwindow   time.Duration
}func NewRedisLimiter(client *redis.Client, window time.Duration, maxReq int) *RedisLimiter {return &RedisLimiter{client: client,script: redis.NewScript(luaScript),maxReq: maxReq,window: window,}
}func (r *RedisLimiter) Allow(userID string) bool {ctx := context.Background()key := fmt.Sprintf("rate_limit:%s", userID)now := time.Now().UnixMilli()result, err := r.script.Run(ctx, r.client, []string{key}, now, r.window.Milliseconds(), r.maxReq).Int()return err == nil && result == 1
}

实现要点

  1. 使用Redis有序集合存储时间戳
  2. Lua脚本保证原子操作
  3. 自动清理过期请求
  4. 精确统计时间窗口内请求

优势

  • 精确的滑动窗口计数
  • 分布式系统通用
  • 自动处理数据过期

三、高级方案:令牌桶算法

适用场景:允许突发流量、精细控制

type TokenBucket struct {capacity    int           // 桶容量tokens      int           // 当前令牌数fillRate    time.Duration // 添加令牌间隔lastRefill  time.Time     // 上次添加时间mu          sync.Mutex
}func NewTokenBucket(capacity int, rate time.Duration) *TokenBucket {return &TokenBucket{capacity:   capacity,tokens:     capacity,fillRate:   rate,lastRefill: time.Now(),}
}func (b *TokenBucket) Allow() bool {b.mu.Lock()defer b.mu.Unlock()// 补充令牌now := time.Now()elapsed := now.Sub(b.lastRefill)newTokens := int(elapsed / b.fillRate)if newTokens > 0 {b.tokens += newTokensif b.tokens > b.capacity {b.tokens = b.capacity}b.lastRefill = now}// 检查令牌是否足够if b.tokens <= 0 {return false}b.tokens--return true
}

算法特点

  • 允许短时间内突发流量
  • 精确控制平均速率
  • 实现相对复杂

四、生产级方案:使用成熟中间件

推荐库

  • Tollbooth
  • Uber-go/ratelimit

Tollbooth示例


func main() {r := chi.NewRouter()// 创建限流器:每分钟1000次limiter := tollbooth.NewLimiter(1000/60.0, nil)limiter.SetIPLookups([]string{"X-Real-IP", "RemoteAddr", "X-Forwarded-For"})// 应用中间件r.Use(tollbooth_chi.LimitHandler(limiter))r.Get("/api/protected", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Protected content"))})http.ListenAndServe(":8080", r)
}

五、方案选型指南

方案实现复杂度精准度突发处理分布式支持
计数器法★☆☆☆☆★★☆☆☆
Redis滑动窗口★★★☆☆★★★★★
令牌桶算法★★★★☆★★★★☆允许突发有限
限流中间件★☆☆☆☆★★★★☆可配置

六、最佳实践

  1. 分层防御

    • 前端:按钮防重复点击
    • 网关:基础IP限流
    • 业务层:用户级精细控制
  2. 动态调整

    // 动态调整限流阈值
    func adjustLimitBasedOnSystemLoad() {load := getSystemLoad()if load > 0.8 {limiter.SetMaxRequests(500) // 高负载时降低阈值}
    }
    
  3. 熔断机制

    // 使用hystrix实现熔断
    hystrix.ConfigureCommand("my_api", hystrix.CommandConfig{Timeout:               1000,MaxConcurrentRequests: 100,ErrorPercentThreshold: 50,
    })
    
  4. 监控指标

    • 请求拒绝率
    • 系统负载
    • 限流阈值命中率
    • Redis内存/QPS

总结

在Go语言中实现请求限流需要根据实际场景选择方案:

  • 单机简单场景:计数器法
  • 分布式系统:Redis滑动窗口
  • 允许合理突发:令牌桶算法
  • 快速上线:成熟中间件

黄金法则:没有最好的限流方案,只有最适合业务场景的方案。建议从简单实现开始,随着业务增长逐步升级限流策略,最终构建包含多层防御的完整限流体系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85600.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11Labs 增长负责人分享:企业级市场将从消费级或开发者切入丨Voice Agent 学习笔记

本文摘自 Founder Park AI 产品如何做增长&#xff0c;ElevenLabs的案例很值得学习。 专注于 AI 语音生成的独角兽企业 ElevenLabs 可以说一直在高速增长。在今年 1 月完成 1.8 亿美元 C 轮融资后&#xff0c;ElevenLabs 的估值突破 30 亿&#xff0c;直指 33 亿美元。2024 年…

Linux 命令:grep

概述 在Linux系统里&#xff0c;grep是一款十分实用的命令行工具&#xff0c;它主要用于在文件或者输入流中搜索符合特定模式的文本。下面为你详细介绍它的用法。资料已经分类整理好&#xff1a;https://pan.quark.cn/s/26d73f7dd8a7 基本语法 grep [选项] 搜索模式 [文件..…

Java八股文——MySQL「架构篇」

MySQL主从复制了解吗 面试官您好&#xff0c;我了解MySQL的主从复制。它是构建高可用、高可扩展数据库架构的核心基石。 1. 主从复制的核心原理与流程 整个主从复制的过程&#xff0c;就是一场围绕 binlog&#xff08;二进制日志&#xff09; 的“接力赛”。这个过程主要可以…

ubuntu下python版本升级导致pyqt不能正常运行解决

最终解决方案 ubuntu下多python版本pyqt兼容性问题解决 python3.9 -m pip install --upgrade --force-reinstall --prefer-binary pyqt5)尝试解决方案一(失败) 系统默认python版本可以&#xff0c;其他版本不行 sudo apt install pyqt5-dev-tools尝试解决方案二(失败) 一直…

AIGC工具平台-VideoRetalking音频对口型数字人

唇形合成技术正逐渐成为AIGC内容生产领域的重要工具&#xff0c;能够实现音视频数据的高度融合。基于VideoRetalking模块的可视化界面降低了技术门槛&#xff0c;使非技术背景的用户也能便捷体验唇形驱动数字人合成的流程。 本文重点解析该模块的使用方式及开发流程&#xff0…

前端项目如何部署为https

如何为项目部署设置HTTPS 设置HTTPS是保护网站数据传输安全的重要步骤。以下是设置HTTPS的主要方法&#xff1a; 1. 获取SSL/TLS证书 免费证书选项 Let’s Encrypt&#xff1a;最流行的免费证书颁发机构Cloudflare&#xff1a;提供免费SSL和CDN服务ZeroSSL&#xff1a;另一…

nginx 配置 系统升级页面

默认80端口配置如下&#xff1a; server {listen 80; # 指定端口号server_name 192.168.2.96; # 替换为实际域名或IP# 全局重定向到升级页面&#xff08;排除自身防循环&#xff09;if ($request_uri !~* "/upgrade.html") {return 307 /upgrade.html; # 临时重定…

计算机基础(一)——设计模式

一、设计模式 设计模式&#xff08;Design Patterns&#xff09;是软件开发中反复出现问题的解决方案的通用描述。 它是经过总结、提炼的高效代码结构和设计方案&#xff0c;帮助开发者写出更灵活、可维护和可扩展的代码。 优点注意点规范代码结构&#xff0c;提高开发效率设…

Mac电脑 磁盘检测和监控工具 DriveDx

DriveDx Mac 一款不监视驱动器的内置S.M.A.R.T.状态的先进驱动器运行状况诊断和监测工具。 还分析了所有驱动器健康密切相关的指标&#xff0c; SSD或硬盘驱动器故障&#xff08;像SSD磨损 /耐久性&#xff0c;坏扇区重新分配&#xff0c;离线坏道&#xff0c;未定扇形区&…

频繁操作Json嵌套数据PostgreSQL配合JSON操作工具类+sql

文章目录 1.工具类2.依赖3.sql 本文档只是为了留档方便以后工作运维&#xff0c;或者给同事分享文档内容比较简陋命令也不是特别全&#xff0c;不适合小白观看&#xff0c;如有不懂可以私信&#xff0c;上班期间都是在得 背景&#xff1a;因为频繁操作json嵌套数据 PostgreSQL得…

京东云 centos vim有操作混乱的问题

centos云服务器 安装micro编辑器可以解决 yum install micro

限流系列之二:TDMQ CKafka 版限流方案详解及最佳实践

导语 在当今大数据和实时通信的时代&#xff0c;消息队列在分布式系统中扮演着至关重要的角色。CKafka 作为一种高性能、高可靠的消息中间件&#xff0c;被广泛应用于各种业务场景中。然而&#xff0c;随着业务的增长和数据流量的增加&#xff0c;CKafka 在生产者和消费者以极…

消息队列的基本概念

文章目录 为什么需要消息队列&#xff1f;&#x1f914;&#x1f3af; 核心价值&#x1f4cb; 使用场景 &#x1f3d7;️ 架构层面的基本概念整体架构图&#x1f4e6; 核心组件详解1. Broker&#xff08;消息代理&#xff09;2. Topic&#xff08;主题&#xff09;3. Partition…

Shell脚本中和||语法解析

https://www.cnblogs.com/liuyuelinfighting/p/16377705.html 在 Shell 脚本中&#xff0c;&& 和 || 是逻辑操作符&#xff0c;用于根据前一个命令的退出状态&#xff08;成功或失败&#xff09;决定是否执行后续命令。这种语法称为 命令链&#xff08;Command Chainin…

MySQL中的常见运算符

精选专栏链接 &#x1f517; MySQL技术笔记专栏Redis技术笔记专栏大模型搭建专栏Python学习笔记专栏深度学习算法专栏 欢迎订阅&#xff0c;点赞&#xff0b;关注&#xff0c;每日精进1%&#xff0c;共攀技术高峰 更多内容持续更新中&#xff01;希望能给大家带来帮助~ &…

高级IO技术详解:阻塞/非阻塞IO、多路复用与内存映射

高级IO技术详解&#xff1a;阻塞/非阻塞IO、多路复用与内存映射 关键词&#xff1a;阻塞IO 非阻塞IO select/poll/epoll mmap 一、阻塞IO vs 非阻塞IO 类型行为特点设置方式阻塞IO- 读空管道阻塞- 写满管道阻塞默认模式非阻塞IO- 读空文件返回 -1&#xff0c;errnoEAGAIN- 写满…

【无标题】拓扑对偶框架的严格性补完与哲学突破

拓扑对偶框架的严格性补完与哲学突破&#xff1a; 一、数学严格性补完&#xff1a;同调类守恒的解决方案 1.1 负系数问题的几何化修正 **问题本质**&#xff1a;当 $a_i$ 含负数时&#xff0c;曲率分配 $\kappa\frac{2\pi a_i}{A_{\text{max}}}$ 导致伪黎曼流形 **解决方案…

从0开始学习R语言--Day25--A/B测试 vs 多臂老虎机

通常在比较两个不同的方案对数据的影响时&#xff0c;我们会各拿50%的数据去进行对照试验&#xff0c;这样观测到的结果会最大程度地保留统计学上的特点。但实际上&#xff0c;并不是所有对比不同方案都要这样做&#xff0c;一来&#xff0c;我们需要等到两组实验都完全结束后&…

功耗高?加密弱?爱普特APT32F1023H8S6单片机 2μA待机+AES硬件加密破局

爱普特APT32F1023H8S6单片机深度解析 1. 产品定位 APT32F1023H8S6 是爱普特半导体&#xff08;APT&#xff09;推出的 32位高性能单片机&#xff0c;基于 ARM Cortex-M0内核&#xff0c;主打 高集成度、低功耗、高性价比&#xff0c;面向消费电子、工业控制和物联网领域。 2. …

【MFC】绘制自定义控件-显示图片(支持放大操作)

目录 一、CDC类&#xff08;二级缓存&#xff09;二、计算视口三、放大操作代码中初始化操作&#xff08;方便以后cv&#xff09; 一、CDC类&#xff08;二级缓存&#xff09; CDC类是设备上下文的核心类&#xff0c;它的作用是抽象化对图形输出设备&#xff08;像屏幕、打印机…