【Java】-3种限流算法及实践

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,倚天版 1GB 1个月
简介: 3种限流算法及实践

image.png

限流算法

  • 计数器算法 维护一个 counter,规定在单位时间内 counter 的大小不能超过最大值,每隔固定时间就将 counter 的值置零。如果这个 counter 大于设定的阈值,那么系统就拒绝请求
  • 漏桶算法
    image.png
  • 漏桶算法维护一个固定容量的桶,这个桶会按照指定的速度漏水。请求到达系统就类似于将水加入桶中,这个速度可以是匀速的也可以是瞬间的,如果这个桶满了,就会忽略后面的请求,直到这个桶可以存放多余的水。
    好处:可以将系统的处理能力维持在一个比较平稳的水平
    缺点:瞬间流量过来时,如果满了就会拒绝后面的请求流量
  • 令牌桶算法
    image.png令牌桶算法系统按照指定的速度往桶中添加 token,每来一个请求,就从桶里拿走一个 token,如果没有 token 就拒绝服务
    好处:控制系统的处理速度,通过统计信息实时优化令牌桶的大小
    与漏桶算法的区别:
    令牌桶算法由于在令牌桶里攒了很多令牌,因此在大流量到达的瞬间可以一次性将队列中所有的请求都处理完,然后按照恒定的速度处理请求
    漏桶算法是一直有一个恒等阈值,在大流量到达的时候,也会将多余的请求拒绝

限流实践

guava 的 concurrent 中有一个限流工具类 RateLimiter,其实现了单机限流,使用了令牌桶算法,它支持两种令牌获取接口:获取不到一直阻塞;在指定时间内获取不到就阻塞,超过这个时间就返回获取失败

  1. 使用 RateLimiter,单机限流
//初始化令牌桶大小,初始大小为2000
private RateLimiter ratelimiter = RateLimiter.create(2000);
public void process() {
 //获取令牌,获取不到就阻塞
 rateLimiter.acquire();
 //执行业务操作,例如写数据库
 bizLogic();
}

如果请求可以丢弃,防止大量请求过来耗尽系统资源,可以使用 tryAcquire()方法,和带超时的 tryAcquire(),在指定时间内获取不到令牌就返回 false

private RateLimiter rateLimiter = RateLimiter.create(2000);
if(rateLimiter.tryAcquire()) {
   doSomething();
} else {
   doSomethingElse();
}

RateLimiter 详细分析可见:https://www.jianshu.com/p/362d261115e7

  1. 使用 Redis, 分布式限流
    比如 1 秒内请求数量限制在 2000 内
  • 使用 Redis 实现计数器算法
    设置 redis 可以的过期时间为 1 秒,每次请求过来 value 加 1,如果 value 超过 2000 就拒绝访问,使用 Lua 脚本实现 incr 和 expire 的原子性
local key =KEYS\[1\]
local expire_time =ARGV\[1\]
local count =redis.call("INCR", key, 1)
if count == 1then
   redis.call("EXPIRE", key, expire_time)
end
return count
  • 使用 Redis 实现令牌桶算法
    使用 Redis 的 List 结构实现 定时任务执行,使用 rightPush 放入令牌,并保证令牌的唯一性
// 1S 的速率往令牌桶中添加 UUID,只为保证唯一性
@Scheduled(fixedDelay = 1000,initialDelay = 0)
public void setIntervalTimeTask(){
   redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
}

使用 leftPop 获取令牌

public Response limitFlow(Long id){
   Object result = redisTemplate.opsForList().leftPop("limit_list");
   if(result == null){
       return Response.ok("当前令牌桶中无令牌");
  }
   return Response.ok(articleDescription);
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6天前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
1天前
|
算法 NoSQL Java
spring cloud的限流算法有哪些?
【8月更文挑战第18天】spring cloud的限流算法有哪些?
10 3
|
1天前
|
Java 程序员
Java中的异常处理:理解与实践
在Java编程的世界中,异常处理是保持程序稳健运行的关键。本文将通过浅显易懂的语言和生动的比喻,带你了解Java的异常处理机制,从基础概念到高级应用,一步步深入探讨。我们将一起学习如何优雅地处理那些不请自来的错误信息,确保你的代码像经验丰富的舞者一样,即使在遇到绊脚石时也能从容不迫地继续前行。
|
2天前
|
机器学习/深度学习 人工智能 算法
【人工智能】传统语音识别算法概述,应用场景,项目实践及案例分析,附带代码示例
传统语音识别算法是将语音信号转化为文本形式的技术,它主要基于模式识别理论和数学统计学方法。以下是传统语音识别算法的基本概述
10 2
|
4天前
|
存储 设计模式 Java
Java中的if-else语句:深入解析与应用实践
Java中的if-else语句:深入解析与应用实践
|
3天前
|
算法 安全 Java
深入解析Java多线程:源码级别的分析与实践
深入解析Java多线程:源码级别的分析与实践
|
4天前
|
算法 Java
HanLP — HMM隐马尔可夫模型 -- 维特比(Viterbi)算法 --示例代码 - Java
HanLP — HMM隐马尔可夫模型 -- 维特比(Viterbi)算法 --示例代码 - Java
10 0
|
5天前
|
存储 缓存 Java
Java本地高性能缓存实践问题之定义Caffeine的缓存的问题如何解决
Java本地高性能缓存实践问题之定义Caffeine的缓存的问题如何解决
|
5天前
|
存储 缓存 Java
Java本地高性能缓存实践问题之使用@CachePut注解来更新缓存中的数据的问题如何解决
Java本地高性能缓存实践问题之使用@CachePut注解来更新缓存中的数据的问题如何解决
|
5天前
|
缓存 Java Spring
Java本地高性能缓存实践问题之的Spring Boot中启用缓存支持问题如何解决
Java本地高性能缓存实践问题之的Spring Boot中启用缓存支持问题如何解决