博客
关于我
[整理] 使用RateLimiter完成简单的大流量限流,抢购秒杀限流
阅读量:425 次
发布时间:2019-03-06

本文共 3055 字,大约阅读时间需要 10 分钟。

RateLimiter:基于令牌桶算法的限流解决方案

RateLimiter 是 Guava 库中基于令牌桶算法实现的限流工具,简单易用,适合根据系统需求调整令牌生成速率。它在抢购限流、网速限制等场景中表现出色。

1. 多任务处理:按秒限流

假设系统每秒最多允许处理 X 个任务,RateLimiter 可以帮助实现这个目标。通过创建一个 RateLimiter 实例,并在每个任务启动前调用 acquire 方法,可以确保每秒不超过指定数量的任务执行。

import com.google.common.util.concurrent.RateLimiter;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Demo1 {    public static void main(String[] args) {        RateLimiter rateLimiter = RateLimiter.create(0.5); // 每秒最多 0.5 个令牌        List
tasks = new ArrayList<>(); for (int i = 0; i < 10; i++) { tasks.add(new UserRequest(i)); } ExecutorService threadPool = Executors.newCachedThreadPool(); for (Runnable runnable : tasks) { System.out.println("等待时间:" + rateLimiter.acquire()); threadPool.execute(runnable); } } private static class UserRequest implements Runnable { private int id; public UserRequest(int id) { this.id = id; } public void run() { System.out.println(id); } }}

运行结果表明,每 2 秒最多执行 1 个任务。通过 acquire 方法可以获取等待时间,确保无过度负载。

2. 抢购场景限流

在抢购场景中,RateLimiter 可以防止系统被过度负载。例如,数据库每秒可处理 10 个请求,超过限制会导致故障。

package com.tianyalei.controller;import com.google.common.util.concurrent.RateLimiter;import com.tianyalei.model.GoodInfo;import com.tianyalei.service.GoodInfoService;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestControllerpublic class IndexController {    @Resource(name = "db")    private GoodInfoService goodInfoService;    RateLimiter rateLimiter = RateLimiter.create(10);    @RequestMapping("/miaosha")    public Object miaosha(int count, String code) {        System.out.println("等待时间" + rateLimiter.acquire());        if (goodInfoService.update(code, count) > 0) {            return "购买成功";        }        return "购买失败";    }    @RequestMapping("/add")    public Object add() {        for (int i = 0; i < 100; i++) {            GoodInfo goodInfo = new GoodInfo();            goodInfo.setCode("iphone" + i);            goodInfo.setAmount(100);            goodInfoService.add(goodInfo);        }        return "添加成功";    }}

测试显示,每秒前 10 个请求无需等待,后续请求每 0.1 秒一个,符合预期效果。

3. 抢购场景降级

直接使用 RateLimiter 可能导致用户等待,影响体验。通过 tryAcquire 方法设置超时,确保在指定时间内无法获取令牌时立即返回失败。

@RequestMapping("/buy")public Object miao(int count, String code) {    // 非阻塞获取令牌    if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {        System.out.println("短期无法获取令牌,真不幸,排队也瞎排");        return "失败";    }    if (goodInfoService.update(code, count) > 0) {        System.out.println("购买成功");        return "成功";    }    System.out.println("数据不足,失败");    return "失败";}

在实际测试中,每秒大约有 22 个成功请求,78 个失败。通过降级策略,用户体验得到了显著提升。

补充:实际应用测试

部署到线上服务器后,测试结果如下:

  • 仅限流测试:数据库 CPU 占用率约 20%,Tomcat 超时较多。
  • 使用 RateLimiter 阻塞:数据库 CPU 不动,压力减少,但 Tomcat 超时仍有。
  • 使用非阻塞限流:QPS显著提升,压力降低,系统性能更优。
  • 通过 RateLimiter 的非阻塞方式,可以更好地控制流量,提升系统性能。

    转载地址:http://hhcuz.baihongyu.com/

    你可能感兴趣的文章
    POJ 1006
    查看>>
    Quartz中时间表达式的设置-----corn表达式
    查看>>
    poj 1035
    查看>>
    POJ 1061 青蛙的约会 (扩展欧几里得)
    查看>>
    Quartz2.2.1简单使用
    查看>>
    POJ 1080 Human Gene Functions(DP:LCS)
    查看>>
    Quant 开源项目教程
    查看>>
    POJ 1088 滑雪
    查看>>
    POJ 1095 Trees Made to Order
    查看>>
    POJ 1113 Wall(计算几何--凸包的周长)
    查看>>
    poj 1125Stockbroker Grapevine(最短路)
    查看>>
    Qualitor processVariavel.php 未授权命令注入漏洞复现(CVE-2023-47253)
    查看>>
    poj 1151 (未完成) 扫描线 线段树 离散化
    查看>>
    POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
    查看>>
    poj 1163 数塔
    查看>>
    POJ 1177 Picture(线段树:扫描线求轮廓周长)
    查看>>
    Qualitor checkAcesso.php 任意文件上传漏洞复现(CVE-2024-44849)
    查看>>
    POJ 1182 食物链(并查集拆点)
    查看>>
    POJ 1185 炮兵阵地 (状态压缩DP)
    查看>>
    POJ 1195 Mobile phones
    查看>>