千家信息网

java如何实现单机接口限流

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,这篇文章主要为大家展示了"java如何实现单机接口限流",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"java如何实现单机接口限流"这篇文章吧。简单说就是设
千家信息网最后更新 2025年01月16日java如何实现单机接口限流

这篇文章主要为大家展示了"java如何实现单机接口限流",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"java如何实现单机接口限流"这篇文章吧。

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

/** * 单机限流 */@Slf4jpublic class FlowLimit { //接口限流上限值和限流时间缓存    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);                        }                    });                }            } 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() {                @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次请求。。。
所以这个时候就需要令牌桶或者其他算法了,其他算法后面再写

以上是"java如何实现单机接口限流"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0