Guava RateLimiter 限流原理解析与实战应用

限流算法概述

在高并发系统中,限流是保护服务稳定性的重要手段。常用的限流算法主要有两种:

漏桶算法

漏桶算法以固定速率处理请求,像水从漏桶中匀速流出一样,能够平滑网络流量,但无法应对突发流量。

令牌桶算法

令牌桶算法以固定速率向桶中添加令牌,请求处理前需要获取令牌,只有拿到令牌的请求才会被处理。这种算法既能够限制平均速率,又允许一定程度的突发流量,更加灵活实用。

Guava RateLimiter 深度解析

核心原理

Guava RateLimiter 基于令牌桶算法实现,其工作原理如下图所示:

https://example.com/ratelimiter-diagram.png

系统以固定频率向令牌桶中添加令牌(例如每秒10个),业务请求在处理前需要从桶中获取令牌。获取令牌的方式支持两种模式:

  • 阻塞等待:直到成功获取令牌
  • 立即返回:获取失败时直接返回,不等待

实战应用

下面通过完整的Spring MVC示例演示RateLimiter的实际应用。

1. 添加Maven依赖
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
2. 限流服务封装

将限流逻辑封装到独立的服务类中,提高代码复用性:

@Service
public class AccessLimitService {
    
    // 创建每秒产生5个令牌的限流器
    private final RateLimiter rateLimiter = RateLimiter.create(5.0);
    
    /**
     * 尝试获取令牌(非阻塞方式)
     * @return true-获取成功,false-获取失败
     */
    public boolean tryAcquire() {
        return rateLimiter.tryAcquire();
    }
    
    /**
     * 阻塞方式获取令牌
     * @return 等待时间(秒)
     */
    public double acquire() {
        return rateLimiter.acquire();
    }
}
3. Controller层实现
@Controller
public class HelloController {
    
    private static final SimpleDateFormat sdf = 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    @Autowired
    private AccessLimitService accessLimitService;
    
    @RequestMapping("/access")
    @ResponseBody
    public String access() {
        // 尝试获取令牌
        if (accessLimitService.tryAcquire()) {
            // 模拟业务处理耗时500毫秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return "thread interrupted";
            }
            return "access success [" + sdf.format(new Date()) + "]";
        } else {
            return "access limit [" + sdf.format(new Date()) + "]";
        }
    }
}
4. 并发测试验证

创建测试客户端验证限流效果:

public class AccessClient {
    private final ExecutorService fixedThreadPool = 
        Executors.newFixedThreadPool(10);
    
    /**
     * 发送HTTP GET请求
     */
    public static String sendGet(URL url) {
        StringBuilder result = new StringBuilder();
        try (BufferedReader in = new BufferedReader(
            new InputStreamReader(url.openConnection().getInputStream()))) {
            
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常: " + e.getMessage());
        }
        return result.toString();
    }
    
    public void access() throws Exception {
        final URL url = new URL("http://localhost:8080/guavalimitdemo/access");
        
        // 提交10个并发请求
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.submit(() -> {
                System.out.println(sendGet(url));
            });
        }
        
        fixedThreadPool.shutdown();
        fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
    }
    
    public static void main(String[] args) throws Exception {
        AccessClient client = new AccessClient();
        client.access();
    }
}

测试结果分析

运行测试程序后,部分请求成功获取令牌并执行,其余请求因无法获取令牌而被限流。值得注意的是,虽然配置的是每秒5个令牌,但实际可能会允许稍多的请求通过,这是因为RateLimiter在设计上允许一定的突发流量。

RateLimiter API 详解

核心方法说明

方法描述
double acquire()获取1个许可,阻塞直到获取成功
double acquire(int permits)获取指定数量的许可,阻塞直到获取成功
static RateLimiter create(double permitsPerSecond)创建固定速率的限流器
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)创建含预热期的限流器
double getRate()获取配置的稳定速率(许可数/秒)
void setRate(double permitsPerSecond)动态更新速率
boolean tryAcquire()尝试获取1个许可,立即返回结果
boolean tryAcquire(int permits)尝试获取指定数量许可,立即返回结果
boolean tryAcquire(long timeout, TimeUnit unit)在指定超时时间内尝试获取许可
boolean tryAcquire(int permits, long timeout, TimeUnit unit)在指定超时时间内尝试获取指定数量许可

使用示例

假设我们需要控制任务提交速率,确保每秒不超过2个任务:

public class TaskProcessor {
    // 创建每秒2个许可的限流器
    private final RateLimiter rateLimiter = RateLimiter.create(2.0);
    
    public void submitTasks(List<Runnable> tasks, Executor executor) {
        for (Runnable task : tasks) {
            rateLimiter.acquire(); // 可能需要阻塞等待
            executor.execute(task);
        }
    }
    
    public boolean trySubmitTask(Runnable task, Executor executor) {
        if (rateLimiter.tryAcquire()) {
            executor.execute(task);
            return true;
        }
        return false;
    }
}

进阶特性

预热模式

RateLimiter支持预热模式,在系统启动阶段平滑地增加处理速率:

// 创建预热型限流器:每秒10个许可,预热时间5秒
RateLimiter rateLimiter = RateLimiter.create(10.0, 5, TimeUnit.SECONDS);

在5秒的预热期内,RateLimiter会从较低速率逐渐增加到目标速率,避免冷启动时的流量冲击。

动态速率调整

RateLimiter支持运行时动态调整速率:

rateLimiter.setRate(20.0); // 将速率调整为每秒20个许可

注意事项

  1. 分布式环境限制:Guava RateLimiter适用于单机限流场景,分布式系统需要结合Redis等中间件实现集群限流。
  2. 精度考虑:虽然配置的是每秒N个令牌,但实际可能会有N+1的突发通过量,这在设计系统容量时需要予以考虑。
  3. 资源清理:使用完毕后应及时关闭相关的线程池和资源。
  4. 异常处理:在生产环境中需要完善异常处理机制,确保限流器异常时不影响核心业务流程。

总结

Guava RateLimiter提供了强大而灵活的限流能力,通过令牌桶算法既保证了系统的平均处理速率,又允许合理的突发流量。本文通过原理分析、实战示例和API详解,展示了如何在实际项目中有效使用RateLimiter进行流量控制。对于分布式系统,可以基于类似的算法思想,结合分布式缓存实现集群级别的限流方案。

概要介绍: 本课程主要是介绍并实战一款java中间件~redisson,介绍redisson相关的核心技术栈及其典型的应用场景,其中的应用场景就包括布隆过滤器、限流器、短信发送、实时/定时邮件发送、数据字典、分布式服务调度等等,在业界号称是在java项目里正确使用redis的姿势。本课程的目标就在于带领各位小伙伴一起学习、攻克redisson,更好地巩固自己的核心竞争力,而至于跳槽涨薪,自然不在话下!  课程内容: 说起redisson,可能大伙儿不是很熟悉,但如果说起redis,想必肯定很多人都晓得。没错,这家伙字如其名,它就是架设在redis基础上的一款综合性的、新型的中间件,号称是java企业级应用开发中正确使用redis的姿势/客户端实例。 它是架设在redis基础之上,但拥有的功能却远远多于原生Redis 所提供的,比如分布式对象、分布式集合体系、分布式锁以及分布式服务调度等一系列具有分布式特性的对象实例… 而这些东西debug将在本门课程进行淋漓尽致的介绍并实战,除此之外,我们将基于spring boot2.0搭建的多模块项目实战典型的应用场景:对象存储、数据字典、短信发送、实时/定时邮件发送、布隆过滤器、限流组件、分布式服务调度....课程大纲如下所示: 下面罗列一下比较典型的核心技术栈及其实际业务场景的实战,如下图所示为redisson基于订阅-发布模式的核心技术~主题Topic的实际业务场景,即实时发送邮件: 而下图则是基于“多值映射MultiMap”数据结构实战实现的关于“数据字典”的缓存管理: 除此之外,我们还讲解了可以分布式服务调度中间件dubbo相媲美的功能:分布式远程服务调度,在课程中我们动手搭建了两个项目,用于分别充当“生产者”“消费者”角色,最终通过redisson的“服务调度组件”实现服务服务之间、接口接口之间的调用!  课程收益: (1)认识并掌握redisson为何物、常见的几种典型数据结构-分布式对象、集合、服务的应用及其典型应用场景的实战; (2)掌握如何基于spring boot2.0整合redisson搭建企业级多模块项目,并以此为奠基,实战企业级应用系统中常见的业务场景,巩固相应的技术栈! (3)站在项目管理技术精进的角度,掌握对于给定的功能模块进行业务流程图的绘制、分析、模块划分、代码实战性能测试和改进,提高编码能力其他软实力; (4)对于Java微服务、分布式、springboot精进者而言,学完本课程,不仅可以巩固提高中间件的实战能力,其典型的应用场景更有助于面试、助力相关知识点的扫盲! 如下图所示: 关键字:Spring Boot,Redis,缓存穿透,缓存击穿,缓存雪崩,红包系统,Mybatis,高并发,多线程并发编程,发送邮件,列表List,集合Set,排行榜,有序集合SortedSet,哈希Hash ,进阶实战,面试,微服务、分布式 适用人群:redisson学习者,分布式中间件实战者,微服务学习者,java学习者,spring boot进阶实战者,redis进阶实战
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今晚哒老虎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值