一、前言
在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流
1缓存 缓存的目的是提升系统访问速度和增大系统处理容量
2降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再打开
3限流 限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处
涉及到的技术:
(1)SpringBoot拦截器
(2)ScheduledThreadPoolExecutor定时任务
(3)Redis队列
(4)SpringBoot RedisTemplate操作redis
(5)jmeter测试工具
使用令牌桶算法实现接口限流

令牌桶算法(Token Bucket):随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token,如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务。
在SpringBoot项目中通过拦截器拦截增加了@LimitingRequired注解的接口查询是否有token来决定是否限制请求。
二、关键代码
@LimitingRequired注解
package com.asyf.demo.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LimitingRequired {
boolean required() default true;
}
常量类
package com.asyf.demo.common;
public class Constant {
public static final String TOKEN_BUCKET_KEY = "token_bucket";//令牌桶key
public static final Long TOKEN_BUCKET_SIZE = 10L;//令牌桶容量
}
类ApplicationRunnerImpl,此方法实现了向桶中添加令牌的功能
package com.asyf.demo.config;
import com.asyf.demo.common.Constant;
import com.asyf.demo.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
@ConfigurationProperties(
prefix = "server",
ignoreUnknownFields = true
)
public class ApplicationRunnerImpl implements ApplicationRunner {
private Integer port;
@Autowired
private RedisTemplate redisTemplate;
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("通过实现ApplicationRunner接口,在spring boot项目启动后打印参数");
String[] sourceArgs = args.getSourceArgs();
for (String arg : sourceArgs) {
System.out.print(arg + " ");
}
//给令牌桶添加令牌-分布式部署时只需要一个端口添加令牌桶即可
if (port.compareTo(8080) == 0) {
addTokenBucket();
}
}
private void addTokenBucket() {
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
Runnable runnable = new Runnable() {
@Override
public void run() {
ListOperations listOperations = redisTemplate.opsForList();
//获取队列的长度,当redis队列不存在返回0
Long size = listOperations.size(Constant.TOKEN_BUCKET_KEY);
if (size.compareTo(Constant.TOKEN_BUCKET_SIZE) == -1) {
long current

本文介绍如何在SpringBoot项目中使用令牌桶算法实现接口限流,通过自定义注解和拦截器控制请求频率,确保系统稳定运行。
最低0.47元/天 解锁文章
880

被折叠的 条评论
为什么被折叠?



