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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 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
相关文章
|
7天前
|
监控 算法 网络协议
Java 实现局域网电脑屏幕监控算法揭秘
在数字化办公环境中,局域网电脑屏幕监控至关重要。本文介绍用Java实现这一功能的算法,涵盖图像采集、数据传输和监控端显示三个关键环节。通过Java的AWT/Swing库和Robot类抓取屏幕图像,使用Socket进行TCP/IP通信传输图像数据,并利用ImageIO类在监控端展示图像。整个过程确保高效、实时和准确,为提升数字化管理提供了技术基础。
40 15
|
2月前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
43 6
|
2月前
|
设计模式 Java 开发者
Java中的异常处理:理解与实践
【10月更文挑战第42天】在Java的世界中,异常处理是每个开发者必须面对的挑战。它就像是一场不可预知的风暴,可能会在任何时候突然降临,打乱我们的计划。但是,如果我们能够掌握正确的处理方法,这场风暴也可以变成推动我们前进的力量。本文将带你深入理解Java中的异常处理机制,通过代码示例,我们将一起学习如何捕获、处理和预防异常,让你的程序在面对任何挑战时都能保持稳健和优雅。
|
5天前
|
NoSQL 算法 Java
Java Redis多限流
通过本文的介绍,我们详细讲解了如何在Java中使用Redis实现三种不同的限流策略:固定窗口限流、滑动窗口限流和令牌桶算法。每种限流策略都有其适用的场景和特点,根据具体需求选择合适的限流策略可以有效保护系统资源和提高服务的稳定性。
34 18
|
1月前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
163 30
|
13天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
25 6
|
2月前
|
Arthas 监控 Java
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
本文介绍了阿里云 Java Agent 4.x 版本在基于 OTel Java Agent 二次开发过程中的实践与思考,并重点从功能、性能、稳定性、兼容性四个方面介绍了所做的工作。同时也介绍了阿里云可观测团队积极参与开源建设取得的丰厚成果。
248 7
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
|
1月前
|
存储 算法
深入解析PID控制算法:从理论到实践的完整指南
前言 大家好,今天我们介绍一下经典控制理论中的PID控制算法,并着重讲解该算法的编码实现,为实现后续的倒立摆样例内容做准备。 众所周知,掌握了 PID ,就相当于进入了控制工程的大门,也能为更高阶的控制理论学习打下基础。 在很多的自动化控制领域。都会遇到PID控制算法,这种算法具有很好的控制模式,可以让系统具有很好的鲁棒性。 基本介绍 PID 深入理解 (1)闭环控制系统:讲解 PID 之前,我们先解释什么是闭环控制系统。简单说就是一个有输入有输出的系统,输入能影响输出。一般情况下,人们也称输出为反馈,因此也叫闭环反馈控制系统。比如恒温水池,输入就是加热功率,输出就是水温度;比如冷库,
293 15
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
1月前
|
安全 Java 数据库连接
Java中的异常处理:理解与实践
在Java的世界里,异常处理是维护代码健壮性的守门人。本文将带你深入理解Java的异常机制,通过直观的例子展示如何优雅地处理错误和异常。我们将从基本的try-catch结构出发,探索更复杂的finally块、自定义异常类以及throw关键字的使用。文章旨在通过深入浅出的方式,帮助你构建一个更加稳定和可靠的应用程序。
34 5