RateLimiter高并发访问限流

使用RateLimiter完成简单的大流量限流,抢购秒杀限流。
RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率。
通常可应用于抢购限流防止冲垮系统;限制某接口、服务单位时间内的访问量,譬如一些第三方服务会对用户访问量进行限制;限制网速,单位时间内只允许上传下载多少字节等。
下面来看一些简单的实践demo,需要先引入guava的maven依赖。
Demo1.有很多任务,但希望每秒不超过N个

        import com.google.common.util.concurrent.RateLimiter;  
    import java.util.ArrayList;  
    import java.util.List;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  

    /** 
     *  
     * 有很多个任务,但希望每秒不超过X个,可用此类 
     */  
    public class Demo1 {  
        public static void main(String[] args) {  
            //0.5代表一秒最多多少个  
            RateLimiter rateLimiter = RateLimiter.create(0.5);  
            List<Runnable> tasks = new ArrayList<Runnable>();  
            for (int i = 0; i < 10; i++) {  
                tasks.add(new UserRequest(i));  
            }  
            ExecutorService threadPool = Executors.newCachedThreadPool();  
            for (Runnable runnable : tasks) {  
                System.out.println("等待时间:" + rateLimiter.acquire());  
                threadPool.execute(runnable);  
            }  
        }  

        private static class UserRequest implements Runnable {  
            private int id;  

            public UserRequest(int id) {  
                this.id = id;  
            }  

            public void run() {  
                System.out.println(id);  
            }  
    }  

}

Demo2.抢购场景限流
如我们预估数据库能承受并发10,超过了可能会造成故障,我们就可以对该请求接口进行限流。

        import com.google.common.util.concurrent.RateLimiter;  
    import com.tianyalei.model.GoodInfo;  
    import com.tianyalei.service.GoodInfoService;  
    import org.springframework.web.bind.annotation.RequestMapping;  
    import org.springframework.web.bind.annotation.RestController;  
    import javax.annotation.Resource;  

    @RestController  
    public class IndexController {  
        @Resource(name = "db")  
        private GoodInfoService goodInfoService;  

        RateLimiter rateLimiter = RateLimiter.create(10);  

        @RequestMapping("/miaosha")  
        public Object miaosha(int count, String code) {  
            System.out.println("等待时间" + rateLimiter.acquire());  
            if (goodInfoService.update(code, count) > 0) {  
                return "购买成功";  
            }  
            return "购买失败";  
        }  
        @RequestMapping("/add")  
        public Object add() {  
            for (int i = 0; i < 100; i++) {  
                GoodInfo goodInfo = new GoodInfo();  
                goodInfo.setCode("iphone" + i);  
                goodInfo.setAmount(100);  
                goodInfoService.add(goodInfo);  
            }  
            return "添加成功";  
        }  
    }  

Demo3.抢购场景降级

     /** 
     * tryAcquire(long timeout, TimeUnit unit) 
     * 从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话, 
     * 或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待) 
     */  
    @RequestMapping("/buy")  
    public Object miao(int count, String code) {  
        //判断能否在1秒内得到令牌,如果不能则立即返回false,不会阻塞程序  
        if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {  
            System.out.println("短期无法获取令牌,真不幸,排队也瞎排");  
            return "失败";  
        }  
        if (goodInfoService.update(code, count) > 0) {  
            System.out.println("购买成功");  
            return "成功";  
        }  
        System.out.println("数据不足,失败");  
        return "失败";  
    }  

猜你喜欢

转载自blog.csdn.net/qq_32447301/article/details/80134815