高并发环境下若生产者不能及时处理请求造成大量请求线程积压,最终会演变为大面积服务崩溃现象产生。根据服务特点设定合理的请求拒绝策略,保证服务正常运行是本文重点。当然必须区别于 负载均衡只能分配流量而不能限制流量
仅针对消费者端生效,只能在 <dubbo:reference>
亦或是其子标签 <dubbo:method>
或者是 <dubbo:consumer>
中配置。优先级策略与文章 Dubbo调优 -- 超时TimeOut 描述一致
描述 | 备注 |
---|---|
作用 | 消费者最大并发数量限制,超过限制将会抛出异常 |
实现 | 过滤器Filter,具体实现子类为ActiveLimitFilter |
默认值 | 0表示没有限制 |
配置地点 | <dubbo:consumer>、<dubbo:reference> 、<dubbo:method> |
大家熟悉的HTTP协议就属于短连接,每次请求的时候都会多次验证握手建立连接。默认的Dubbo协议属于长连接,采用NIO异步传输,每消费者与生产者之间默认采用单一长连接方式通信。换个简单说法就是每个消费者与生产者之间长连接默认就创建一个,所有请求共用
connections参数针对上述长连接与短连接具备不同作用效果:
connections参数生效的位置在消费端,图一表示消费端的配置,图二表示在生产者的配置。根据自身测试以及github验证,生产端的配置确实会通过注册中心传递给消费端生效
描述 | 备注 |
---|---|
作用 | 限制消费者短连接数量,长连接创建数量 |
实现 | 初始化连接时根据参数控制 |
默认值 | 长连接默认表示使用JVM共享长连接,线上一般都是多生产多消费,这个参数不建议更改 |
配置地点 | <dubbo:consumer>、<dubbo:reference> 、<dubbo:provider>、<dubbo:service> |
首先项目初始化的时候会根据connections参数初始化连接,过程在DubboProtocol类的getClients()方法中,下图是debug跟进的初始化结果。可以看到用于储存连接的数组最后返回的是两个连接实例
连接使用发生在类DubboInvoker中,该类的方法doInvoke()用于执行调用逻辑。使用的连接就是在DubboProtocol类中getClients()初始化出来并在方法refer()中放入DubboInvoker对象的连接。如下图所示是DubboInvoker中doIncoke()使用连接的关键代码
消费者可以通过connections参数设置连接的数量,但是如果生产者不进行自我保护,采用默认的无限制连接策略。高并发情况下生产者可能就会因为连接数量巨大崩溃,这时可以通过参数accepts限制生产者可接受最大连接数量
accepts用于生产者限制最大连接数量保护自身服务可用性,可以在标签 <dubbo:protocol>
中进行配置。这时候在 <dubbo:reference>
中设置connections超过accepts值,用于方便后续的源码跟进
描述 | 备注 |
---|---|
作用 | 限制生产者最大可接受连接数量,用于保护生产者自身 |
实现 | 消费者初始化创建连接时会打开创建链接,这时候就会根据限制参数判断 |
默认值 | 0表示没有限制,比较危险的配置 |
配置地点 | <dubbo:protocol> |
生产者启动初始化过程中可以看到开启连接的时候获取了参数accepts的设置,过程在AbstractServer类构造函数中可以看到
消费端初始化的时候当超过生产者限制连接数量后,在AbstractClient类中可以看到,构造函数中调用方法connect()创建连接。这时候会抛出异常,因为异常原因是等待创建连接超时3000ms。验证参数accepts效果
多线程并发操作一定离不开线程池,Dubbo自身提供了支持了四种线程池类型支持。生产者 <dubbo:protocol>
标签中可配置线程池关键参数,线程池类型、阻塞队列大小、核心线程数量等
CPU+1
,不建议更改设置 200
参数threadpool指定使用线程池类型,Dubbo中自身实现提供了如下表所示四种线程池。默认使用固定大小线程池FixedThreadPool
类型名称 | 队列类型 | 特性备注 |
---|---|---|
FixedThreadPool | queues 属性为0创建无容量阻塞队列 SynchronousQueue ,若 queues 小于0则创建Integer.MAX_VALUE容量 LinkedBlockingQueue 阻塞队列,大于0则创建 queues 参数限定容量 LinkedBlockingQueue 阻塞队列 |
核心线程数量与最大线程数量一致采用参数 threads 值、线程空闲存活时间0 |
CachedThreadPool | 队列创建类型规则与 FixedThreadPool 一致 |
相对于固定容量大小FixedThreadPool线程池多了参数 corethreads 设置核心线程数量支持默认0,线程空闲存活时间暂时未提供参数设置,默认1分钟 |
LimitedThreadPool | 队列创建类型规则与 FixedThreadPool 一致 |
相对于CachedThradPool而言最大的变化在于线程存活时间修改为Long.MAX_VALUE |
EagerThreadPool | 队列为Dubbo设计实现的 TaskQueue 队列,该队列继承自 LinkedBlockingQueue 。当 queues 参数小于等于0则其容量为1,若大于0则容量为 queues 参数值 |
后面会有专门文章研究这个线程池实现 |
Dubbo官网文档只描述了fixed/cached,四种线程池默认支持的是fixed
一个只能在生产者即 dubbo:service 亦或是其子标签 dubbo:method 中配置的属性,消费者中配置不会生效。这个参数主要目的是在生产者端限制应用线程使用数量