java单机接口限流处理方案详解

作者:景川呀 时间:2021-05-25 21:08:07 

对单机服务做接口限流的处理方案

简单说就是设定某个接口一定时间只接受固定次数的请求,比如/add接口1秒最多接收100次请求,多的直接拒绝,这个问题很常见,场景也好理解,直接上代码:


/**
* 单机限流
*/
@Slf4j
public class FlowLimit {

//接口限流上限值和限流时间缓存
   private static Cache<String, AtomicLong> localCache = CacheBuilder.newBuilder().maximumSize(100)
           .expireAfterWrite(1000, TimeUnit.MILLISECONDS).build();

//每个接口的上限缓存
   private static Map<String, Long> maxFlowLimitMap = new ConcurrentHashMap<>();

private static final FlowLimit instance = new FlowLimit();

//这块的目的是初始化每个接口的上限,下面的变量:apiFlowLimitConfigure
//实际使用的时候应该是从db或者其他地方获取设置的每个接口的限流上限值,
//这样可以动态的调整接口上限,比如直接修改db,不用发布,就可以调整接口限流值
   static {
       new ScheduledThreadPoolExecutor(1, runnable -> {
           Thread thread = new Thread(runnable, "api-flowLimit-configure");
//            thread.setDaemon(true);
           return thread;
       }).scheduleAtFixedRate(() -> {
           try {
               String apiFlowLimitConfigure = "{\"doAdd\":100}";  //表示/doAdd接口1秒接受100次请求
               Map mapObj = JSONObject.parseObject(apiFlowLimitConfigure, Map.class);
               if(mapObj != null){
                   mapObj.forEach((key, value) -> {
                       if(value != null){
                           instance.setMaxFlowLimit(key.toString(), new Long(value.toString()));
                       }else{
                           log.warn(key + " - 设置接口限流发现限流值为空,设置默认值");
                           instance.setMaxFlowLimit(key.toString(), 100L);
                       }
                   });
               }
           } catch (Exception e) {
               log.error("设置接口限流出现异常{}", e);
           }
       }, 0, 3, TimeUnit.SECONDS);
   }

public static FlowLimit getInstance() {
       return instance;
   }

private FlowLimit setMaxFlowLimit(String key, Long maxFlowLimit) {
       maxFlowLimitMap.put(key, maxFlowLimit);
       return this;
   }

public Boolean isAvailable(String key) {
       return checkAvailable(key, 1L);
   }

public Boolean isAvailable(String key, Long incrNum) {
       return checkAvailable(key, incrNum);
   }

private Boolean checkAvailable(String key, Long incrNum){
       Long maxFlowLimit = maxFlowLimitMap.get(key);
       if (null == maxFlowLimit || maxFlowLimit == 0) {
           return true;
       }
       if (incrAndGet(key, incrNum) <= maxFlowLimit.longValue()) {
           return true;
       } else {
           return false;
       }
   }

private long incrAndGet(String key, final long n) {
       try {
           return localCache.get(key, new Callable<AtomicLong>() {
               @Override
               public AtomicLong call() throws Exception {
                   return new AtomicLong(0);
               }
           }).addAndGet(n);
       } catch (Exception e) {
           log.error(e.getMessage(), e);
       }
       return 0;
   }

public long get(String key) {
       return incrAndGet(key, 0);
   }

}

上面这个就是单机限流逻辑,代码不难,感觉没必要使用ConcurrentHashMap,不过感觉无所谓了
这段代码只需要加在需要限流的接口前面:


@GetMapping("doAdd")
public Boolean doAdd(){
   FlowLimit instance = FlowLimit.getInstance(); //单例获取
   //查看当前的/doAdd接口是否触发了限流
   Boolean flowLimitFlag = instance.isAvailable("doAdd");
   if(!flowLimitFlag){
       log.warn("触发限流,拒绝请求");
       return false;
   }
   //doAdd()
   return true;
}

调用实例如上

上面这个限流其实是有一定问题的:比如你限定10秒钟1000次,在第9.9秒的时候,突然进来1000个请求,然后第10.1秒的时候,攻击者,又进来1000次请求,这样,0.2秒之内,进来2000次请求。。。
所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写

没怎么仔细测试,有问题欢迎提出,共同学习

来源:https://blog.csdn.net/qq_34203492/article/details/103246119

标签:java,单机,接口限流
0
投稿

猜你喜欢

  • Spring boot jpa 删除数据和事务管理的问题实例详解

    2022-07-02 12:11:43
  • Java编写简单猜数游戏

    2021-09-09 01:38:49
  • Java Swing组件编程之JTable表格用法实例详解

    2022-12-23 01:49:26
  • 解决Jenkins集成SonarQube遇到的报错问题

    2023-11-24 08:54:10
  • 如何基于java实现Gauss消元法过程解析

    2023-12-15 21:51:08
  • 一文带你了解SpringBoot的启动原理

    2023-11-28 20:44:42
  • C++实现LeetCode(159.最多有两个不同字符的最长子串)

    2023-06-20 22:39:46
  • SQLite在C#中的安装与操作技巧

    2023-04-19 08:31:12
  • Kafka 日志存储实现过程

    2021-11-01 05:04:00
  • Java如何实现简单后台访问并获取IP

    2021-10-27 02:26:27
  • 使用@PropertySource读取配置文件通过@Value进行参数注入

    2021-11-21 13:21:03
  • springboot如何读取自定义properties并注入到bean中

    2022-12-16 22:22:09
  • Java JDK动态代理实现原理实例解析

    2022-04-23 05:19:10
  • Spring interceptor拦截器配置及用法解析

    2023-06-26 06:08:15
  • 浅谈springBoot注解大全

    2023-11-09 15:02:56
  • Java 面试题和答案 -(上)

    2023-10-08 08:15:56
  • Spring Boot JPA中使用@Entity和@Table的实现

    2023-11-22 11:49:58
  • 详解Java内部类与对象的打印概念和流程

    2021-10-10 21:36:56
  • springboot使用JPA时间类型进行模糊查询的方法

    2023-10-26 21:59:02
  • 使用SpringBoot 工厂模式自动注入到Map

    2021-12-22 10:02:42
  • asp之家 软件编程 m.aspxhome.com