首页 > 其他分享 >Go语言如何实现限制用户 1 分钟内最多请求 1000 次?

Go语言如何实现限制用户 1 分钟内最多请求 1000 次?

时间:2025-01-20 21:27:34浏览次数:3  
标签:令牌 lb 请求 算法 time Go tb 1000

文章精选推荐

1 JetBrains Ai assistant 编程工具让你的工作效率翻倍
2 Extra Icons:JetBrains IDE的图标增强神器
3 IDEA插件推荐-SequenceDiagram,自动生成时序图
4 BashSupport Pro 这个ides插件主要是用来干嘛的 ?
5 IDEA必装的插件:Spring Boot Helper的使用与功能特点
6 Ai assistant ,又是一个写代码神器
7 Cursor 设备ID修改器,你的Cursor又可以继续试用了

文章正文

在 Go 语言中,限制用户每分钟最多请求 1000 次的常见做法是使用 限流算法(Rate Limiting)。有多种算法可以实现这一目标,其中最常见的包括 令牌桶算法 (Token Bucket)漏桶算法 (Leaky Bucket)计数器算法 (Counter)。每种算法有其特点和适用场景,下面将逐个介绍,并附上相应的 Go 语言实现。

1. 令牌桶算法 (Token Bucket)

令牌桶算法是常见的限流算法,适用于需要平滑流量控制的场景。令牌桶维护一个存储令牌的桶,每个请求需要消耗一个令牌。如果桶内有足够的令牌,请求可以继续;如果没有令牌,则请求被拒绝。令牌按固定速率生成,当桶满时,额外的令牌会丢弃。

令牌桶算法的实现
package main

import (
	"fmt"
	"sync"
	"time"
)

type TokenBucket struct {
	rate      int           // 生成令牌的速率,单位是令牌/秒
	capacity  int           // 桶的容量
	tokens    int           // 当前令牌数量
	lastToken time.Time     // 上次生成令牌的时间
	mutex     sync.Mutex    // 用于并发控制
}

func NewTokenBucket(rate, capacity int) *TokenBucket {
	return &TokenBucket{
		rate:     rate,
		capacity: capacity,
		tokens:   capacity, // 初始时,桶里有满的令牌
	}
}

func (tb *TokenBucket) refill() {
	// 计算过去时间段内生成的令牌数
	now := time.Now()
	elapsed := now.Sub(tb.lastToken)
	tb.lastToken = now
	// 按速率生成令牌
	newTokens := int(elapsed.Seconds()) * tb.rate
	if newTokens > 0 {
		// 桶中令牌数增加
		tb.tokens += newTokens
		if tb.tokens > tb.capacity {
			// 超过桶容量,令牌数只能是桶的最大容量
			tb.tokens = tb.capacity
		}
	}
}

func (tb *TokenBucket) Allow() bool {
	tb.mutex.Lock()
	defer tb.mutex.Unlock()
	// 补充令牌
	tb.refill()
	if tb.tokens > 0 {
		// 有令牌可以消耗
		tb.tokens--
		return true
	}
	// 没有令牌可用,限制请求
	return false
}

func main() {
	// 创建令牌桶,令牌生成速率为每秒 1000 个,容量为 1000 个令牌
	tb := NewTokenBucket(1000, 1000)

	// 模拟用户发起请求
	for i := 0; i < 10; i++ {
		if tb.Allow() {
			fmt.Println("Request", i+1, "allowed")
		} else {
			fmt.Println("Request", i+1, "rejected")
		}
		time.Sleep(100 * time.Millisecond) // 模拟请求间隔
	}
}
说明:
  • rate:每秒生成的令牌数。
  • capacity:桶的最大容量。
  • tokens:当前桶中可用的令牌数。
  • 每次请求时,Allow() 方法会检查桶中是否有令牌,如果有,则消耗一个令牌并允许请求;如果没有令牌,则拒绝请求。

2. 漏桶算法 (Leaky Bucket)

漏桶算法是另一种常用的限流算法,适用于流量平滑控制。在漏桶算法中,桶里有水(请求),水按固定速率流出。当请求到来时,如果桶满了,新的请求会被丢弃;如果桶未满,新的请求会被加入桶中,并在固定速率下流出。

漏桶算法的实现
package main

import (
	"fmt"
	"sync"
	"time"
)

type LeakyBucket struct {
	rate      int           // 水流出速率,单位是请求/秒
	capacity  int           // 桶的容量
	water     int           // 当前桶中水的数量
	lastDrain time.Time     // 上次排水时间
	mutex     sync.Mutex    // 用于并发控制
}

func NewLeakyBucket(rate, capacity int) *LeakyBucket {
	return &LeakyBucket{
		rate:     rate,
		capacity: capacity,
		water:    0, // 初始时,桶里没有水
	}
}

func (lb *LeakyBucket) drain() {
	// 计算过去时间段内排出的请求数
	now := time.Now()
	elapsed := now.Sub(lb.lastDrain)
	lb.lastDrain = now
	// 按排出速率流出请求
	drained := int(elapsed.Seconds()) * lb.rate
	if drained > 0 {
		lb.water -= drained
		if lb.water < 0 {
			lb.water = 0
		}
	}
}

func (lb *LeakyBucket) Allow() bool {
	lb.mutex.Lock()
	defer lb.mutex.Unlock()
	// 排水
	lb.drain()
	if lb.water < lb.capacity {
		// 桶未满,允许请求
		lb.water++
		return true
	}
	// 桶已满,拒绝请求
	return false
}

func main() {
	// 创建漏桶,排水速率为每秒 1000 个,桶的容量为 1000 个
	lb := NewLeakyBucket(1000, 1000)

	// 模拟用户发起请求
	for i := 0; i < 10; i++ {
		if lb.Allow() {
			fmt.Println("Request", i+1, "allowed")
		} else {
			fmt.Println("Request", i+1, "rejected")
		}
		time.Sleep(100 * time.Millisecond) // 模拟请求间隔
	}
}
说明:
  • rate:请求的排出速率。
  • capacity:桶的最大容量。
  • water:当前桶中水(请求)的数量。
  • drain():排水操作,控制请求的流出速率。

3. 计数器算法 (Fixed Window Counter)

计数器算法是最简单的一种限流算法。在每个时间窗口内,记录请求的数量。当请求数达到限制时,就会拒绝进一步的请求。它适用于简单的限流场景,但对于高并发时可能会出现窗口突发的情况。

计数器算法的实现
package main

import (
	"fmt"
	"sync"
	"time"
)

type Counter struct {
	limit      int           // 请求限制次数
	windowSize time.Duration // 时间窗口大小
	mu         sync.Mutex    // 用于并发控制
	requests   int           // 当前请求计数
	windowStart time.Time    // 当前时间窗口开始时间
}

func NewCounter(limit int, windowSize time.Duration) *Counter {
	return &Counter{
		limit:      limit,
		windowSize: windowSize,
		requests:   0,
		windowStart: time.Now(),
	}
}

func (c *Counter) Allow() bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	// 判断是否在当前时间窗口内
	now := time.Now()
	if now.Sub(c.windowStart) > c.windowSize {
		// 如果超过了窗口时间,则重置请求计数器和窗口开始时间
		c.windowStart = now
		c.requests = 0
	}
	if c.requests < c.limit {
		// 如果请求数未达到限制,允许请求
		c.requests++
		return true
	}
	// 否则,拒绝请求
	return false
}

func main() {
	// 创建计数器,限制每分钟 1000 次请求
	counter := NewCounter(1000, time.Minute)

	// 模拟用户发起请求
	for i := 0; i < 10; i++ {
		if counter.Allow() {
			fmt.Println("Request", i+1, "allowed")
		} else {
			fmt.Println("Request", i+1, "rejected")
		}
		time.Sleep(100 * time.Millisecond) // 模拟请求间隔
	}
}
说明:
  • limit:时间窗口内允许的最大请求次数。
  • windowSize:时间窗口的大小(比如 1 分钟)。
  • requests:当前时间窗口内已处理的请求数量。
  • Allow():每次请求时,检查当前窗口内请求数是否达到限制。

4. 总结

  • 令牌桶算法(Token Bucket)适用于平滑流量控制,允许突发请求。
  • 漏桶算法(Leaky Bucket)适用于平滑流量,适合流量控制比较严格的场景。
  • 计数器算法(Counter)是最简单的一种限流方式,适合简单的限流需求,但对突发流量处理较差。根据不同的需求场景,选择合适的算法进行实现。

标签:令牌,lb,请求,算法,time,Go,tb,1000
From: https://blog.csdn.net/wuchaoyong0413/article/details/145269525

相关文章

  • (开源)基于Django+Yolov8+Tensorflow的智能鸟类识别平台
    1项目简介(开源地址在文章结尾)系统旨在为了帮助鸟类爱好者、学者、动物保护协会等群体更好的了解和保护鸟类动物。用户群体可以通过平台采集野外鸟类的保护动物照片和视频,甄别分类、实况分析鸟类保护动物,与全世界各地的用户,沟通交流。2启动步骤1.配置开发环境2.python......
  • 基于goland的WebShell检测设计于研究
    摘要随着互联网在我们生活中被广泛应用到社交、金融、行政以及办公等领域,网络安全的问题也越来越被重视。WebShell的本质是一种Web应用脚本程序,由于其可以通过HTTP协议的方式对服务器进行控制,故常被黑客用于植入到被入侵的系统中,严重威胁到主机的安全。本文针对现有的WebSh......
  • Go语言【Gin框架】:JSON、AsciiJSON、PureJSON和SecureJSON的区别
    在Go语言中,JSON、AsciiJSON、PureJSON和SecureJSON是Gin框架用于发送JSON响应的方法。1.c.JSON功能:将提供的数据序列化为标准的JSON格式,并将其作为HTTP响应发送给客户端。特点:支持Unicode字符,无需将非ASCII字符转义。某些字符(如<、>和&)会被自动转义为相应的Unicode......
  • ajax的请求状态有哪几种?
    Ajax的请求状态主要有五种,这些状态可以通过XMLHttpRequest对象的readyState属性来获取。以下是这五种状态的详细解释:未初始化(readyState=0):此时XMLHttpRequest对象已经创建,但尚未调用send()方法,即还没有开始发送请求。这是Ajax请求的初始状态。载入(readyState=1):在此状态下,已......
  • 当用户刷新网页时,js的请求有哪些地方会有缓存处理呢?
    当用户刷新网页时,JavaScript(JS)的请求在多个环节都可能涉及到缓存处理。以下是一些主要的缓存处理点和相关机制:浏览器缓存:浏览器会尝试缓存已下载的JS文件,以便在将来的页面加载中重新使用它们,减少对服务器的请求次数和页面加载时间。当用户刷新网页时,浏览器首先会检查本地缓......
  • Oracle GoldenGate product family
    [IntroductiontoOracleGoldenGate](https://docs.oracle.com/goldengate/c1230/gg-winux/GGCON/introduction-oracle-goldengate.htm) Therearenumerousproductsinthe OracleGoldenGate productfamily.OracleGoldenGate Veridata : OracleGoldenGate Ver......
  • 百兆/千兆/万兆(100Mbps/1000Mbps/10000Mbps)网络带宽的实际传输速率粗略计算 (转)
    首先关于网络带宽有两个值:理论带宽与实际带宽。实际带宽是由于实际的应用中,要再扣约12%的EthernetHeader,IPHeader,TCPHeader,ATMHeader等控制讯号,然后再排除网络损耗以及线路衰减等因素,所以实际带宽都达不到理论值百兆网(100Mbps):100Mbps理论传输速度是12.5MB/s,实际11MB/......
  • gorm - datatypes.JSONQuery 多种 JSON 查询方式
    一.官方:https://github.com/go-gorm/datatypes 二.modeltypeUserstruct{Name`gorm:"column:name;type:varchar(255);`Attributesdatatypes.JSON`gorm:"column:attributes;type:json"`}//数据内容user:=model.Us......
  • Ubuntu 安装MongoDB
    使用apt安装MongoDB导入MongoDB的公钥MongoDB的包使用GPG密钥进行签名,需要先导入公钥:wget-qO-https://www.mongodb.org/static/pgp/server-6.0.asc|sudoapt-keyadd-添加MongoDB的软件源创建一个MongoDB的源列表文件:echo"deb[arch=amd64,arm64]htt......
  • 如何解决phpMyAdmin导出时提示“当前表单包含的字段多于 1000,受限于PHP 中 max_input_
    常见原因max_input_vars 设置过低:默认情况下,max_input_vars 的值为1000,当表单字段超过这个数量时,就会触发警告。表单字段过多:某些大型数据库或复杂的表单可能会包含超过1000个字段。解决方法方法一:修改 php.ini 文件找到 php.ini 文件:php.ini 文件通常位于PHP安......