接口限流方案

由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统,必须采取流量控制措施。
服务接口的流量控制策略:分流、降级、限流 熔断
分流:扩容机器、单元化通道
降级:关闭非核心接口,保证核心接口链路的正常运行
限流:业务系统限流、数据库限流

常见的限流算法有:令牌桶、漏桶、Redis计数器。
下面用图说话吧 令牌桶算法
这里写图片描述

谷歌的guava库已经帮我们实现好了 有兴趣的朋友可以去看看源码

@Component
public class GuavaLimitSimpalDemo {
   
   

    private static final RateLimiter rateLimit 
### 验证码接口限流实现方案 对于验证码接口的限流处理,可以通过多种算法和技术手段来实现。以下是基于提供的引用内容以及专业知识整理的一个完整的解决方案。 #### 1. 使用令牌桶算法 令牌桶是一种常见的限流算法,适用于各种场景下的流量控制。通过设置固定的速率向桶中放入令牌,每次请求消耗一定数量的令牌。如果桶中的令牌不足,则拒绝该次请求[^2]。 ```java import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TokenBucket { private int capacity; // 桶容量 private double tokens; // 当前令牌数 private final double ratePerSecond; // 每秒新增令牌数 private long lastRefillTimestamp; // 上一次填充时间戳 public TokenBucket(int capacity, double ratePerSecond) { this.capacity = capacity; this.tokens = capacity; this.ratePerSecond = ratePerSecond; this.lastRefillTimestamp = System.currentTimeMillis(); } public synchronized boolean tryConsume(int numTokens) { refill(); // 填充令牌 if (tokens >= numTokens) { // 判断是否有足够的令牌 tokens -= numTokens; return true; } return false; } private void refill() { long now = System.currentTimeMillis(); double newTokens = (now - lastRefillTimestamp) / 1000 * ratePerSecond; tokens = Math.min(capacity, tokens + newTokens); lastRefillTimestamp = now; } } ``` 上述代码展示了如何创建一个简单的令牌桶类,并提供了一个 `tryConsume` 方法用于判断当前请求是否可以被允许执行。 --- #### 2. 结合AOP与注解的方式 为了提高开发效率并减少重复代码,在Spring Boot项目中可以利用面向切面编程(AOP)配合自定义注解完成限流逻辑。这种方式使得开发者只需在目标方法上添加特定注解即可启用限流功能。 ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RateLimit { String keyPrefix() default ""; // 缓存key前缀 int limit() default 100; // 请求上限 int timeUnit() default 60; // 时间窗口大小(单位:秒) } @Aspect @Component public class RateLimitInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Around("@annotation(rateLimit)") public Object handleRateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable { String key = generateKey(joinPoint, rateLimit.keyPrefix()); Integer count = getCountFromRedis(key); if (count != null && count > rateLimit.limit()) { throw new RuntimeException("超出访问频率限制"); } else { incrementCountInRedis(key, rateLimit.timeUnit()); return joinPoint.proceed(); } } private String generateKey(ProceedingJoinPoint joinPoint, String prefix) { StringBuilder sb = new StringBuilder(prefix).append("_").append(joinPoint.getSignature().toShortString()); return sb.toString(); } private Integer getCountFromRedis(String key) { ValueOperations<String, Object> ops = redisTemplate.opsForValue(); return ops.get(key) == null ? 0 : (Integer) ops.get(key); } private void incrementCountInRedis(String key, int expireInSeconds) { ValueOperations<String, Object> ops = redisTemplate.opsForValue(); ops.increment(key, 1); // 自增计数器 redisTemplate.expire(key, expireInSeconds, TimeUnit.SECONDS); // 设置过期时间 } } ``` 此部分实现了基于Redis存储状态信息的功能,能够有效应对分布式环境下的需求[^4]。 --- #### 3. 考虑滑动窗口策略 除了传统的固定窗口外,还可以采用更精确的滑动窗口机制进一步优化限流效果。这种方法会将统计周期划分为若干子区间,从而避免因突发流量而误触阈值的情况发生[^3]。 ```java class SlidingWindowRateLimiter { private static final int WINDOW_SIZE_MS = 1000; // 统计窗口长度(毫秒) private static final int BUCKET_COUNT = 10; // 子区间的数目 private List<Long[]> buckets = new ArrayList<>(BUCKET_COUNT); public SlidingWindowRateLimiter() { for (int i = 0; i < BUCKET_COUNT; ++i) { buckets.add(new Long[] {System.currentTimeMillis(), 0L}); } } public synchronized boolean allowRequest(long maxRequestsAllowedWithinWindow) { long currentTimeMillis = System.currentTimeMillis(); // 清理旧数据 while (!buckets.isEmpty() && currentTimeMillis - buckets.get(0)[0] > WINDOW_SIZE_MS) { buckets.remove(0); } // 更新最新一条记录的时间戳和次数 Long[] latestEntry = buckets.size() > 0 ? buckets.get(buckets.size()-1):null; if(latestEntry!=null&&currentTimeMillis-latestEntry[0]<WINDOW_SIZE_MS/BUCKET_COUNT){ latestEntry[1]++; }else{ buckets.add(new Long[]{currentTimeMillis,1L}); } // 计算总请求数量 long totalRequests = buckets.stream().mapToLong(entry -> entry[1]).sum(); return totalRequests <= maxRequestsAllowedWithinWindow; } } ``` 以上即为一种典型的滑动窗口限流器设计思路。 --- #### 总结 综上所述,针对验证码接口实施有效的限流措施可以从以下几个方面入手: - **选择合适的算法**:如令牌桶或漏斗模型; - **引入缓存工具支持分布式的高效协作**:推荐使用Redis作为中间件; - **简化编码流程**:借助AOP技术封装复杂的业务细节于框架内部; 最终目的是既保障用户体验又能维持服务端稳定运行。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值