令牌桶限流

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: 令牌桶算法比较简单,它就好比摇号买房,拿到号的人才有资格买,没拿到号的就只能等下次了(还好小编不需摇号,因为买不起!)。

1、简介

令牌桶算法比较简单,它就好比摇号买房,拿到号的人才有资格买,没拿到号的就只能等下次了(还好小编不需摇号,因为买不起!)。

在实际的开发中,系统会维护一个容器用于存放令牌(token),并且系统以一个固定速率往容器中添加令牌(token),这个速率通常更加系统的处理能力来权衡。当客户端的请求打过来时,需要从令牌桶中获取到令牌(token)之后,这个请求才会被处理,否则直接拒绝服务。

令牌桶限流的关键在于发放令牌的速率和令牌桶的容量。

实现令牌桶限流的方式有很多种,本文讲述的是基于Redis的Redis-Cell限流模块,这是Redis提供的适用于分布式系统、高效、准确的限流方式,使用十分广泛,而且非常简单!

2、Redis-Cell的安装

Redis默认是没有集成Redis-Cell这个限流模块的,就好比Redis使用布隆过滤器一样,我们也需要对该模块进行安装与集成。

2.1 GitHub源码&安装包

Redis-Cell的GitHub地址:

https://github.com/brandur/redis-cell

Redis-Cell基于Rust语言开发,如果不想花费精力去搞Rust环境,那么可以直接下载与你的操作系统对应的安装包(这个很关键,我就安装了挺多次的,如果安装的问题比较多的话,也建议降低一个release版本!)


下载对应的安装包:

https://github.com/brandur/redis-cell/releases/download/v0.3.0/redis-cell-v0.3.0-armv7-unknown-linux-gnueabihf.tar.gz

如果不清楚自己的服务器(Linux)版本的,可以事先查看后再下载安装包:

# Linux 查看当前操作系统的内核信息

uname -a

# 查看当前操作系统系统的版本信息

cat /proc/version


2.2 安装&异常处理

  • 在Redis的安装目录的同级目录下,新建文件夹Redis-Cell,将压缩包上传后解压

tar -zxvf redis-cell-v0.2.5-powerpc64-unknown-linux-gnu.tar.gz

  • 解压后出现如下文件,复制libredis_cell.so文件的路径(pwd查看当前路径

  • 修改Redis配置文件,redis.conf,添加完成后记得保存后再退出

  • 重启Redis,如果启动正常,进入redis客户端,通过module list查看挂载的模块是否有Redis-Cell

  • 测试指令,出现如下情况说明集成Redis-Cell成功

  • 如果重启Redis后,客户端无法连接成功,说明Redis启动失败,这个时候我们需要查看Redis的启动日志,如果已经配置日志文件的可以直接查看日志定位问题,如果还未配置日志文件的需要先配置日志文件,redis.conf添加日志文件路径地址,再次重启,查看日志文件输出的错误日志

  • 错误可能千奇百怪,问题不大搞技术就不要心急,一个个解决,我这里记录下我最后遇到的问题,/lib64/libc.so.6: version `GLIBC_2.18‘ not found

43767:M 08 Sep 2021 21:39:39.643 # Module /usr/local/soft/Redis-Cell-0.3.0/libredis_cell.so failed to load: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by /usr/local/soft/Redis-Cell-0.3.0/libredis_cell.so)

43767:M 08 Sep 2021 21:39:39.643 # Can't load module from /usr/local/soft/Redis-Cell-0.3.0/libredis_cell.so: server aborting

  • 缺失GLIBC_2.18,那就安装它(最后两个编译的过程时间比较长,耐心等待几分钟)

yum install gcc

wget http://ftp.gnu.org/gnu/glibc/glibc-2.18.tar.gz

tar zxf glibc-2.18.tar.gz

cd glibc-2.18/

mkdir build

cd build/

../configure --prefix=/usr

make -j4

make install

  • 安装完成后,重启Redis,测试是否安装成功,循环上面的过程,通过日志分析错误即可

3、CL.THROTTLE指令

指令CL.THROTTLE参数含义

CL.THROTTLE liziba  10  5 60 1

              ▲     ▲  ▲  ▲ ▲

              |     |  |  | └───── apply 1 token (default if omitted) (本次申请一个token)

              |     |  └──┴─────── 5 tokens / 60 seconds  (60秒添加5个token到令牌桶中)

              |     └───────────── 10 max_burst (最大的突发请求,不是令牌桶的最大容量)

              └─────────────────── key "liziba" (限流key)

输出参数值含义

127.0.0.1:6379> cl.throttle liziba 10 5 60 1

1) (integer) 0     # 当前请求是否被允许,0表示允许,1表示不允许

2) (integer) 11     # 令牌桶的最大容量,令牌桶中令牌数的最大值

3) (integer) 10      # 令牌桶中当前的令牌数

4) (integer) -1     # 如果被拒绝,需要多长时间后在重试,如果当前被允许则为-1

5) (integer) 12     # 多长时间后令牌桶中的令牌会满

这里唯一有歧义的可能是max_burst,这个并不是令牌桶的最大容量,从作者的README.md中的解释也可以看出来

The total limit of the key (max_burst + 1). This is equivalent to the common X-RateLimit-Limit HTTP header.


4、Java调用Redis-Cell模块实现限流

4.1 导入依赖

<dependency>

 <groupId>io.lettuce</groupId>

 <artifactId>lettuce-core</artifactId>

 <version>5.3.4.RELEASE</version>

 <!--排除 netty 包冲突-->

 <exclusions>

   <exclusion>

     <groupId>io.netty</groupId>

     <artifactId>netty-buffer</artifactId>

   </exclusion>

   <exclusion>

     <groupId>io.netty</groupId>

     <artifactId>netty-common</artifactId>

   </exclusion>

   <exclusion>

     <groupId>io.netty</groupId>

     <artifactId>netty-codec</artifactId>

   </exclusion>

   <exclusion>

     <groupId>io.netty</groupId>

     <artifactId>netty-transport</artifactId>

   </exclusion>

 </exclusions>

</dependency>

4.2 实现代码

Redis命令接口定义:

package com.lizba.redis.limit.tokenbucket;


import io.lettuce.core.dynamic.Commands;

import io.lettuce.core.dynamic.annotation.Command;


import java.util.List;


/**

* <p>

*      Redis命令接口定义

* </p>

*

* @Author: Liziba

* @Date: 2021/9/8 23:50

*/

public interface IRedisCommand extends Commands {



   /**

    * 定义限流方法

    *

    * @param key           限流key

    * @param maxBurst      最大的突发请求,桶容量等于maxBurst + 1

    * @param tokens        tokens 与 seconds 是组合参数,表示seconds秒内添加个tokens

    * @param seconds       tokens 与 seconds 是组合参数,表示seconds秒内添加个tokens

    * @param apply         当前申请的token数

    * @return

    */

   @Command("CL.THROTTLE ?0 ?1 ?2 ?3 ?4")

   List<Object> throttle(String key, long maxBurst, long tokens, long seconds, long apply);


}


Redis-Cell令牌桶限流类定义:

package com.lizba.redis.limit.tokenbucket;


import io.lettuce.core.RedisClient;

import io.lettuce.core.api.StatefulRedisConnection;

import io.lettuce.core.dynamic.RedisCommandFactory;


import java.util.List;


/**

* <p>

*      Redis-Cell令牌桶限流

* </p>

*

* @Author: Liziba

* @Date: 2021/9/8 23:47

*/

public class TokenBucketRateLimiter {


   private static final String SUCCESS = "0";

   private RedisClient client;

   private StatefulRedisConnection<String, String> connection;

   private IRedisCommand command;


   public TokenBucketRateLimiter(RedisClient client) {

       this.client = client;

       this.connection = client.connect();

       this.command = new RedisCommandFactory(connection).getCommands(IRedisCommand.class);

   }



   /**

    * 请是否被允许

    *

    * @param key

    * @param maxBurst

    * @param tokens

    * @param seconds

    * @param apply

    * @return

    */

   public boolean isActionAllowed(String key, long maxBurst, long tokens, long seconds, long apply) {

       List<Object> result = command.throttle(key, maxBurst, tokens, seconds, apply);

       if (result != null && result.size() > 0) {

           return SUCCESS.equals(result.get(0).toString());

       }

       return false;

   }


}

测试代码:

package com.lizba.redis.limit.tokenbucket;


import io.lettuce.core.RedisClient;


/**

* <p>

*      测试令牌桶限流

*      测试参数 cl.throttle liziba 10 5 60 1

* </p>

*

* @Author: Liziba

* @Date: 2021/9/9 0:02

*/

public class TestTokenBucketRateLimiter {


   public static void main(String[] args) {

       RedisClient client = RedisClient.create("redis://192.168.211.108:6379");

       TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(client);

       // cl.throttle liziba 10 5 60 1

       for (int i = 1; i <= 15; i++) {

           boolean success = limiter.isActionAllowed("liziba", 10, 5, 60, 1);

           System.out.println("第" + i + "次请求" + (success ? "成功" : "失败"));

       }


   }


}

测试结果(这里也说明了令牌桶的容量是max_burst + 1):

第0次请求成功

第1次请求成功

第2次请求成功

第3次请求成功

第4次请求成功

第5次请求成功

第6次请求成功

第7次请求成功

第8次请求成功

第9次请求成功

第10次请求成功

第11次请求成功

第14次请求失败

第15次请求失败

第14次请求失败

第15次请求失败

目录
相关文章
|
域名解析 网络协议 安全
DNS查询工具简介
DNS查询工具简介
1159 4
|
JavaScript 前端开发 Docker
前端的全栈之路Meteor篇(一):开发环境的搭建 -全局安装或使用容器镜像
本文介绍了如何搭建 Meteor 开发环境,包括全局安装 Meteor 工具和使用 Docker 镜像两种方法,以及创建和运行一个简单的 Meteor 项目的基本步骤。 Meteor 是一个全栈 JavaScript 框架,适用于构建实时 Web 应用程序。文章还提供了遇到问题时的解决建议和调试技巧。
640 3
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
237 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
网络协议 算法 数据安全/隐私保护
HTTP2和HTTP3区别?HTTP2有什么缺点?
总的来说,如果把HTTP/2比作是优化过的汽车,那HTTP/3就像是直升飞机,它不仅飞得快,而且即使前面有障碍也不会轻易停下。想要网站速度更快,HTTP/3无疑提供了更好的选择。
1083 3
|
前端开发 JavaScript
HTML+CSS如何打造撒花动画效果?3分钟学会,炫酷到爆!
HTML+CSS如何打造撒花动画效果?3分钟学会,炫酷到爆!
|
Web App开发 JavaScript 前端开发
Web 页面性能衡量指标-以用户为中心的性能指标
Web 页面性能衡量指标-以用户为中心的性能指标 以用户为中心的性能指标是理解和改进站点体验的关键点 一、以用户为中心的性能指标 1. 指标是用来干啥的? 指标是用来衡量性能和用户体验的 2. 指标类型 • 感知加载速度:网页可以多快地加载网页中的所有视觉元素并将其渲染到屏幕上 • 加载响应速度:页面加载和执行组件快速响应用户互动所需的 JavaScript 代码的速度 • 运行时响应速度:网页在加载后对用户互动的响应速度 • 视觉稳定性:页面上的元素是否会以用户意想不到的方式发生偏移,是否可能会干扰用户的互动? • 流畅性:过渡和动画是否以一致的帧速率渲染,并在一种状态之间流畅地流动
591 1
|
监控 安全 UED
淘宝代购集运系统“牵手”马来西亚iPay88,进一步完善电商支付体验
**淘宝代购集运系统与iPay88合作,整合多支付方式,增强跨境支付体验,扩大东南亚市场覆盖,提升交易安全,共同打造更高效、便捷的购物环境。此联动能优化支付流程,提供客户服务支持,标志着双方在推进电商发展上的重要步骤。**
|
人工智能 算法 机器人
Github上5个实用的ChatGPT仓库
Github上5个实用的ChatGPT仓库
488 0
|
存储 数据可视化 数据库
Grafana数据可视化工具安装与应用
关键词:Grafana、Elasticsearch、Table、Gauge、BarGrauge、Graph、PieChart、Variables。
5759 0
Grafana数据可视化工具安装与应用
|
存储 XML 机器学习/深度学习
VisionOn 一款集流程图、思维导图、白板于一体的轻量级在线制图工具
在工作和学习过程中,通过可视化的图形,有助于清晰高效地表达我们的灵感、想法、思想。 工欲善其事,必先利其器。 目前,思维导图软件已经有 Xmind、Mindnode、 MindMeister 、亿图图示、 Gitmind,流程图软件包括 Microsoft Visio、 Draw.io、ProcessOn,白板软件包括 Miro、 无边记、 BoardMix 博思白板、Excalidraw. 今天介绍一款简单、好用、强大、高颜值、性价比高的制图工具 —— VisionOn.
798 0

热门文章

最新文章