35

信号量限流,高并发场景不得不说的秘密

 4 years ago
source link: https://www.tuicool.com/articles/y2QRZfi
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

e6JBVrU.gif

限流可以认为是一种降级,一般是根据后台的负载提前预估的一个阈值(也可以动态调整)。超过了这个值,就要进行一些旁路处理。根据业务形态,会有直接拒绝、延迟处理、保持等待、部分穿透、默认返回等响应方式。

concurrent包中的信号量,由于使用简单, 易于理解 ,被广泛应用。但是,你要是直接用了网友们分享的简单代码而不经过认真测试,那可以送你一部电影观赏一下:《当故障来敲门》。

看下面简单的代码,acquire和release是一对同命鸳鸯,我们把release贴心的放在了finally块中,一切显得非常和谐。

1)模拟的业务请求,耗时大约是100毫秒

2)acquire的参数5代表同一时间允许5个线程进行处理

3)每次执行完毕,输出一下本次执行的具体耗时,加上等待时间

a2eiQjb.jpg!web

我们启动1000个线程去执行req方法。

SemaphoreLimiterBadChecker limiter = new SemaphoreLimiterBadChecker();
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
    executor.submit(() -> {
        while (true) {
            System.out.println(limiter.req());
        }
    });
}

下面是执行结果。

zYrEriZ.gif

可以看到,虽然我们的接口耗时只有100ms,实际的执行时间,却长的多,而且并没有出现fail的情况。运行稍长一点时间,能够发现有大量的线程处于 饿死 的状态。改为公平锁并不能改善这一情况。

Z7ne6zA.jpg!web

这就是故障。

原因就在于。web端(如tomcat)的资源也是有限的。当我们的限流器产生了作用,而实际并发请求比处理能力高的时候,这种线程阻塞情况就会逐级传递。服务器的响应可能会有以下过程:

1)压力普通,正常服务,耗时正常  。

2)压力上升,服务开始出现大面积超时,由于使用不公平锁竞争,偶尔会有正常耗时的请求。

3)压力继续增大,服务器开始进入假死状态,几乎不能再接受新的请求。

2YR7zuB.jpg!web

表现在用户端,既不能出现服务不能处理的提示,也无法中断请求,所有的请求都在 转圈 。继续加大tomcat的连接数和线程数,并不会起到多大的作用。

acquire 改成 tryAcquire ?依然不能解决问题。tryAcquire返回的是bool类型,失败的时候依然能够往下执行,包括finally块。有个毛用?

if(!tryAcquire()){
    return TOO_MANY_REQUESTS;
}

上面多加了一个判断,这个才是正途。tryAcquire还可以加超时参数,不至于立马返回失败,也不至于让调用者无限等待,而是将成功的请求控制在一个合理的响应时间。

响应时间=超时时间+业务处理时间

fQ7jQnj.jpg!web 具体做法,拿spring来说,你可以在 preHandle 中获取这个许可,然后在 postHandle 中释放它;也可以使用定时器以一定的频率去重制信号量。

当然你也要区别对待。

1、像上面提到的web服务,可以直接拒绝服务。快速响应才是重要的

2、像一些秒杀、下单等,可以通过排队或者等待解决(部分的)

3、像消息消费等,如果没有顺序需求,我觉得,无限等待还可能是个好的方式

4、对于大多数可有可无的业务结果,使用一些默认值直接返回,效果会好的多。虽然是限流,但干的是熔断的活

使用者一定要注意区分。

End

非常让人奇怪的是,java抽象了使用场景并不是很高(相对)的CyclicBarrier,但是并没有一个通用的限流方法。信号量虽然可以模拟实现这个过程,但它不太友好,太容易出错。限流还是使用guava的组件进行控制比较好(非分布式),我们会在后面的文章来探讨它。

相关文章:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK