在应对秒杀、大促、双 11、618 等高性能压力的场景时,限流已经成为了标配技术解决方案,为保证系统的平稳运行起到了关键性的作用。不管应用场景是哪种,限流无非就是针对超过预期的流量,通过预先设定的限流规则选择性的对某些请求进行限流“熔断”。

1. 限流

  1.1 单机限流

    a>>限制并发量

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class SemaphoreTest {    private static final int THREAD_COUNT = 30;    private static ExecutorService threadPool = Executors
            .newFixedThreadPool(THREAD_COUNT);    private static Semaphore s = new Semaphore(10);    public static void main(String[] args) {        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override                public void run() {                    try {
                        s.acquire();
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(5000);
                        System.out.println("--------------");
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }

        threadPool.shutdown();
    }
}

   b>>计数器,以CountDownLatch为例

import java.util.concurrent.CountDownLatch;public class CountDownLatchTest2 {    public static void main(String[] args) {        // 创建计数器,初始化为2
        final CountDownLatch latch = new CountDownLatch(2);        new Thread(() -> {            try {
                System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                Thread.sleep(3000);
                System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                latch.countDown();// 减一
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();        new Thread(() -> {            try {
                System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                Thread.sleep(3000);
                System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();        try {
            System.out.println("等待2个子线程执行完毕...");            // 阻塞            latch.await();
            System.out.println("2个子线程已经执行完毕");
            System.out.println("继续执行主线程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

c>>guava RateLimiter    

public void test()
{    /**
     * 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以2个的消息。
     * 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果     */
    RateLimiter r = RateLimiter.create(2);    while (true)
    {        /**
         * acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。
         * acquire(N)可以获取多个令牌。         */
        System.out.println(r.acquire());
    }
}

1.2 分布式限流

a>> nginx

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;server { 
location / { 
	limit_req zone=mylimit;    }
}

b>>api-gateway+redis限流

https://github.com/wangzheng0822/ratelimiter4j

  1. 熔断对比

功能对比

Sentinel Hystrix resilience4j 隔离策略 信号量隔离(并发线程数限流) 线程池隔离/信号量隔离 信号量隔离 熔断降级策略 基于响应时间、异常比率、异常数 基于异常比率 基于异常比率、响应时间 实时统计实现 滑动窗口(LeapArray) 滑动窗口(基于 RxJava) Ring Bit Buffer 动态规则配置 支持多种数据源 支持多种数据源 有限支持 扩展性 多个扩展点 插件的形式 接口的形式 基于注解的支持 支持 支持 支持 限流 基于 QPS,支持基于调用关系的限流 有限的支持 Rate Limiter 流量整形 支持预热模式、匀速器模式、预热排队模式 不支持 简单的 Rate Limiter 模式 系统自适应保护 支持 不支持 不支持 控制台 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 简单的监控查看 不提供控制台,可对接其它监控系统

参考文献:

【1】https://mp.weixin.qq.com/s?__biz=MjM5MDE0Mjc4MA==&mid=2651008444&idx=1&sn=a579c3ceb143ea30930bd4c6d4a8d7e2&chksm=bdbed5ef8ac95cf93e71c5393f08e3b97a7e19e8232ce3872231f2cae74f7a19ab15501aeb44&scene=27#wechat_redirect

【2】https://mp.weixin.qq.com/s?__biz=MzIwMzY1OTU1NQ==&mid=2247484306&idx=1&sn=b6c1b7b9d7c57bbb9f82ec451bcda867&chksm=96cd43dea1bacac8a24cde429146f69dba8bb15c5c9c3fe9adfe858d9a4349cc127fbfa84a8c&scene=27#wechat_redirect

【3】https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel