常用的限流工具Guava RateLimiter 或Redisson RRateLimiter

在分布式系统和高并发场景中,限流是一个非常常见且重要的需求。以下是一些常用的限流工具和库,包括它们的特点和使用场景:

1. Guava RateLimiter

Google 的 Guava 库中的 RateLimiter 是一个简单且高效的限流工具,适用于单节点应用。

优点:

  • 易于使用
  • 高效

缺点:

  • 仅适用于单节点环境,不支持分布式限流

示例代码:

import com.google.common.util.concurrent.RateLimiter;

public class GuavaRateLimiterExample {
    public static void main(String[] args) {
        // 创建一个每秒允许10个请求的RateLimiter
        RateLimiter rateLimiter = RateLimiter.create(10.0);
        
        for (int i = 0; i < 20; i++) {
            // 尝试获取一个许可
            if (rateLimiter.tryAcquire()) {
                System.out.println("Acquired permit " + (i + 1));
                // 执行限流操作
            } else {
                System.out.println("Could not acquire permit " + (i + 1));
            }
        }
    }
}

2. Redis + Lua 脚本

使用 Redis 和 Lua 脚本可以实现分布式限流,因为 Redis 本身是一个高性能的分布式缓存和存储系统。

优点:

  • 支持分布式
  • 高性能

缺点:

  • 实现复杂度较高,需要编写和维护 Lua 脚本

示例代码(Lua脚本):

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")

if current + 1 > limit then
    return 0
else
    redis.call("INCRBY", key, 1)
    redis.call("EXPIRE", key, 1)
    return 1
end

Java代码调用Lua脚本:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class RedisRateLimiter {
    private JedisPool jedisPool;

    public RedisRateLimiter(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    public boolean tryAcquire(String key, int limit) {
        try (Jedis jedis = jedisPool.getResource()) {
            String luaScript = "..."; // 上述Lua脚本内容
            Object result = jedis.eval(luaScript, 1, key, String.valueOf(limit));
            return result.equals(1L);
        }
    }
}

3. Redisson RRateLimiter

Redisson 是一个基于 Redis 的 Java 客户端,提供了多种分布式数据结构和服务,其中包括 RRateLimiter 用于分布式限流。

优点:

  • 支持分布式
  • 使用方便,集成良好

缺点:

  • 依赖 Redis

示例代码:

import org.redisson.Redisson;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonRateLimiterExample {
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");

        RedissonClient redisson = Redisson.create(config);

        RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
        rateLimiter.trySetRate(RRateLimiter.RateType.OVERALL, 5, 1, RateIntervalUnit.SECONDS);

        for (int i = 0; i < 10; i++) {
            if (rateLimiter.tryAcquire()) {
                System.out.println("Acquired permit " + (i + 1));
            } else {
                System.out.println("Could not acquire permit " + (i + 1));
            }
        }

        redisson.shutdown();
    }
}

      <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
        </dependency>


spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: redis://xxxxx:6383
          connectionPoolSize: 30
          connectionMinimumIdleSize: 30
          password: xxx
          database: 0
          connectTimeout: 1000
          timeout: 500
          retryAttempts: 3
          retryInterval: 1000
        threads: 10
        nettyThreads: 10
        transportMode: NIO



@Component
@Configuration
public class XXXControlConfig {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private xxxControlProperties xxxControlProperties;

    /**
     * 拆章滑动窗口
     */
    @Bean
    public RRateLimiter rateLimiter() {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter("xxx");

        rateLimiter.trySetRate(RateType.OVERALL,
                               flowControlProperties.getRate().getInterval(),
                               flowControlProperties.getRate().getPermits(),
                               RateIntervalUnit.MINUTES);

        return rateLimiter;
    }

    /**
     * 试听最大并发数
     */
    @Bean
    public RSemaphore semaphore() {
        RSemaphore semaphore = redissonClient.getSemaphore("xxxxx");
        semaphore.trySetPermits(flowControlProperties.getSemaphore().getPermits());
        return semaphore;
    }




    @Autowired
    private RRateLimiter rateLimiter;



     if(flowControlProperties.getRate().isEnabled() && !rateLimiter.tryAcquire()) {
            throw new SystemException(Code, "系统繁忙,请稍后再试");
        }

4. Bucket4j

Bucket4j 是一个 Java 限流库,提供了灵活的令牌桶算法实现,可用于本地或分布式限流(通过第三方存储如 Hazelcast)。

优点:

  • 灵活
  • 支持多种存储后端

缺点:

  • 配置相对复杂

示例代码:

import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.Refill;

import java.time.Duration;

public class Bucket4jExample {
    public static void main(String[] args) {
        Bandwidth limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofSeconds(1)));
        Bucket bucket = Bucket4j.builder().addLimit(limit).build();

        for (int i = 0; i < 20; i++) {
            if (bucket.tryConsume(1)) {
                System.out.println("Acquired permit " + (i + 1));
            } else {
                System.out.println("Could not acquire permit " + (i + 1));
            }
        }
    }
}

这些工具各有优缺点,可以根据你的具体需求选择合适的限流工具。如果你需要分布式限流,推荐使用 Redis 相关的解决方案,如 Redisson 或者自定义 Lua 脚本。如果是单节点应用,Guava 的 RateLimiter 或 Bucket4j 都是不错的选择。

相关推荐
天之涯上上4 分钟前
JAVA开发 在 Spring Boot 中集成 Swagger
java·开发语言·spring boot
2402_857583495 分钟前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
白宇横流学长6 分钟前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
APP 肖提莫9 分钟前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
kirito学长-Java11 分钟前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端
爱学习的白杨树11 分钟前
MyBatis的一级、二级缓存
java·开发语言·spring
Code成立22 分钟前
《Java核心技术I》Swing的网格包布局
java·开发语言·swing
中草药z28 分钟前
【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)
java·数据库·spring boot·spring·bean·源码阅读
信徒_35 分钟前
常用设计模式
java·单例模式·设计模式
神仙别闹41 分钟前
基于C#实现的(WinForm)模拟操作系统文件管理系统
java·git·ffmpeg