专栏首页架构专题信号量限流,高并发场景不得不说的秘密

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

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

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

看下面简单的代码,acquire和release是一对同命鸳鸯,我们把release贴心的放在了finally块中,一切显得非常和谐。 1)模拟的业务请求,耗时大约是100毫秒 2)acquire的参数5代表同一时间允许5个线程进行处理 3)每次执行完毕,输出一下本次执行的具体耗时,加上等待时间

我们启动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());
        }
    });
}

下面是执行结果。

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


这就是故障。

原因就在于。web端(如tomcat)的资源也是有限的。当我们的限流器产生了作用,而实际并发请求比处理能力高的时候,这种线程阻塞情况就会逐级传递。服务器的响应可能会有以下过程: 1)压力普通,正常服务,耗时正常 。 2)压力上升,服务开始出现大面积超时,由于使用不公平锁竞争,偶尔会有正常耗时的请求。 3)压力继续增大,服务器开始进入假死状态,几乎不能再接受新的请求。

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


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

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

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

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

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

当然你也要区别对待。 1、像上面提到的web服务,可以直接拒绝服务。快速响应才是重要的 2、像一些秒杀、下单等,可以通过排队或者等待解决(部分的) 3、像消息消费等,如果没有顺序需求,我觉得,无限等待还可能是个好的方式 4、对于大多数可有可无的业务结果,使用一些默认值直接返回,效果会好的多。虽然是限流,但干的是熔断的活

使用者一定要注意区分。

End

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

本文分享自微信公众号 - 小姐姐味道(xjjdog)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 实现websocket的两种方式

    1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket

    凯哥Java
  • Jenkins安装配置

     1.安装JDK:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads...

    凯哥Java
  • 有哪些 Java 源代码看了后让你收获很多,代码思维和能力有较大的提升?

    最早看的 架构探险 从零开始写Java Web框架,黄勇写的,算是一种启蒙,作者自己写了一套ioc和aop框架以及mvc请求分发框架。

    凯哥Java
  • 新版本的tomcat对url的参数做了比较规范的限制,不注意就会掉坑了

    Invalid character found in the request target. The valid characters are defined ...

    凯哥Java
  • spring boot 2.x 整合mybaits及分页插件

    在众多ORM持久层框架中,凯哥还是比较喜欢使用mybatis。至于mybatis的好处在此就不一一列举了。本篇主要介绍的是在spring boot中怎么整合my...

    凯哥Java
  • UEditor文档-JSP 使用说明

    UEditor 1.4.0 版本对之前的配置方式进行了简化,具体请参见:后端请求规范,为了适应这次升级,JAVA 后台也进行了重写,跟之前的版本差别较大,升级的...

    凯哥Java
  • spring boot整合jsp的时候访问页面错误日志:Path with "WEB-INF" or "META-INF":

    虽然spring boot 官方不推荐使用jsp.然后凯哥qianqian的,想整合jsp。在整合过程中遇到了错误:

    凯哥Java
  • 《企业IT架构转型之道》读书笔记(部分2)

    2007年,淘宝已经拥有超过500人的技术团队规模,整个淘宝网站是一个几百兆字节的WAR包,大小功能模块超过200个。

    SammyLiu
  • spring boot 基于yml整合jsp

    对应习惯了jsp开发的朋友来说,使用spring boot的时候也想使用jsp怎么办?本文将图文并茂的讲解怎么在spring boot中使用jsp。

    凯哥Java
  • eclipse+tomcat的问题能启动,但量不能访问

    今天还发现了一种情况tomcat起不来,配置是默认的,就是下面两张图的第一张图的配置。但是就是起不来,原因是web.xml配置有问题也会出现这种情况。

    潇洒

扫码关注云+社区

领取腾讯云代金券