Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >超90%应用都在用的限流算法!究竟是什么套路轻松应对突发流量过载?细品...

超90%应用都在用的限流算法!究竟是什么套路轻松应对突发流量过载?细品...

作者头像
程序视点
发布于 2024-06-07 06:52:04
发布于 2024-06-07 06:52:04
21100
代码可运行
举报
文章被收录于专栏:程序小小事程序小小事
运行总次数:0
代码可运行
前言

前文,我们分享了限流算法中的固定窗口限流算法滑动窗口算法、漏桶限流算法及它们的实践。今天分享一个实践中最常用的限流算法:令牌桶算法。

令牌桶限流

算法介绍

令牌桶算法是实现限流的一种常见思路,用于限制请求的速率。它可以确保系统在高负载情况下仍能提供稳定的服务,并防止突发流量对系统造成过载。

最常用的 Google Java 开发工具包 Guava 中的限流工具类 RateLimiter 就是令牌桶的一个实现。令牌桶算法基于一个令牌桶的概念,其中令牌以固定的速率产生,并放入桶中。每个令牌代表一个请求的许可。当请求到达时,需要从令牌桶中获取一个令牌才能通过。如果令牌桶中没有足够的令牌,则请求被限制或丢弃。

令牌桶算法的实现步骤如下:

  1. 初始化一个令牌桶,包括桶的容量和令牌产生的速率。
  2. 持续以固定速率产生令牌,并放入令牌桶中,直到桶满为止。
  3. 当请求到达时,尝试从令牌桶中获取一个令牌。
  4. 如果令牌桶中有足够的令牌,则请求通过,并从令牌桶中移除一个令牌。
  5. 如果令牌桶中没有足够的令牌,则请求被限制或丢弃。

代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

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

// TokenBucket 表示一个令牌桶。
type TokenBucket struct {
   rate       float64    // 令牌添加到桶中的速率。
   capacity   float64    // 桶的最大容量。
   tokens     float64    // 当前桶中的令牌数量。
   lastUpdate time.Time  // 上次更新令牌数量的时间。
   mu         sync.Mutex // 互斥锁,确保线程安全。
}

// NewTokenBucket 创建一个新的令牌桶,给定令牌添加速率和桶的容量。
func NewTokenBucket(rate float64, capacity float64) *TokenBucket {
   return &TokenBucket{
      rate:       rate,
      capacity:   capacity,
      tokens:     capacity, // 初始时,桶是满的。
      lastUpdate: time.Now(),
   }
}

// Allow 检查是否可以从桶中移除一个令牌。如果可以,它移除一个令牌并返回 true。
// 如果不可以,它返回 false。
func (tb *TokenBucket) Allow() bool {
   tb.mu.Lock()
   defer tb.mu.Unlock()

   // 根据经过的时间计算要添加的令牌数量。
   now := time.Now()
   elapsed := now.Sub(tb.lastUpdate).Seconds() 
   tokensToAdd := elapsed * tb.rate            

   tb.tokens += tokensToAdd
   if tb.tokens > tb.capacity {
      tb.tokens = tb.capacity // 确保令牌数量不超过桶的容量。
   }

   if tb.tokens >= 1.0 {
      tb.tokens--
      tb.lastUpdate = now
      return true
   }

   return false
}

func main() {
   tokenBucket := NewTokenBucket(2.0, 3.0)

   for i := 1; i <= 10; i++ {
      now := time.Now().Format("15:04:05")
      if tokenBucket.Allow() {
         fmt.Printf(now+"  第 %d 个请求通过\n", i)
      } else { // 如果不能移除一个令牌,请求被拒绝。
         fmt.Printf(now+"  第 %d 个请求被限流\n", i)
      }
      time.Sleep(200 * time.Millisecond)
   }
}

执行结果:

优缺点

优点

  1. 平滑流量:令牌桶算法可以平滑突发流量,使得突发流量在一段时间内均匀地分布,避免了流量的突然高峰对系统的冲击。
  2. 灵活性:令牌桶算法可以通过调整令牌生成速率和桶的大小来灵活地控制流量。
  3. 允许突发流量:由于令牌桶可以积累一定数量的令牌,因此在流量突然增大时,如果桶中有足够的令牌,可以应对这种突发流量。

缺点

  1. 实现复杂:相比于其他一些限流算法(如漏桶算法),令牌桶算法的实现稍微复杂一些,需要维护令牌的生成和消耗。
  2. 需要精确的时间控制:令牌桶算法需要根据时间来生成令牌,因此需要有精确的时间控制。如果系统的时间控制不精确,可能会影响限流的效果。
  3. 可能会有资源浪费:如果系统的流量持续低于令牌生成的速率,那么桶中的令牌可能会一直积累,造成资源的浪费。

四种基本算法的对比

结合之前固定窗口限流算法滑动窗口算法、漏桶限流算法,这里把这几个算法做个对比和总结如下。

算法

优点

缺点

适合场景

固定窗口

简单直观,易于实现适用于稳定的流量控制易于实现速率控制

无法应对短时间内的突发流量流量不均匀时可能导致突发流量

稳定的流量控制,不需要保证请求均匀分布的场景

滑动窗口

平滑处理突发流量颗粒度更小,可以提供更精确的限流控制

实现相对复杂需要维护滑动窗口的状态存在较高的内存消耗

需要平滑处理突发流量的场景

漏桶算法

平滑处理突发流量可以固定输出速率,有效防止过载

对突发流量的处理不够灵活无法应对流量波动的情况

需要固定输出速率的场景避免流量的突然增大对系统的冲击的场景

令牌桶

平滑处理突发流量可以动态调整限流规则能适应不同时间段的流量变化

实现相对复杂需要维护令牌桶的状态

需要动态调整限流规则的场景需要平滑处理突发流量的场景

结各个算法的优缺点、适用场景上表都说得很清楚了。后续大家在项目中根据情况按需使用就好。

但以上不是限流算法的全部,随着微服务架构的普及,系统的服务通常会部署在多台服务器上,此时就需要分布式限流来保证整个系统的稳定性。后续我们将继续分享分布式限流的技术方案

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序视点 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
拒绝宕机!一文详解分布式限流方案(附代码实现)
随着微服务的流行,服务之间的依赖性和调用关系变得越来越复杂,服务的稳定性变得尤为重要。业务场景中经常会涉及到瞬时流量冲击,可能会导致请求响应超时,甚至服务器被压垮、宕机不可用。出于对系统本身和上下游服务的保护,我们通常会对请求进行限流处理,快速拒绝超出配置上限的请求,保证系统或上下游服务系统的稳定。合理策略能有效应对流量冲击,确保系统可用性和性能。本文详细介绍了几种限流算法,比较各个算法的优缺点,给出了限流算法选型的一些建议,同时对业务上常用的分布式限流也提出一些解决方案。
腾讯云开发者
2024/02/28
5.2K1
拒绝宕机!一文详解分布式限流方案(附代码实现)
限流的底层原理解析
在软件架构中,限流是一种控制资源使用和保护系统安全的重要机制。它通过限制在一定时间内可以处理的请求数量,来防止系统过载。
GeekLiHua
2024/08/22
2510
限流的底层原理解析
常用限流算法的应用场景和实现原理
在高并发业务场景下,保护系统时,常用的"三板斧"有:"熔断、降级和限流"。今天和大家谈谈常用的限流算法的几种实现方式,这里所说的限流并非是网关层面的限流,而是业务代码中的逻辑限流。
KevinYan
2020/12/31
1.1K0
常用限流算法的应用场景和实现原理
分布式高并发系统限流原理与实践
随着业务的发展壮大,对后端服务的压力也会越来越大,为了打造高效稳定的系统, 产生了分布式,微服务等等系统设计,因为这个原因,设计复杂度也随之增加,基于此 诞生了高并发系统三大利器限流,缓存,降级/熔断。
merlinfeng
2020/12/31
9020
分布式高并发系统限流原理与实践
流量暴增如何应对?漏桶限流算法,让你轻松应对流量高峰!揭晓标准代码,超乎想象的稳定、简单!”
前文,我们分享了限流算法中的滑动窗口算法及其实践。尽管滑动窗口算法可以提供一定的限流效果,但它仍然受限于窗口的大小和时间间隔。
程序视点
2024/06/07
1920
流量暴增如何应对?漏桶限流算法,让你轻松应对流量高峰!揭晓标准代码,超乎想象的稳定、简单!”
基本限流算法与GuavaRateLimiter实现
总结: 固定窗口算法适用于对请求速率有明确要求且流量相对稳定的场景,但对于突发流量和请求分布不均匀的情况,可能需要考虑其他更灵活的限流算法。
leobhao
2024/08/07
2010
基本限流算法与GuavaRateLimiter实现
如何通过限流算法防止系统过载
我们在日常生活中,就有很多限流的例子,比如地铁站在早高峰的时候,会利用围栏让乘客们有序排队,限制队伍行进的速度,避免大家一拥而上;再比如在疫情期间,很多景点会按时段限制售卖的门票数量,避免同一时间在景区的游客太多等等。
栗筝i
2023/02/02
6410
如何通过限流算法防止系统过载
Go实现常见的限流算法
该算法主要是会存在临界问题,如果流量都集中在两个窗口的交界处,那么突发流量会是设置上限的两倍。
每周聚焦
2025/05/07
980
Go实现常见的限流算法
5大常见高并发限流算法选型浅析
在现代高并发系统中,随着用户访问量的激增和业务需求的不断扩展,限流作为一种至关重要的保护机制,被广泛应用于防止系统过载,确保系统的稳定性和可用性。 本文将深入剖析几种常见的限流算法,探讨它们的原理、优缺点并给出代码实例,帮助读者更好地理解和应用这些算法,从而在实际项目中构建更加高效、稳定的系统。
腾讯云开发者
2024/12/19
3350
5大常见高并发限流算法选型浅析
高并发系统的限流策略:漏桶和令牌桶(附源码剖析)
漏桶算法比较好理解,假设我们现在有一个水桶,我们向这个水桶里添水,虽然我们我们无法预计一次会添多少水,也无法预计水流入的速度,但是可以固定出水的速度,不论添水的速率有多大,都按照固定的速率流出,如果桶满了,溢出的上方水直接抛弃。我们把水当作HTTP请求,每次都把请求放到一个桶中,然后以固定的速率处理请求,说了这么多,不如看一个图加深理解(图片来自于网络,手残党不会画,多多包涵):
Golang梦工厂
2022/07/08
1.1K0
高并发系统的限流策略:漏桶和令牌桶(附源码剖析)
常见限流算法及其实现
在分布式系统中,随着业务量的增长,如何保护核心资源、防止系统过载、保证系统的稳定性成为了一个重要的问题。限流算法作为一种有效的流量控制手段,被广泛应用于各类系统中。本文将详细介绍四种常见的限流算法、两种常用的限流器工具,从原理、源码的角度进行分析。
掂过碌蔗啊
2024/03/05
6110
一文了解限流策略的原理与实现
在业务迭代开发过程中,系统的稳定性和可靠性变得越来越重要,其中,限流算法是一种非常重要的技术手段之一。
架构精进之路
2024/03/18
1.1K0
一文了解限流策略的原理与实现
Golang官方限流器的用法详解
限流器是提升服务稳定性的非常重要的组件,可以用来限制请求速率,保护服务,以免服务过载。限流器的实现方法有很多种,常见的限流算法有固定窗口、滑动窗口、漏桶、令牌桶,我在前面的文章 「常用限流算法的应用场景和实现原理」 中给大家讲解了这几种限流方法自身的特点和应用场景,其中令牌桶在限流的同时还可以应对一定的突发流量,与互联网应用容易因为热点事件出现突发流量高峰的特点更契合。
KevinYan
2021/07/15
6.4K0
使用Redis实现限流
在分布式系统中,限流是保护服务的重要手段之一。通过限流,可以防止接口被恶意刷请求或突发流量压垮,从而保证系统的稳定性。Redis是一个高性能的键值存储工具,因其高效的读写性能和丰富的数据结构,被广泛用于限流场景。本文将介绍三种使用Redis实现限流的方式,并通过代码示例说明其实现原理和应用场景。
用户11397231
2024/12/23
5160
使用Redis实现限流
流量控制还能这么搞。。。
在上一篇文章聊聊服务注册与发现中,我们讲了微服务架构中核心功能之一服务注册与发现。在本文中,我们将着重讲下微服务的另外一个核心功能点:流量控制。
高性能架构探索
2022/08/25
6530
流量控制还能这么搞。。。
面试必备:4种经典限流算法讲解
最近,我们的业务系统引入了Guava的RateLimiter限流组件,它是基于令牌桶算法实现的,而令牌桶是非常经典的限流算法。本文将跟大家一起学习几种经典的限流算法。
捡田螺的小男孩
2021/06/15
1.9K2
面试必备:4种经典限流算法讲解
高并发之接口限流算法总结
曾经在一个大神的博客里看到这样一句话:在开发高并发系统时,有三把利器用来保护系统:缓存、降级和限流。那么何为限流呢?顾名思义,限流就是限制流量,就像你宽带包了1个G的流量,用完了就没了。通过限流,我们可以很好地控制系统的qps,从而达到保护系统的目的。本篇文章将会介绍一下常用的限流算法以及他们各自的特点。
beifengtz
2019/06/03
1K0
高并发之接口限流算法总结
后端服务不得不了解之限流
现在说到高可用系统,都会说到高可用的保护手段:缓存、降级和限流,本博文就主要说说限流。限流是流量限速(Rate Limit)的简称,是指只允许指定的事件进入系统,超过的部分将被拒绝服务、排队或等待、降级等处理。
好好学java
2021/02/07
1.8K0
Spring Boot 的接口限流算法
在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用。
阿珍
2025/06/11
940
Spring Boot 的接口限流算法
Java - 深入四大限流算法:原理、实现与应用
Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级
小小工匠
2024/05/25
1.1K0
Java - 深入四大限流算法:原理、实现与应用
推荐阅读
相关推荐
拒绝宕机!一文详解分布式限流方案(附代码实现)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验