解决推送每分钟六百次频率调用限制

  1 package com.hsjry.plutus.customer.web;
  2 
  3 import lombok.extern.slf4j.Slf4j;
  4 import org.springframework.scheduling.annotation.Scheduled;
  5 import org.springframework.stereotype.Component;
  6 import org.springframework.web.bind.annotation.RequestMapping;
  7 import org.springframework.web.bind.annotation.RestController;
  8 
  9 import java.util.Calendar;
 10 import java.util.Date;
 11 import java.util.concurrent.LinkedBlockingQueue;
 12 import java.util.concurrent.atomic.AtomicInteger;
 13 
 14 
 15 /**
 16  * 限流器 每分钟限制请求600次,用于解决推送,每分钟六百次的接口请求次数限制问题
 17  * @Auther: 屈艳锋
 18  * @Date: 2019/5/23 15:12
 19  */
 20 @Component
 21 @RestController
 22 @Slf4j
 23 public class CurrentLimiter {
 24 
 25     /**
 26      * 限流请求次数记录容器,用于记录前一分钟,当前分钟,后一分钟的请求次数
 27      */
 28     static AtomicInteger[] limitRequestCountRecordArray = {new AtomicInteger(0), new AtomicInteger(0), new AtomicInteger(0)};
 29 
 30     /**
 31      * 限流队列,用于存放超过请求次数限制的请求
 32      */
 33     static LinkedBlockingQueue limitScheduleQueue = new LinkedBlockingQueue<Integer>(1000);
 34 
 35 
 36     /**
 37      * 定时任务,每逢五十秒时,将后一分钟的请求次数初始化为0
 38      */
 39     @Scheduled(cron = "0/50 * * * * ?")
 40     public void initNextMiniuteValue() {
 41 
 42         //限流容器长度
 43         int limitArrayLength = limitRequestCountRecordArray.length;
 44 
 45         //获取当前分钟数据所在下标
 46         int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitArrayLength;
 47 
 48         //获取后一分钟数据所在下标
 49         int nextIndex = 0;
 50         if (currentIndex < limitArrayLength - 1) {
 51             nextIndex = currentIndex + 1;
 52         }
 53 
 54         //将后一分钟的请求次数初始化为0
 55         limitRequestCountRecordArray[nextIndex] = new AtomicInteger(0);
 56         log.info("执行是定时任务,当前分钟下标为{},请求次数为{}",currentIndex,limitRequestCountRecordArray[currentIndex].get());
 57     }
 58 
 59 
 60     /**
 61      * 测试每分钟六百次限流
 62      *
 63      * @return
 64      * @throws InterruptedException
 65      */
 66     @RequestMapping("/test")
 67     public String testLimiter() throws InterruptedException {
 68 
 69         for (int i = 0; i < 1000; i++) {
 70 
 71             //获取当前分钟数数据所在限流容器的下标
 72             int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitRequestCountRecordArray.length;
 73 
 74             //如果超过阀值,则放入队列
 75             if (limitRequestCountRecordArray[currentIndex].get() > 599) {
 76                 limitScheduleQueue.put(i);
 77             } else {
 78                 //当前分钟数数据加一
 79                 limitRequestCountRecordArray[currentIndex].incrementAndGet();
 80                 log.info("{}分钟正常调用{}", getMinute(new Date()), i);
 81             }
 82 
 83         }
 84 
 85         if (limitScheduleQueue.size() > 0) {
 86             new Thread(this::limitHandler).start();
 87         }
 88         return "";
 89     }
 90 
 91 
 92     /**
 93      * 限流处理
 94      *  
95
*/ 96 void limitHandler() { 97 98 log.info("=========>当前时间:{}", getMinute(new Date())); 99 for (int i = 0; i < limitScheduleQueue.size(); i++) { 100 101 //获取当前分钟数数据所在限流容器的下标 102 int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitRequestCountRecordArray.length; 103 104 //如果超过阀值,则不处理 105 if (limitRequestCountRecordArray[currentIndex].get() > 599) { 106 try { 107 log.info("{}分钟已超过限制,休息一会,稍微继续~~~",getMinute(new Date())); 108 Thread.sleep(60000); 109 } catch (InterruptedException e) { 110 } 111 } else { 112 //当前分钟数数据加一 113 limitRequestCountRecordArray[currentIndex].incrementAndGet(); 114 log.info("{}分钟正常调用中:{}", getMinute(new Date()), limitScheduleQueue.poll()); 115 } 116 117 } 118 119 if (limitScheduleQueue.size() > 0) { 120 limitHandler(); 121 } 122 } 123 124 /** 125 * 返回当前分钟数 126 * 127 * @param date 日期 128 * @return 返回分钟 129 */ 130 public static int getMinute(Date date) { 131 Calendar calendar = Calendar.getInstance(); 132 calendar.setTime(date); 133 return calendar.get(Calendar.MINUTE); 134 } 135 136 }

 

posted @ 2019-05-31 14:09  geekLife  阅读(1042)  评论(0)    收藏  举报