使用Java实现Redis限流的方法
作者:别团等shy哥发育 发布时间:2023-09-27 01:43:47
1、概述
限流的含义是在单位时间内确保发往某个模块的请求数量小于某个数值,比如在实现秒杀功能时,需要确保在10秒内发往支付模块的请求数量小于500个。限流的作用是防止某个段时间段内的请求数过多,造成模块因高并发而不可用。
2、zset有序集合相关命令与限流
zset也叫有序集合,是Redis的一种数据类型,在其中每个值(value)都会有一个对应的score参数,以此来描述该值的权重分值。可以通过如下形式的命令向zset有序集合里添加元素:
zadd key score value
在限流相关的应用里,可以通过zadd命令往有序集合里存放数据时引入表示权重的score参数,并在其中存放时间戳。由于zset是有序集合,因此包含时间戳的score能被排序,这样就能用zremrangeByScore命令去除指定时间范围内的数据。zrenrabgeByScore命令的语法如下:
zremrangeByScore key min max
通过该命令能在有序集合里删除键为key、score值在min到max范围内的数据。通过这种删除动作,能排除限流时间范围外的数据,并能在此基础上通过zcard命令统计有序集合内元素的数量,以确保请求数量小于限流的上限值。zcard命令的语法格式如下:
zcard key
该命令会返回有序集合内指定key的元素数量。
3、zset有序结合与限流
有关redis启动的知识不做过多介绍了,这里我用docker创建的redis容器。
本例实现100秒内只能处理3个请求
LimitRequest.java
package com.baizhi.request;
import redis.clients.jedis.Jedis;
public class LimitRequest {
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.159.33",6379);
jedis.del("PayRequest");
//模拟发5个请求
int cnt=5;
for (int i = 0; i < cnt; i++) {
LimitUtil.canVisit(jedis,"PayRequest",100,3);
}
}
}
class LimitUtil{
//判断是否需要限流
public static void canVisit(Jedis jedis,String requestType,int limitTime,int limitNum){
long currentTime=System.currentTimeMillis();
//把请求放入zset
jedis.zadd(requestType,currentTime,Long.valueOf(currentTime).toString());
//去掉时间范围外(超时)的请求
jedis.zremrangeByScore(requestType,0,currentTime-limitTime*1000);
//统计时间范围内总数
Long count=jedis.zcard(requestType);
//设置所有请求的超时时间
jedis.expire(requestType,limitTime+1);
boolean flag=limitNum>=count;
if(flag){
System.out.println("Can visit");
}else{
System.out.println("Can not visit");
}
}
}
先通过zadd方法把表示操作类型的requestType作为键插入有序集合,插入时用表示当前时间的currentTime作为值,以保证值的唯一性,同时用currentTime作为有序集合里元素的score值。
随后通过zremrangeByScore命令去除0到距当前时间limitTime时间范围内的数据。比如限流的时间范围是100秒,那么通过zremrangeByScore命令就能在有序集合里去除score范围从0到距离当前时间100秒的数据,这样就能确保有序集合内只存有最近100秒内发来的元素。
其中,用zcard命令统计有序集合内键为requestType的个数,如果通过if语句发现当前个数还没有达到限流的上限,则允许该请求方法,否则不允许。这里通过最后的打印语句来模拟“是否允许请求访问”的动作。
同时请注意,需要使用expire语句设置有序集合里相关键的超时时间,这样就能确保在限流动作完成后这些键能自动删除,而不是一致驻留在内存中。
在main函数里,首先创建指向虚拟机6379端口的jedis对象,为了确保在多次运行时数据不相互干扰,在运行前通过del语句删除相关的键。
随后使用for循环里通过调用canVisit方法模拟发出5个请求。在调用该方法时,通过传入参数指定限流所用的键为"PayRequest",同时指定了100秒内只能处理3个请求。运行之后控制台的效果如下:
来源:https://blog.csdn.net/qq_43753724/article/details/120456516


猜你喜欢
- 1.easy-captcha工具包生成验证码的方式有许多种,这里选择的是easy-captcha工具包。github开原地址为:easy-c
- 一、关键字关键字:被Java语言赋予特定含义的单词。组成关键字的字母全部小写。注:goto和const作为保留字存在,目前并不使用。main
- pom 文件依赖 <dependency> &
- 一、创建maven项目我使用的是汉化的idea可以选择原型,我这里没有选择输入项目名称,完成创建二、配置tomcat选择运行编辑配置点加号找
- 一、前言拷贝这个词想必大家都很熟悉,在工作中经常需要拷贝一份文件作为副本。拷贝的好处也很明显,相较于新建来说,可以节省很大的工作量。在Jav
- Java设计模式访问者模式模式概念访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的
- 本文实例讲述了Android编程之控件状态配置文件。分享给大家供大家参考,具体如下:<selector xmlns:android=&
- @Profiles和@PropertySource根据环境切换配置文件使用@PropertySource注解加载配置文件,并制定解析配置文件
- 本文实例讲述了Android持久化技术之SharedPreferences存储。分享给大家供大家参考,具体如下:1、SharedPrefer
- Volley简单使用我这里是以依赖架包的形式 ,大家也可以以gradle的形式进行依赖。好了,接下来上代码了.....//获取volley的
- 一、基础很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定
- 前言日常编码过程中,最重要的技能不是说你学会使用很多最新的编程技术或者做出一个高大上的系统。而是你在写代码过程中,对异常的处理,是否系统可以
- java随机验证码生成实现实例代码摘要: 在项目中有很多情况下都需要使用到随机验证码,这里提供一个java的随机验证码生成方案,可以指定难度
- 作为Android开发者,工作中少不了要反编译别人的apk,当然主要目的还是为了学习到更多,取彼之长,补己之短。今天就来总结一下Androi
- Android 加载大图及多图避免程序出现OOM(OutOfMemory)异常1、高效加载大图片我们在编写Android程序的时候经常要用到
- 前言最近公司产品突然有一个类似支付宝蚂蚁森林的功能,大致功能跟支付宝蚂蚁森林相像,在看了一下支付宝蚂蚁森林的效果之后,打算先撸一个控件出来,
- 访问权限符:(1)public:对于成员来说:任何其他类都可以访问它们,不管在同一个包中还是在另外的包中。对于类来说:  
- 本文实例讲述了C#实现回文检测的方法。分享给大家供大家参考。具体分析如下:回文:称正读和反读都相同的字符序列为“回文”,如“abba”、“a
- 需求:校验收货地址是否超出配送范围重要:做该需求的思路就是通过卖家和卖家具体的地址信息,来获取到二者的经纬度, 此时可以使用百度的 &quo
- Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建