自定义限流
package com.atguigu.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 限流器 每分钟限制请求600次,用于解决推送,每分钟六百次的接口请求次数限制问题
*
* @Auther: 屈艳锋
* @Date: 2019/5/23 15:12
*/
@RestController
@Slf4j
public class CurrentLimiter {
/**
* 限流请求次数记录容器,用于记录前一分钟,当前分钟,后一分钟的请求次数
*/
static AtomicInteger[] limitRequestCountRecordArray = {new AtomicInteger(0), new AtomicInteger(0), new AtomicInteger(0)};
/**
* 限流队列,用于存放超过请求次数限制的请求
*/
static LinkedBlockingQueue limitScheduleQueue = new LinkedBlockingQueue<Integer>(4);
/**
* 定时任务,每逢五十秒时,将后一分钟的请求次数初始化为0
*/
@Scheduled(cron = "0/50 * * * * ?")
public void initNextMiniuteValue() {
//限流容器长度
int limitArrayLength = limitRequestCountRecordArray.length;
//获取当前分钟数据所在下标
int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitArrayLength;
//获取后一分钟数据所在下标
int nextIndex = 0;
if (currentIndex < limitArrayLength - 1) {
nextIndex = currentIndex + 1;
}
//将后一分钟的请求次数初始化为0
limitRequestCountRecordArray[nextIndex] = new AtomicInteger(0);
log.info("执行是定时任务,当前分钟下标为{},请求次数为{}", currentIndex, limitRequestCountRecordArray[currentIndex].get());
}
/**
* 测试每分钟六百次限流
*
* @return
* @throws InterruptedException
*/
@RequestMapping("/ratelimit/test")
public String testLimiter() throws InterruptedException {
for (int i = 0; i < 1000; i++) {
//获取当前分钟数数据所在限流容器的下标
int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitRequestCountRecordArray.length;
//如果超过阀值,则放入队列
if (limitRequestCountRecordArray[currentIndex].get() > 599) {
limitScheduleQueue.put(i);
} else {
//当前分钟数数据加一
limitRequestCountRecordArray[currentIndex].incrementAndGet();
log.info("{}分钟正常调用{}", getMinute(new Date()), i);
}
}
if (limitScheduleQueue.size() > 0) {
new Thread(this::limitHandler).start();
}
return "";
}
/**
* 限流处理
* 95
*/
void limitHandler() {
log.info("=========>当前时间:{}", getMinute(new Date()));
for (int i = 0; i < limitScheduleQueue.size(); i++) {
//获取当前分钟数数据所在限流容器的下标
int currentIndex = (int) (System.currentTimeMillis() / 60000) % limitRequestCountRecordArray.length;
//如果超过阀值,则不处理
if (limitRequestCountRecordArray[currentIndex].get() > 599) {
try {
log.info("{}分钟已超过限制,休息一会,稍微继续~~~", getMinute(new Date()));
Thread.sleep(60000);
} catch (InterruptedException e) {
}
} else {
//当前分钟数数据加一
limitRequestCountRecordArray[currentIndex].incrementAndGet();
log.info("{}分钟正常调用中:{}", getMinute(new Date()), limitScheduleQueue.poll());
}
}
if (limitScheduleQueue.size() > 0) {
limitHandler();
}
}
/**
* 返回当前分钟数
*
* @param date 日期
* @return 返回分钟
*/
public static int getMinute(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.MINUTE);
}
}
摘自https://www.cnblogs.com/quyanfengalan/p/10954972.html

浙公网安备 33010602011771号