博客
关于我
[整理] 使用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/

    你可能感兴趣的文章
    OAuth2.0_授权服务配置_资源服务测试_Spring Security OAuth2.0认证授权---springcloud工作笔记146
    查看>>
    OAuth2.0_环境介绍_授权服务和资源服务_Spring Security OAuth2.0认证授权---springcloud工作笔记138
    查看>>
    OAuth2.0_环境搭建_Spring Security OAuth2.0认证授权---springcloud工作笔记139
    查看>>
    oauth2.0协议介绍,核心概念和角色,工作流程,概念和用途
    查看>>
    OAuth2授权码模式详细流程(一)——站在OAuth2设计者的角度来理解code
    查看>>
    OAuth2:项目演示-模拟微信授权登录京东
    查看>>
    OA系统多少钱?OA办公系统中的价格选型
    查看>>
    OA系统选型:选择好的工作流引擎
    查看>>
    OA项目之我的会议(会议排座&送审)
    查看>>
    OA项目之我的会议(查询)
    查看>>
    Object c将一个double值转换为时间格式
    查看>>
    object detection训练自己数据
    查看>>
    object detection错误Message type "object_detection.protos.SsdFeatureExtractor" has no field named "bat
    查看>>
    object detection错误之Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERROR
    查看>>
    object detection错误之no module named nets
    查看>>
    Object of type 'ndarray' is not JSON serializable
    查看>>
    Object Oriented Programming in JavaScript
    查看>>
    object references an unsaved transient instance - save the transient instance before flushing
    查看>>
    Object.keys()的详解和用法
    查看>>
    OBJECTIVE C (XCODE) 绘图功能简介(转载)
    查看>>