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

网友投稿 246 2022-11-20

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

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

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

/**

* 单机限流

*/

@Slf4j

public class FlowLhttp://imit {

//接口限流上限值和限流时间缓存

private static Cache localCache = CacheBuilder.newBuilder().maximumSize(100)

.expireAfterWrite(1000, TimeUnit.MILLISECONDS).build();

//每个接口的上限缓存

private static Map 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);

blgVToaY }

});

}

} 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 localCachttp://he.get(key, new Callable() {

@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次请求。。。

所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Hadoop之MapReduce篇(一)
下一篇:基于以太网和现场总线控制系统实现嵌入式HTTP服务器的设计
相关文章

 发表评论

暂时没有评论,来抢沙发吧~