写点什么

程序员一定要知道的限流大法:令牌桶算法

  • 2024-01-12
    福建
  • 本文字数:1393 字

    阅读完需:约 5 分钟

记得很多年前就有喜欢在面试的时候问这个问题:如何在高并发、大流量的时候,进行服务限流?不同人能给出不同的解决办法。无外乎两种处理:


  • 在客户端限流。


  • 在服务端限流。


在客户端限流,就是利用产品设计,让单位时间内(可以是 1 秒,10 秒,30 秒,1 分钟等)只能发出一定请求数量。给用户友好的交互提醒,让他过一会儿再试。


当然如果遇到懂技术的用户,通过一些手段绕过客户端限流限制,那么服务端又会承受这泼天的密集请求。

在服务端限流是一个比较好的选择,更多的控制权放在服务端。一般考虑在 2 个地方去实现限流。第一个是利用 API Gateway,在网关增加请求速率的限制,把大量的请求直接拦在网关处,从而减少服务器在一定时间内能处理的请求数量。


另一个方案是在 API 服务里面增加限流逻辑,大体的实现思路是:


初始化一个容量固定(比如 N)的 bucket 并装满 N 个 token。每当一个请求过来,就消耗一个 token。当 bucket 没有 token 了,就无法处理请求了。


而我们在一个时间间隔之后快速 refill 满 bucket,继续等待请求过来消耗 token。


下面用一个 js 代码来展示一个 bucket 是如何被消耗 token 并且自动 refill 的:


class TokenBucket {  constructor(capacity, refillRate, refillInterval) {    this.capacity = capacity;         // Maximum tokens in the bucket    this.tokens = capacity;           // Initial number of tokens    this.refillRate = refillRate;     // Number of tokens added per interval    this.refillInterval = refillInterval; // Interval for refilling tokens in milliseconds
// Start the refill process setInterval(() => this.refill(), this.refillInterval); }
// Refill tokens periodically refill() { this.tokens = Math.min(this.tokens + this.refillRate, this.capacity); console.log(`Refilled. Current tokens: ${this.tokens}`); }
// Attempt to consume tokens consume(tokensRequired) { if (this.tokens >= tokensRequired) { this.tokens -= tokensRequired; console.log(`Consumed ${tokensRequired} tokens. Remaining: ${this.tokens}`); return true; } else { console.log(`Not enough tokens. Required: ${tokensRequired}, Available: ${this.tokens}`); return false; } }}
// Example usageconst bucket = new TokenBucket(10, 1, 1000); // Capacity of 10 tokens, refills 1 token every second
// Simulate sending packetssetInterval(() => { const packetSize = 3; // Tokens required per packet if (bucket.consume(packetSize)) { console.log("Packet sent successfully"); } else { console.log("Failed to send packet due to insufficient tokens"); }}, 500); // Attempt to send a packet every 0.5 seconds
复制代码


关于如何实现 refill 还有很多不同实现方法,比如固定时间窗口,滑动时间窗口等,我这个实现是最简单粗暴的。后面找机会再聊一下滑动时间窗口的实现。


总结


令牌桶是一个很常见并且好用的算法,对于那些希望在一段时间内只处理有限请求的场景特别使用。毕竟这泼天的富贵,也要一口一口慢慢吃啊!


文章转载自:freephp

原文链接:https://www.cnblogs.com/freephp/p/17957226

体验地址:http://www.jnpfsoft.com/?from=001


用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
程序员一定要知道的限流大法:令牌桶算法_程序员_不在线第一只蜗牛_InfoQ写作社区