go限流、计数器固定窗口算法/计数器滑动窗口算法

go限流、计数器固定窗口算法/计数器滑动窗口算法

一、问题

问题1:后端接口只能支撑每10秒1w个请求,要怎么来保护它呢?
问题2:发短信的接口,不超过100次/时,1000次/24小时,要怎么实现?

二、计数器固定窗口算法

所谓固定窗口,就是只设置了一个时间段,给这个时间段加上一个计数器。 常见的就是统计每秒钟的请求量。 这里就是一个QPS计数器。 在这一秒种内的所有请求,只要给这个计数器递增就可以得到当前的并发量了。 用这个方法也就可以解决前面的问题1。可以直接使用系统的当前UNIX时间戳,精确到秒钟。 这个时间戳作为key,设置一个较短的过期时间,比如:10s。

package mainimport ("fmt""time"
)type SlidingWindow struct {WindowSize        intWindow            []intLastUpdateTime    time.TimeWindowDuration    time.DurationCurrentIndex      intCount             intMaxAllowedRequest int
}func NewSlidingWindow(windowSize int, windowDuration time.Duration, maxRequest int) *SlidingWindow {if windowSize <= 0 {panic("windowSize must be greater than 0")}return &SlidingWindow{WindowSize:        windowSize,Window:            make([]int, windowSize),LastUpdateTime:    time.Now(),WindowDuration:    windowDuration,CurrentIndex:      0,MaxAllowedRequest: maxRequest,}
}func (sw *SlidingWindow) IncrementCount() {now := time.Now()if now.Sub(sw.LastUpdateTime) >= sw.WindowDuration { //比较时间是否超过限定时间sw.ResetWindow()}sw.Count++sw.Window[sw.CurrentIndex] = sw.Count //窗口总量加1if sw.Count > sw.MaxAllowedRequest { //最好用窗口总量去计算。这里为了显示两种效果fmt.Println("Max allowed request exceeded")}sw.CurrentIndex = (sw.CurrentIndex + 1) % sw.WindowSize //窗口往后移动一个位置
}func (sw *SlidingWindow) ResetWindow() {for i := range sw.Window {//将窗口归零sw.Window[i] = 0}sw.Count = 0sw.LastUpdateTime = time.Now() //记录最后一次更新
}func main2() {windowSize := 5 //窗口粒度,问题1的话可以简化掉。windowDuration := time.Second * 10//十秒的访问量maxRequest := 10000//最大访问量slidingWindow := NewSlidingWindow(windowSize, windowDuration, maxRequest)for i := 0; i < 10; i++ {slidingWindow.IncrementCount()time.Sleep(time.Second)}
}

三、计数器滑动窗口算法

固定窗口就一个计数器,而滑动窗口就需要有多个计数器。 具体需要多少个计数器,要看窗口的范围和粒度来决定窗口大小。 比如:时间窗口的范围是24小时,时间窗口的粒度是1小时,那么窗口大小就是24,需要的计数器也就是24个。 我们再来回顾下前面的问题2。 如果我们用上面的固定窗口算法,需要2个计数器,一个是小时的计数器,一个是24小时,也就是天的计数器。 很明显,天的计数器会有很大的误差。 比如:昨天14点前没有任何请求,然后在14点开始,每小时都有100次请求。 到昨天的23点,刚好用完了1000次全天的额度。 但是这时候,还是每小时有100个请求, 那么从昨天的14点到今天10点,总共20小时就会有2000次请求,远远超过了24小时最多1500次的限制。 所以,这里使用滑动窗口替代固定窗口会更加合适。 如果想要限流控制点更加精准,那么就可以把窗口粒度设计的更细。 而代价就是窗口大小增加,需要的存储和计算量都会增加。 所以,这里也是需要对精准度和成本做平衡和选择,难以兼得。
在这里插入图片描述

package mainimport ("fmt""time"
)type RateLimiter struct {perHour     intperDay      inthourWindow  []intdayWindow   []intlastHourIdx intlastDayIdx  int
}func NewRateLimiter(perHour, perDay int) *RateLimiter {return &RateLimiter{perHour:     perHour,perDay:      perDay,hourWindow:  make([]int, 60),dayWindow:   make([]int, 1440),lastHourIdx: 0,lastDayIdx:  0,}
}func (rl *RateLimiter) Allow() bool {now := time.Now()hourIdx := (now.Minute() + now.Hour()*60) % 60  //记录小时的id,dayIdx := now.Hour()*60 + now.Minute()         //记录天的idif rl.hourWindow[hourIdx] >= rl.perHour || rl.dayWindow[dayIdx] >= rl.perDay {return false}rl.hourWindow[hourIdx]++rl.dayWindow[dayIdx]++rl.cleanUpOldEntries(hourIdx, dayIdx)return true
}func (rl *RateLimiter) cleanUpOldEntries(hourIdx, dayIdx int) {if hourIdx != rl.lastHourIdx {//如果小时id更新了需要窗口往右移动rl.hourWindow[hourIdx] = 1 //最新小时id的总量为1rl.hourWindow[rl.lastHourIdx] = 0 //窗口往右移动,上一个归零rl.lastHourIdx = hourIdx //记录最新id}if dayIdx != rl.lastDayIdx {rl.dayWindow[dayIdx] = 1rl.dayWindow[rl.lastDayIdx] = 0rl.lastDayIdx = dayIdx}
}func main3() {limiter := NewRateLimiter(100, 1000)for i := 0; i < 1200; i++ {if limiter.Allow() {fmt.Printf("Request %d allowed\n", i+1)} else {fmt.Printf("Request %d blocked\n", i+1)}time.Sleep(time.Second)}
}

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

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

相关文章

豆瓣影评信息爬取 (爬虫)

代码块&#xff1a; from lxml import etree import requestsheaders{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0 }url_list[] for i in range(0,5):i*20urlsf"https:…

链表带环问题——leetcode环形链表1 2

证明链表带环 链表的带环问题指的是本该指向NULL的最后一个节点指向了之前的节点&#xff0c;导致链表成环&#xff0c;找不到尾结点的情况&#xff0c;那么我们该如何证明链表带环呢&#xff1f; 我们可以类比物理中的追及问题&#xff0c;让快慢指针同时走&#xff0c;两者相…

企微知识库是如何搭建的?这篇文章来解答

知识库在企业中发挥着至关重要的作用&#xff0c;它不仅能够存储和整理重要的工作资料&#xff0c;还能提高员工的工作效率&#xff0c;加强团队之间的协作。对于使用微信企业版&#xff08;企业微信&#xff09;的企业来说&#xff0c;搭建一个专门的知识库是极有必要的。本文…

ceph osd分组

一、前言 使用分组可以更好的管理osd&#xff0c;将不同类型的磁盘&#xff0c;分到不同的组中&#xff0c;例如hhd类型的osd分配到hhd组&#xff0c;ssd类型的osd分配到ssd组&#xff0c;将io要求不高的分配到hhd组做存储&#xff0c;io要求高的分配到ssd组做存储 二、配置 查…

ubuntu23.10.1 php8.2安装

1、更新镜像源 apt update2、安装php apt install php php-fpm php-mysql其他扩展包&#xff0c;在后面加个-可以查看&#xff0c;选择安装,我这里是php8.2版本 apt-get install php8.2- 2.1php与nginx结合 PHP-FPM的配置文件位于/etc/php/{PHP版本}/fpm/pool.d/www.conf;…

字体反爬知识积累2

一、os模块中函数的应用 如何获取当前文件中所有文件的路径方法 这段代码使用 os.walk()函数来遍历指定目录 imgs 下的所有子目录和文件。具体来说&#xff0c;os.walk()函数返回一个生成器&#xff0c;可以在每次迭代中获取目录树中的一个元组&#xff0c;元组包含当前目录的…

【Linux C | 多线程编程】线程同步 | 条件变量(万字详解)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-04-15 0…

电大搜题微信公众号:重庆开放大学学子的学习利器

在当今信息化时代&#xff0c;学习已经成为每个人不可或缺的一部分。然而&#xff0c;对于重庆开放大学的学子们来说&#xff0c;由于远程教育的特殊性&#xff0c;他们面临着更大的学习挑战。幸运的是&#xff0c;他们现在可以依靠一款强大的学习利器——电大搜题微信公众号&a…

单片机基础知识 07

一. 键盘检测 键盘分为编码键盘和非编码键盘。 编码键盘 &#xff1a;键盘上闭合键的识别由专用的硬件编码器实现&#xff0c;并产生键编码号或者键值&#xff0c;如计算机键盘。 非编码键盘&#xff1a;靠软件编程来识别。 在单片机组成的各种系统中&#xff0c;用的较多的…

Darknet框架优化介绍

一、DarkNet框架简介 1.DarkNet的简介 Darknet是一个完全使用C语言编写的人工智能框架&#xff0c;可以使用CUDA的开源框架。主要应用于图像识别领域。 它具有可移植性好&#xff0c;安装间接&#xff0c;查看源码方便等优势&#xff0c;提供了OpenCV等附加选项&#xff0c;还…

(七)Pandas时序数据 学习简要笔记 #Python #CDA学习打卡

一. 时序数据简介 1&#xff09;定义 时间序列&#xff08;time series&#xff09;&#xff0c;就是由时间构成的序列&#xff0c;它指的是在一定时间内按照时间顺序测量的某个变量的取值序列&#xff0c;比如一天内的温度会随时间而发生变化&#xff0c;或者股票的价格会随…

c语言题目之求最大公约数

题目内容&#xff1a;求最大公约数 给定两个数&#xff0c;求这两个数的最大公约数 例如&#xff1a; 输入&#xff1a;20 40 输出&#xff1a;20 什么叫最大公约数&#xff1f; 方法分析&#xff1a; 提示&#xff1a;这里我们用辗转相除法&#xff1a; 例如&#xff1a;输…

腾讯云APP备案指南:一站式完成备案手续,助您顺利上线

工信部最新通知要求所有互联网信息服务提供者完成移动互联网应用程序备案手续。腾讯云为开发者提供了简单易行的备案流程&#xff0c;本文详细解答如何在腾讯云平台完成备案&#xff0c;帮助开发者快速上线自己的APP。从验证备案域名到腾讯云审核&#xff0c;一步步指导您完成备…

vue 一键更换主题颜色

这里提供简单的实现步骤&#xff0c;具体看自己怎么加到项目中 我展示的是vue2 vue3同理 在 App.vue 添加 入口处直接修改 #app { // 定义的全局修改颜色变量--themeColor:#008cff; } // 组件某些背景颜色需要跟着一起改变&#xff0c;其他也是同理 /deep/ .ant-btn-primar…

响应式修改 页面字体字号【大 中 小 】

浅浅记录下&#xff0c;工作中遇到的问题&#xff0c;修改页面文本字号。 <p class"change_fontSize">[ 字号 <a href"javascript:doZoom(18)">大</a><a href"javascript:doZoom(16)">中</a><a href"ja…

『FPGA通信接口』汇总目录

Welcome 大家好&#xff0c;欢迎来到瑾芳玉洁的博客&#xff01; &#x1f611;励志开源分享诗和代码&#xff0c;三餐却无汤&#xff0c;顿顿都被噎。 &#x1f62d;有幸结识那个值得被认真、被珍惜、被捧在手掌心的女孩&#xff0c;不出意外被敷衍、被唾弃、被埋在了垃圾堆。…

墨子web3时事周报

蚂蚁集团Web3研发进展与布局 国内Web3赛道的领军企业——蚂蚁集团&#xff0c;凭借其在前沿科技领域的深耕不辍&#xff0c;已在Web3技术研发疆域缔造了卓越战绩。特别是在引领行业革新的关键时刻&#xff0c;集团于今年四月末震撼推出了颠覆性的Web3全套解决方案&#xff0c…

在 Ubuntu 12.10 安装 wxPython

安装 wxPython 可以使用 pip 工具&#xff0c;但在 Ubuntu 12.10 上需要首先安装 wxPython 的依赖项。请注意&#xff0c;Ubuntu 12.10 已于2013年终止支持&#xff0c;建议升级到更高版本的 Ubuntu。以下是在 Ubuntu 12.10 上安装 wxPython 的一般步骤&#xff1a; 一、问题背…

考研日常记录

由于实在太无聊了 &#xff0c; 所以记录以下考研备考日常 &#xff0c; 增加一点成就感 &#xff0c; 获得一点前进动力。 2024.4.18 周四 课程情况&#xff1a; 无课 时间规划&#xff1a; 上午&#xff1a;休息 下午&#xff1a; 事项耗时进度备注写作业1h复习英语单词…

深入浅出学习切片LOD——ArcGIS server模拟缓存切片(影像快显)

一、第一次实践 原理 免切片实现影像服务的模拟切片&#xff0c;主要原理是接收前端传过来的xyz(行列层级)以及切片方案&#xff0c;计算出该请求的切片的四至经纬度信息&#xff0c;通过mapserver的exportImage接口&#xff0c;传入每个模拟切片的四至经纬度信息得到图片返回…