java高并发限流

半兽人 发表于: 2018-10-17   最后更新时间: 2018-10-17 00:45:34  
{{totalSubscript}} 订阅, 5,342 游览

一、对单个接口的总并发数进行限制

1、利用一个AtomicLong变量进行简单粗暴的限流

try {
    if(atomic.incrementAndGet() > 限流数) {
        //拒绝请求
    }
    //处理请求
} finally {
    atomic.decrementAndGet();
}

2、利用SHARED模式的ReentrantLock

try {
    if(lock.lock()) {
        //拒绝请求
    }
    //处理请求
} finally {
    lock.unlock();
}

这里可以根据需要采用完全阻塞的lock,立即返回的tryLock,以及带等待时间的lock(lockTime)等方法。

3、异步

对于异步需要注意,如果consumer方没有回调或者回调超时,要保证对应请求的decrementunlock操作都要执行,否则计数就会有问题了。

二、限流某个接口的时间窗请求数

LoadingCache<Long, AtomicLong> counter =
        CacheBuilder.newBuilder()
                .expireAfterWrite(2, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, AtomicLong>() {
                    @Override
                    public AtomicLong load(Long seconds) throws Exception {
                        return new AtomicLong(0);
                    }
                });
long limit = 1000;
while(true) {
    //得到当前秒
    long currentSeconds = System.currentTimeMillis() / 1000;
    if(counter.get(currentSeconds).incrementAndGet() > limit) {
        System.out.println("限流了:" + currentSeconds);
        continue;
    }
    //业务处理
}

这里统计每秒内的请求次数总和,过期时间设置为大于1s的时间即可,保证1s内的统计不会过期。

和上面段落实现功能的区别:

上面限制总并发数的限制,如果业务流执行很快,很快就decrementAndGet或者unlock,那么1s内可以接收很多请求,比如业务处理消耗1ms,即使并发数最大是1,1s中也可以接收1000个请求。

本段落限制时间窗内的请求数就和业务执行快慢无关了,这里只统计1s钟内执行了多少次,即使业务处理消耗时间很少,比如1ms,但是如果在第一个ms内就来了1000个请求,那么剩余的999ms就一个请求也进不来了。

三、分布式限流

用redis实现的分布式限流。(换成redis的方式)

int current = jedis.incr(key);
if (current + 1 > limit) //如果超出限流大小
   return 0;
else if (current == 1) //只有第一次访问需要设置2秒的过期时间
   jedis.expire(key, "2");
return 1
更新于 2018-10-17
在线,6小时前登录

查看java更多相关的文章或提一个关于java的问题,也可以与我们一起分享文章