Golang编写自定义IP限流中间件

news2024/10/7 8:20:17

目录

  • 基于令牌桶的限流算法
  • 实现高并发限流(使用golang官方限流器)
    • Go代码
    • 测试记录
      • ab -t 1 -c 1 http://127.0.0.1:8080/api/resource
      • 结果预测:1秒内最多生成10个令牌,而总共有20个串行的请求,结果应该是1个成功(在50ms结束),1个失败(后50ms内还未有新的令牌生成),1个成功,1个失败。。。
      • 结果输出(符合预期)
  • 升级:根据每个IP地址进行限流
    • Go代码
    • 测试记录
      • ab -t 1 -c 1 http://127.0.0.1:8080/api/resource
      • 结果预测:1秒内最多生成2个令牌,桶容量为5 代表在1/2秒内的最大并发量是5,总共有20个串行的请求,结果应该是先成功5个(桶容量全使用成功), 之后剩余成功的是1个,其余全部失败
      • 结果输出(符合预期)

基于令牌桶的限流算法

  • r:每秒钟向桶内放入 r 个令牌,即每隔 1/r秒放一个令牌
  • b:桶的最大容量是 b,桶满后试图再放入的令牌会被丢弃掉
  • 当有人请求 n 个令牌时,如果桶中的令牌数小于n,则请求放阻塞或直接放弃,否则顺利从桶中取走 n 个令牌
    • 当 b > 1 时,任意 1/r 秒内最多可以取走 b 个令牌
      • 限制很短的一个瞬间的一个最高的并发量,b=最高的并发量,r=最短的时间段
    • 当 b = 1 时,每秒钟最多可被取走 r 个令牌
      • 限制每秒钟的最高的QPS:b=1,r=最高的QPS
      • 限制每分钟的最高请求量:把每分钟的请求量/60=转换成1秒钟,赋给 r 就可以了
      • 限制每5分钟、每10分钟,同理

实现高并发限流(使用golang官方限流器)

Go代码

源码地址: GitHub-golang版本

middleware/rateLimiterMiddleware.go

package middleware

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)

var Limiter *rate.Limiter

// 定义一个中间件函数来进行限流
func RateLimiterMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !Limiter.AllowN(time.Now(), 1) {
			c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
			// 设置休眠和业务时长一样,为了更好从日志出看出规则
			time.Sleep(50 * time.Millisecond)
			c.Abort()
			return
		}

		c.Next()
	}
}

main.go

func main() {
	r := gin.Default()
	
	// 创建一个限流器,每秒允许最多10个请求
	middleware.Limiter = rate.NewLimiter(rate.Limit(10), 1)

	// 使用限流中间件
	r.Use(middleware.RateLimiterMiddleware())

	r.GET("/api/resource", func(c *gin.Context) {
		time.Sleep(50 * time.Millisecond)
		c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
	})

	r.Run(":8080")
}

测试记录

ab -t 1 -c 1 http://127.0.0.1:8080/api/resource

使用ab压力测试,并发量为1的(相当于串行),在1秒内不断发出请求(算下来,每个请求50ms,总共能发出20个请求)

结果预测:1秒内最多生成10个令牌,而总共有20个串行的请求,结果应该是1个成功(在50ms结束),1个失败(后50ms内还未有新的令牌生成),1个成功,1个失败。。。

结果输出(符合预期)

在这里插入图片描述
在这里插入图片描述

升级:根据每个IP地址进行限流

Go代码

源码地址: GitHub-golang版本

middleware/ipRateLimiterMiddleware.go

package middleware

import (
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)

var IPLimiter *IPRateLimiter

func NewIPRateLimiter() *IPRateLimiter {
	return &IPRateLimiter{
		limiter: make(map[string]*rate.Limiter),
	}
}

type IPRateLimiter struct {
	mu      sync.Mutex
	limiter map[string]*rate.Limiter
}

func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
	i.mu.Lock()
	defer i.mu.Unlock()

	limiter, exists := i.limiter[ip]
	if !exists {
		limiter = rate.NewLimiter(2, 5) // 每秒2个请求,桶容量为5
		i.limiter[ip] = limiter
	}

	return limiter
}

// 定义一个中间件函数来进行限流
func IPRateLimiterMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		ip := c.ClientIP()

		limiter := IPLimiter.GetLimiter(ip)

		if !limiter.Allow() {
			c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
			// 设置休眠和业务时长一样,为了更好从日志出看出规则
			time.Sleep(50 * time.Millisecond)
			c.Abort()
			return
		}

		c.Next()
	}
}

main.go

func main() {
	r := gin.Default()

	// 创建IP限流器
	middleware.IPLimiter = middleware.NewIPRateLimiter()

	// 使用限流中间件
	r.Use(middleware.IPRateLimiterMiddleware())

	r.GET("/api/resource", func(c *gin.Context) {
		time.Sleep(50 * time.Millisecond)
		c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
	})

	r.Run(":8080")
}

测试记录

ab -t 1 -c 1 http://127.0.0.1:8080/api/resource

使用ab压力测试,并发量为1的(相当于串行),在1秒内不断发出请求(算下来,每个请求50ms,总共能发出20个请求)

结果预测:1秒内最多生成2个令牌,桶容量为5 代表在1/2秒内的最大并发量是5,总共有20个串行的请求,结果应该是先成功5个(桶容量全使用成功), 之后剩余成功的是1个,其余全部失败

  1. 当程序启动时,限流器初始化,桶是空的,没有令牌。
  2. 在每秒的前两次令牌生成中,每次生成2个令牌,并放入桶中。
  3. 在第3秒,生成的2个令牌中只有1个能够被放入桶中,因为桶已经满了。
  4. 当使用ab发出请求时,前5个请求依次拿到了令牌并成功,每个请求耗时50ms。此时总耗时为250ms。
  5. 第6个请求在300ms,第7个请求在350ms,第8个请求在400ms,第9个请求在450ms,第10个请求在500ms。
  6. 因为限流器的速率是每秒2个请求,也就是每500ms生成一个令牌。 第500ms时新的令牌生成,所以第6-10请求期间,是没有令牌的,所以都请求失败,而11个请求时有新令牌生成,所以能成功。
  7. 之后的请求以此类推,需要等待新令牌生成。

结果输出(符合预期)

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Hadoop源码阅读(二):DataNode启动

说明: 1.Hadoop版本:3.1.3 2.阅读工具:IDEA 2023.1.2 3.源码获取:Index of /dist/hadoop/core/hadoop-3.1.3 (apache.org) 4.工程导入:下载源码之后得到 hadoop-3.1.3-src.tar.gz 压缩包,在当前目录打开Pow…

二叉树(2——二叉树链式结构的实现)

二叉树的遍历 前序、中序以及后序遍历 学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历 (Traversal) 是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次 。访问结点所做的操作依赖于具体的应用问题。…

第一次课,通过进程信息和服务信息识别当前计算机运行程序(预习版)

题目: 检测的目标进程: ydebugg ; “ImmunityDebugger.exe” _500], rax Exe ; “ollydbg.exe” _4F8], rax hackerE ; “ProcessHacker.exe” _4F0], rax Exe ; “tcpview.exe” _4E8], rax sExe ; “autoruns.exe” _4E0], rax scExe ; “autorunsc.ex…

什么是GPT磁盘?介绍GPT(GUID 分区表)磁盘及其优势!

GPT概述 GPT磁盘是什么意思?GPT是全局唯一标识符分区表(GUID Partition Table)的简称,它是硬盘分区表结构的一个标准模式。在我们深入了解GPT磁盘的特性之前须知,MBR磁盘的分区信息直接保存在主引导记录&#xff0…

【论文阅读】Cornus: Atomic Commit for a Cloud DBMS with Storage Disaggregation

Cornus Paper Preknowledge Share-Nothing Related Work Cornus: Atomic Commit for a Cloud DBMS with Storage Disaggregation ABSTRACT 传统2PC存在两个限制(缺点) Long Latency:long latency due to two eager log writes on the …

SQL优化--分页优化(limit)

在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。 通过测试我们会看到,越往后,分页查询效率越低,这就是分页查询的问题所在。 因为,当在进行分页查询时&…

想要精通算法和SQL的成长之路 - 最长等差数列

想要精通算法和SQL的成长之路 - 最长等差数列 前言一. 最长等差数列 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 最长等差数列 原题链接 思路: 我们假设dp[i][j] 为:以num[i]为结尾,以j为公差的最长等差子序列的长度。由此可知&a…

wifi密码破解

文章目录 前言一、破解原理二、配置环境三、运行测试四、资源自取 前言 本文基于 python 实现了破解 wifi 密码的功能,采用的破解方式是穷举法,效率相对来说很低,对于设置密码简单的路由器来说比较适用。 一、破解原理 程序主要采用 python…

2023-09-16 CSP-J 第一轮初赛真题解析

分数:100 考试时间:120分钟 一、 单项选择题(共15题,每题2分,共计30分:每题有且仅有一个正确选项) 1.在 C中,下面哪个关键字用于声明一个变量,其值不能被修改&#xf…

JavaWeb基础学习(5)

JavaWeb基础学习 一、Filter1.1 Filter介绍1.2 Filter快速入门1.3、Filter执行流程1.4、Filter使用细节1.5、Filter-案例-登陆验证 二、Listener2.1 Listener介绍2.2、ServletContextListener使用 三、AJAX3.1 AJAX介绍与概念3.2 AJAX快速入门3.3 Axios异步架构3.4 JSON-概述和…

基于Yolov8网络进行目标检测(三)-训练自己的数据集

前一篇文章详细了讲解了如何构造自己的数据集,以及如何修改模型配置文件和数据集配置文件,本篇主要是如何训练自己的数据集,并且如何验证。 VOC2012数据集下载地址: http://host.robots.ox.ac.uk/pascal/VOC/voc2012/ coco全量数据…

推荐书目:Python从入门到精通(文末送书)

目录 编辑推荐 内容简介 作者简介 前言/序言 本书特点 编辑推荐 “软件开发视频大讲堂”丛书是清华社计算机专业基础类零售图书畅销品牌之一。 (1)2008—2023年,丛书累计修订7次,销售400万册,深受广大程序员喜爱。…

Vulnhub系列靶机---The Planets: Earth(行星-地球)

文章目录 信息收集主机发现端口扫描目录扫描dirsearch 漏洞利用反弹shellnc文件传输strace调试工具 靶机文档:The Planets: Earth 下载地址:Download (Mirror) 难易程度:Easy 信息收集 主机发现 端口扫描 80端口 需要做映射/etc/hosts https…

【算法|虚拟头节点|链表】移除链表元素

Leetcode203 移除链表元素 题目描述: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 示例 1: 输入:head [1,2,6,3,4,5,6], val 6 输出&#xf…

Python入门教学——类和对象

目录 一、面向过程和面向对象 1、面向过程 2、面向对象 二、类 三、类对象与类属性 1、类对象 2、类属性 四、类方法与静态方法 1、类方法 2、静态方法 一、面向过程和面向对象 1、面向过程 是一种以过程为中心的编程思想,强调事件的流程和顺序。思想&…

驱动开发,IO模型,信号驱动IO实现过程

1.信号驱动IO框架图 分析: 信号驱动IO是一种异步IO方式。linux预留了一个信号SIGIO用于进行信号驱动IO。进程主程序注册一个SIGIO信号的信号处理函数,当硬件数据准备就绪后会发起一个硬件中断,在中断的处理函数中向当前进程发送一个SIGIO信号…

高内聚低耦合

低耦合 元素(方法、类)与元素依赖度不要太高;我们在设计程序时应该降低元素与元素之间的直接关系;降低元素与元素之间的耦合性; 若当前有方法A与方法B,A依赖与B,当B不存在的时候A就不能正常工作,那么就说…

高可用集群HA、LVS+Keepalived、健康检测

keepalived是集群管理中保证集群高可用(HA)的一个服务软件,其功能类似于heartbeat,用来防止单点故障。 2.工作原理 keepalived是以VRRP协议为实现基础的,当backup收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个ba…

机器学习笔记之无约束优化问题——(阶段性收尾)共轭方向法与Wolfe准则优化方法Python示例

机器学习笔记之无约束优化问题——基于共轭方向法与Wolfe准则优化方法的Python示例 引言小插曲:画图——非标准二次型的等值线算法在图像中的表示基于精确搜索的共轭梯度法基于Wolfe准则的共轭梯度法 附:共轭梯度法完整代码 引言 本节使用 Python \text…

SQL优化--分组优化(group by)

分组操作,我们主要来看看索引对于分组操作的影响。 在没有索引的情况下,执行如下SQL,查询执行计划: explain select profession , count(*) from tb_user group by profession ;然后,我们在针对于 profession &#…