Guava RateLimiter:高效流量控制实践指南

网络 网络管理
在互联网飞速发展的今天,随着系统用户规模的不断扩大和分布式架构的广泛应用,API 接口的稳定性和性能成为系统设计中至关重要的因素。

背景

在互联网飞速发展的今天,随着系统用户规模的不断扩大和分布式架构的广泛应用,API 接口的稳定性和性能成为系统设计中至关重要的因素。无论是应对突发的流量高峰,还是防止恶意爬虫的恶意请求,限流策略都已成为现代系统不可或缺的一部分,其主要目的包括但不限于以下几点:

  1. 保护后端服务:通过限制单位时间内对特定接口的访问次数,可以有效避免因突发流量或恶意攻击导致的服务过载,从而确保后端服务的稳定运行。
  2. 保证用户体验:合理的限流策略可以在不影响正常用户使用的情况下,控制资源的合理分配,确保大多数用户的请求能够得到及时响应,提升整体服务质量。
  3. 资源优化利用:对于有限的计算资源,如数据库连接、缓存资源等,通过限流可以避免这些资源被少数高频率请求耗尽,确保资源的有效利用。
  4. 成本控制:云服务通常按照资源消耗计费,不当的请求可能会导致不必要的成本增加。限流可以帮助企业更好地控制成本,避免因为意外的高流量而导致的成本激增。
  5. 防止恶意行为:限流可以作为一道防线,阻止恶意爬虫、DDoS攻击等非法行为,保护系统免受损害。
  6. 数据安全:通过限制对外部数据的访问频率,可以减少敏感信息泄露的风险,特别是在处理个人隐私数据时尤为重要。
  7. 合规性:某些行业有特定的数据访问规则和限制,实施限流有助于满足这些合规要求,避免法律风险。

Guava 提供了多种实现限流的方法,其中最常用的是 RateLimiter 类。RateLimiter 可以帮助我们控制应用程序的资源消耗速度,例如限制每秒的请求数量。

实现

1.依赖引入:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version> 
</dependency>

2.application.yml 中配置限流参数:

rate-limiter:
  permits-per-second: 5       # 每秒许可数
  warmup-period: 0            # 预热时间(秒)
  timeout: 0                  # 获取许可的超时时间(秒)

3.限流配置属性类

@Data
@Component
@ConfigurationProperties(prefix = "rate-limiter")
public class RateLimiterProperties {

    /**
     * 每秒许可数
     */
    private double permitsPerSecond;

    /**
     * 预热时间(秒)
     */
    private long warmupPeriod;

    /**
     * 获取许可的超时时间(秒)
     */
    private long timeout;
}

4.配置 RateLimiter

@Configuration
public class RateLimiterConfig {

    /**
     * 配置 RateLimiter Bean
     *
     * @param properties 注入的限流配置属性
     * @return RateLimiter 实例
     */
    @Bean
    public RateLimiter rateLimiter(RateLimiterProperties properties) {
        if (properties.getWarmupPeriod() > 0) {
            // 创建带有预热期的 RateLimiter
            return RateLimiter.create(
                    properties.getPermitsPerSecond(),
                    properties.getWarmupPeriod(),
                    TimeUnit.SECONDS
            );
        } else {
            // 创建标准的 RateLimiter
            return RateLimiter.create(properties.getPermitsPerSecond());
        }
    }
}

5.创建控制器

@RestController
public class RateLimiterController {

    @Autowired
    private RateLimiter rateLimiter;

    @Autowired
    private RateLimiterProperties properties;

    /**
     * 测试限流接口
     *
     * @return 请求结果
     */
    @GetMapping("/api/test")  
    //@RateLimitAspect(qps = 2, timeout = 200, timeUnit = TimeUnit.MILLISECONDS)
    public ResponseEntity<String> rateApi() {
        boolean acquired = rateLimiter.tryAcquire(properties.getTimeout(), TimeUnit.SECONDS);
        if (acquired) {
            // 允许请求,返回成功响应
            return ResponseEntity.ok("请求成功!");
        } else {
            // 拒绝请求,返回限流响应
            return ResponseEntity.status(429).body("请求过多,请稍后再试!");
        }
    }
}

6.进阶版利用切面:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimitAspect {
    double qps() default 1; // 每秒钟生成令牌的速率
    long timeout() default 0; // 尝试获取令牌的超时时间
    TimeUnit timeUnit() default TimeUnit.SECONDS; // 超时时间单位
}
@Aspect
@Component
public class ApiRateLimitAspect {

    private final Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();

    @Before("@annotation(RateLimitAspect)")
    public void limit(JoinPoint joinPoint, RateLimitAspect rateLimitAspect) {
        String methodName = joinPoint.getSignature().toLongString();
        double qps = rateLimitAspect.qps();
        RateLimiter limiter = rateLimiters.computeIfAbsent(methodName, k -> RateLimiter.create(qps));
        long timeout = rateLimitAspect.timeout();
        TimeUnit timeUnit = rateLimitAspect.timeUnit();
        if (timeout > 0) {
            if (!limiter.tryAcquire(timeout, timeUnit)) {
                throw new RuntimeException("API rate limit exceeded");
            }
        } else {
            if (!limiter.tryAcquire()) {
                throw new RuntimeException("API rate limit exceeded");
            }
        }
    }
}


责任编辑:武晓燕 来源: 一安未来
相关推荐

2010-02-03 23:04:31

流量控制P2P华夏创新

2023-10-08 12:14:42

Sentinel流量控制

2022-06-22 09:07:09

Guava算法

2013-07-22 14:25:29

iOS开发ASIHTTPRequ

2011-06-23 09:09:37

流量控制

2014-12-25 09:47:59

GuavaGuava并发

2010-06-17 17:00:07

Linux流量控制

2021-03-09 07:38:15

Percona Xtr流量控制运维

2010-06-04 10:49:58

Linux流量控制

2021-03-22 08:06:59

SpringBootSentinel项目

2010-08-06 10:02:07

2019-07-02 10:22:15

TCP流量数据

2010-05-27 11:03:44

Linux流量控制

2010-06-04 11:21:42

Linux 流量控制

2009-02-05 10:13:00

局域网流量控制数据流量

2024-03-04 00:02:00

Redis存储令牌

2023-06-20 08:10:00

2010-11-30 09:40:15

流量控制设备AllotQOS策略

2009-10-27 20:14:15

数据传输流量控制网管技巧

2009-12-03 10:47:47

路由器功能介绍
点赞
收藏

51CTO技术栈公众号