目录引言固定时间窗口算法实现滑动时间窗口算法实现漏桶算法实现令牌桶算法引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了。因为在网站运行期间可能会因为突然的
优点
缺点
controller
@RequestMapping(value = "/start",method = RequestMethod.GET)
public Map<string,object> start(@RequestParam Map<string, object=""> paramMap) {
return testService.startQps(paramMap);
}
service
@Override
public Map<string, object=""> startQps(Map<string, object=""> paramMap) {
//根据前端传递的qps上线
Integer times = 100;
if (paramMap.containsKey("times")) {
times = Integer.valueOf(paramMap.get("times").toString());
}
String redisKey = "redisQps";
RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory());
int no = redisAtomicInteger.getAndIncrement();
//设置时间固定时间窗口长度 1S
if (no == 0) {
redisAtomicInteger.expire(1, TimeUnit.SECONDS);
}
//判断是否超限 time=2 表示qps=3
if (no > times) {
throw new RuntimeException("qps refuse request");
}
//返回成功告知
Map<string, object=""> map = new HashMap<>();
map.put("success", "success");
return map;
}
结果测试
我们设置的qps=3 , 我们可以看到五个并发进来后前三个正常访问,后面两个就失败了。稍等一段时间我们在并发访问,前三个又可以正常访问。说明到了下一个时间窗口
优点
缺点
controller
@RequestMapping(value = "/startList",method = RequestMethod.GET)
public Map<string,object> startList(@RequestParam Map<string, object=""> paramMap) {
return testService.startList(paramMap);
}
service
@RequestMapping(value = "/startList",method = RequestMethod.GET)
public Map<string,object> startList(@RequestParam Map<string, object=""> paramMap) {
return testService.startList(paramMap);
}
结果测试
优点
缺点
controller
@RequestMapping(value = "/startLoutong",method = RequestMethod.GET)
public Map<string,object> startLoutong(@RequestParam Map<string, object=""> paramMap) {
return testService.startLoutong(paramMap);
}
service
在service中我们通过redis的list的功能模拟出桶的效果。这里代码是实验室性质的。在真实使用中我们还需要考虑并发的问题
@Override
public Map<string, object=""> startLoutong(Map<string, object=""> paramMap) {
String redisKey = "qpsList";
Integer times = 100;
if (paramMap.containsKey("times")) {
times = Integer.valueOf(paramMap.get("times").toString());
}
Long size = redisTemplate.opsForList().size(redisKey);
if (size >= times) {
throw new RuntimeException("qps refuse request");
}
Long aLong = redisTemplate.opsForList().rightPush(redisKey, paramMap);
if (aLong > times) {
//为了防止并发场景。这里添加完成之后也要验证。 即使这样本段代码在高并发也有问题。此处演示作用
redisTemplate.opsForList().trim(redisKey, 0, times-1);
throw new RuntimeException("qps refuse request");
}
Map<string, object=""> map = new HashMap<>();
map.put("success", "success");
return map;
}
下游消费
@Component
public class SchedulerTask {
@Autowired
RedisTemplate redisTemplate;
private String redisKey="qpsList";
@Scheduled(cron="*/1 * * * * ?")
private void process(){
//一次性消费两个
System.out.println("正在消费。。。。。。");
redisTemplate.opsForList().trim(redisKey, 2, -1);
}
}
测试
令牌桶和漏桶法是一样的。只不过将桶的作用方向改变了一下。
漏桶的出水速度是恒定的,如果流量突然增加的话我们就只能拒绝入池
但是令牌桶是将令牌放入桶中,我们知道正常情况下令牌就是一串字符当桶满了就拒绝令牌的入池,但是面对高流量的时候正常加上我们的超时时间就留下足够长的时间生产及消费令牌了。这样就尽可能的不会造成请求的拒绝
最后,不论是对于令牌桶拿不到令牌被拒绝,还是漏桶的水满了溢出,都是为了保证大部分流量的正常使用,而牺牲掉了少部分流量
public Map<string, object=""> startLingpaitong(Map<string, object=""> paramMap) {
String redisKey = "lingpaitong";
String token = redisTemplate.opsForList().leftPop(redisKey).toString();
//正常情况需要验证是否合法,防止篡改
if (StringUtils.isEmpty(token)) {
throw new RuntimeException("令牌桶拒绝");
}
Map<string, object=""> map = new HashMap<>();
map.put("success", "success");
return map;
}
@Scheduled(cron="*/1 * * * * ?")
private void process(){
//一次性生产两个
System.out.println("正在消费。。。。。。");
for (int i = 0; i < 2; i++) {
redisTemplate.opsForList().rightPush(redisKey, i);
}
}
到此这篇关于基于redis实现的四种常见的限流策略的文章就介绍到这了,更多相关redis 限流策略内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: redis实现的四种常见限流策略
本文链接: https://www.lsjlt.com/news/128454.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0