go-zero 是如何实现计数器限流的?
原文链接: 如何实现计数器限流?
上一篇文章 go-zero 是如何做路由管理的? 介绍了路由管理,这篇文章来说说限流,主要介绍计数器限流算法,具体的代码实现,我们还是来分析微服务框架 go-zero 的源码。
在微服务架构中,一个服务可能需要频繁地与其他服务交互,而过多的请求可能导致性能下降或系统崩溃。为了确保系统的稳定性和高可用性,限流算法应运而生。
限流算法允许在给定时间段内,对服务的请求流量进行控制和调整,以防止资源耗尽和服务过载。
计数器限流算法主要有两种实现方式,分别是:
- 固定窗口计数器
- 滑动窗口计数器
下面分别来介绍。
固定窗口计数器
算法概念如下:
- 将时间划分为多个窗口;
- 在每个窗口内每有一次请求就将计数器加一;
- 如果计数器超过了限制数量,则本窗口内所有的请求都被丢弃当时间到达下一个窗口时,计数器重置。

固定窗口计数器是最为简单的算法,但这个算法有时会让通过请求量允许为限制的两倍。

考虑如下情况:限制 1 秒内最多通过 5 个请求,在第一个窗口的最后半秒内通过了 5 个请求,第二个窗口的前半秒内又通过了 5 个请求。这样看来就是在 1 秒内通过了 10 个请求。
滑动窗口计数器
算法概念如下:
- 将时间划分为多个区间;
- 在每个区间内每有一次请求就将计数器加一维持一个时间窗口,占据多个区间;
- 每经过一个区间的时间,则抛弃最老的一个区间,并纳入最新的一个区间;
- 如果当前窗口内区间的请求计数总和超过了限制数量,则本窗口内所有的请求都被丢弃。

滑动窗口计数器是通过将窗口再细分,并且按照时间滑动,这种算法避免了固定窗口计数器带来的双倍突发请求,但时间区间的精度越高,算法所需的空间容量就越大。
go-zero 实现
go-zero 实现的是固定窗口的方式,计算一段时间内对同一个资源的访问次数,如果超过指定的 limit,则拒绝访问。当然如果在一段时间内访问不同的资源,每一个资源访问量都不超过 limit,此种情况是不会拒绝的。
而在一个分布式系统中,存在多个微服务提供服务。所以当瞬间的流量同时访问同一个资源,如何让计数器在分布式系统中正常计数?
这里要解决的一个主要问题就是计算的原子性,保证多个计算都能得到正确结果。
通过以下两个方面来解决:
- 使用 redis 的
incrby做资源访问计数 - 采用 lua script 做整个窗口计算,保证计算的原子性
接下来先看一下 lua script 的源码:
// core/limit/periodlimit.goconst periodScript = `local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 thenredis.call("expire", KEYS[1], window)
end
if current < limit thenreturn 1
elseif current == limit thenreturn 2
elsereturn 0
end`
主要就是使用 INCRBY 命令来实现,第一次请求需要给 key 加上一个过期时间,到达过期时间之后,key 过期被清楚,重新计数。
限流器初始化:
type (// PeriodOption defines the method to customize a PeriodLimit.PeriodOption func(l *PeriodLimit)// A PeriodLimit is used to limit requests during a period of time.PeriodLimit struct {period int // 窗口大小,单位 squota int // 请求上限limitStore *redis.RediskeyPrefix string // key 前缀align bool}
)// NewPeriodLimit returns a PeriodLimit with given parameters.
func NewPeriodLimit(period, quota int, limitStore *redis.Redis, keyPrefix string,opts ...PeriodOption) *PeriodLimit {limiter := &PeriodLimit{period: period,quota: quota,limitStore: limitStore,keyPrefix: keyPrefix,}for _, opt := range opts {opt(limiter)}return limiter
}
调用限流:
// key 就是需要被限制的资源标识
func (h *PeriodLimit) Take(key string) (int, error) {return h.TakeCtx(context.Background(), key)
}// TakeCtx requests a permit with context, it returns the permit state.
func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {resp, err := h.limitStore.EvalCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{strconv.Itoa(h.quota),strconv.Itoa(h.calcExpireSeconds()),})if err != nil {return Unknown, err}code, ok := resp.(int64)if !ok {return Unknown, ErrUnknownCode}switch code {case internalOverQuota: // 超过上限return OverQuota, nilcase internalAllowed: // 未超过,允许访问return Allowed, nilcase internalHitQuota: // 正好达到限流上限return HitQuota, nildefault:return Unknown, ErrUnknownCode}
}
上文已经介绍了,固定时间窗口会有临界突发问题,并不是那么严谨,下篇文章我们来介绍令牌桶限流。
以上就是本文的全部内容,如果觉得还不错的话欢迎点赞,转发和关注,感谢支持。
参考文章:
- https://juejin.cn/post/6895928148521648141
- https://juejin.cn/post/7051406419823689765
- https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673
推荐阅读:
- go-zero 是如何做路由管理的?
相关文章:
go-zero 是如何实现计数器限流的?
原文链接: 如何实现计数器限流? 上一篇文章 go-zero 是如何做路由管理的? 介绍了路由管理,这篇文章来说说限流,主要介绍计数器限流算法,具体的代码实现,我们还是来分析微服务框架 go-zero 的源…...
【考研复习】24王道数据结构课后习题代码|第3章栈与队列
文章目录 3.1 栈3.2 队列3.3 栈和队列的应用 3.1 栈 int symmetry(linklist L,int n){char s[n/2];lnode *pL->next;int i;for(i0;i<n/2;i){s[i]p->data;pp->next;}i--;if(n%21) pp->next;while(p&&s[i]p->data){i--;pp->next;}if(i-1) return 1;…...
java中excel文件下载
1、System.getProperty(user.dir) 获取的是启动项目的容器位置 2、 Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING); StandardCopyOption.REPLACE_EXISTING 来忽略文件已经存在的异常,如果存在就去覆盖掉它Sta…...
29 | 广州美食店铺数据分析
广州美食店铺数据分析 一、数据分析项目MVP加/价值主张宣言 随着经济的快速发展以及新媒体的兴起,美食攻略、美食探店等一系列东西进入大众的眼球,而人们也会在各大平台中查找美食推荐,因此本项目做的美食店铺数据分析也是带有可行性的。首先通过对广东省的各市美食店铺数量…...
fastApi基础
1、fastApi简介 官方文档:https://fastapi.tiangolo.com/ 源码: https://github.com/tiangolo/fastapi 2、环境准备 安装python 安装pycharm 安装fastAPI 安装 uvicorn 查看已经安装的第三方库:pip list 查看pip 配置信息:pip co…...
Mysql整理二 - 常见查询语句面试题(附原表)
表结构,创建原表的代码在最后 -- cid课程id; tid老师id; sid学生id; select * from t_mysql_course; select * from t_mysql_score; select * from t_mysql_student; select * from t_mysql_teacher; 1. 查询" 01 “课程比” 02 "课程成绩高的学生的信息…...
Python - 读取pdf、word、excel、ppt、csv、txt文件提取所有文本
前言 本文对使用python读取pdf、word、excel、ppt、csv、txt等常用文件,并提取所有文本的方法进行分享和使用总结。 可以读取不同文件的库和方法当然不止下面分享的这些,本文的代码主要目标都是:方便提取文件中所有文本的实现方式。 这些库的…...
Codeforces Round 892 (Div. 2) C. Another Permutation Problem 纯数学方法 思维题
Codeforces Round 892 (Div. 2) C. Another Permutation Problem 源码: #include <iostream> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <stack> #include &l…...
持续输出:自媒体持续输出文字内容、视音频创作(视频课程、书籍章节)
以下是自媒体持续输出文字内容、视音频创作的最佳方法: 灵感来源:寻找灵感来源是自媒体创作的重要一环。可以从日常生活、网络热点、行业动态等方面寻找创作灵感。 确定主题:在确定主题的时候,需要根据读者和观众的需求ÿ…...
篇十七:备忘录模式:恢复对象状态
篇十七:"备忘录模式:恢复对象状态" 开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 另外有2本不错的关于设计模式的资料&…...
初识mysql数据库之图形化界面
目录 一、好用的数据库图形化界面软件 1. Navicat 2. SQLyog 3. MYSQL Workbench 二、MYSQL Workbench基本使用 1. 安装 2. 远端连接 3. 执行sql语句 一、好用的数据库图形化界面软件 在以前的文章中,一共介绍了两种使用数据库的方式,分别为在l…...
APP外包开发的H5开发框架
跨平台移动应用开发框架允许开发者使用一套代码在多个操作系统上构建应用程序,从而节省时间和资源。以下是一些常见的跨平台移动应用开发框架以及它们的特点,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司࿰…...
高性能跨平台网络通信框架 HP-Socket v5.9.3
项目主页 : http://www.oschina.net/p/hp-socket开发文档 : https://www.docin.com/p-4478351216.html下载地址 : https://github.com/ldcsaa/HP-SocketQQ Group: 44636872, 663903943 v5.9.3 更新 一、主要更新 问题修复:通过 POST/PUT 等带有请求内容的 HTTP 方…...
Vue3.2+TS在v-for的时候,循环处理时间,将其变成xx-xx-xx xx:xx:xx格式,最后教给大家自己封装一个时间hooks,直接复用
Vue3.2TS在v-for的时候,循环处理时间,将其变成xx-xx-xx xx:xx:xx格式 最后教给大家自己封装一个时间hooks,直接复用 1.没有封装,直接使用 <template><div><ul><li v-for"item,index in arr" :k…...
05 mysql innodb page
前言 最近看到了 何登成 大佬的 "深入MySQL源码 -- Step By Step" 的 pdf 呵呵 似乎是找到了一些 方向 之前对于 mysql 方面的东西, 更多的仅仅是简单的使用[业务中的各种增删改查], 以及一些面试题的背诵 这里会参照 MySQL Internals Manual 来大致的看一下 i…...
记录一次electron打包提示文件找不到的解决方法
没有配置files选项 files的作用是配置打包到应用程序的构建资源 就是说如果你想使用项目那个目录下的文件 就得通过files配置一下不然就会报错 json文件或者yml文件会报的错 格式是这样的 "files": ["dist-electron", "dist"],electron打包配…...
《大型网站技术架构》第二篇 架构-高可用
高可用在公司中的重要性 对公司而言,可用性关系网站的生死存亡。对个人而言,可用性关系到自己的绩效升迁。 工程师对架构做了许多优化、对代码做了很多重构,对性能、扩展性、伸缩性做了很多改善,但别人未必能直观地感受到&#…...
VS Code 使用cnpm下载包失败
一、 问题如下: 网上找到的解决方法是要在powershell中执行: Set-ExecutionPolicy RemoteSigned进行更改策略。 首先我们解释下这个Set-ExecutionPolicy RemoteSigned,Set-ExecutionPolicy 是一个 PowerShell 命令,用于控制脚本…...
【图像分类】CNN + Transformer 结合系列.4
介绍两篇利用Transformer做图像分类的论文:CoAtNet(NeurIPS2021),ConvMixer(ICLR2022)。CoAtNet结合CNN和Transformer的优点进行改进,ConvMixer则patch的角度来说明划分patch有助于分类。 CoAtN…...
分享一下利用Vue表单处理实现复杂表单布局
在开发Web应用程序中,表单是非常常见的一种元素。而在某些情况下,我们需要实现一些更为复杂的表单布局,以满足业务需求。使用Vue.js作为前端框架,我们可以很方便地处理复杂表单布局,并且实现数据的双向绑定。 下面来将…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
