Dubbo调优(二) -- 限流策略

·  阅读 1928

一:前情导读

高并发环境下若生产者不能及时处理请求造成大量请求线程积压,最终会演变为大面积服务崩溃现象产生。根据服务特点设定合理的请求拒绝策略,保证服务正常运行是本文重点。当然必须区别于负载均衡只能分配流量而不能限制流量

在这里插入图片描述

二:消费端actives

仅针对消费者端生效,只能在<dubbo:reference>亦或是其子标签<dubbo:method>或者是<dubbo:consumer>中配置。优先级策略与文章Dubbo调优 -- 超时TimeOut描述一致

2.1 配置示例
2.2 参数详解
描述 备注
作用 消费者最大并发数量限制,超过限制将会抛出异常
实现 过滤器Filter,具体实现子类为ActiveLimitFilter
默认值 0表示没有限制
配置地点 <dubbo:consumer>、<dubbo:reference> 、<dubbo:method>
2.3 源码导读

在这里插入图片描述

  1. 处理请求参数:URL为Dubbo封装的一个请求对象类,包含Map<String, String>类型属性numbers,该属性中含有actives配置
  2. 请求过滤判断:RpcStatus类封装生产者调用状态,AtomicInteger原子类型active属性存储当前调用数量。通过其与URL中获取到的对应参数属性值比较判断
  3. 请求返回结果:如果允许则进行下一步RPC调用,不允许则会暂停等待线程timeout参数时长,若唤醒还未有空余线程则抛出异常

三:消费端connections

大家熟悉的HTTP协议就属于短连接,每次请求的时候都会多次验证握手建立连接。默认的Dubbo协议属于长连接,采用NIO异步传输,每消费者与生产者之间默认采用单一长连接方式通信。换个简单说法就是每个消费者与生产者之间长连接默认就创建一个,所有请求共用

connections参数针对上述长连接与短连接具备不同作用效果:

  • 短连接因为是多连接所以限制其个数
  • 长连接因为是单一连接所以是指定其创建数量
3.1 配置示例

connections参数生效的位置在消费端,图一表示消费端的配置,图二表示在生产者的配置。根据自身测试以及github验证,生产端的配置确实会通过注册中心传递给消费端生效

在这里插入图片描述
在这里插入图片描述

3.2 参数详解
描述 备注
作用 限制消费者短连接数量,长连接创建数量
实现 初始化连接时根据参数控制
默认值 长连接默认表示使用JVM共享长连接,线上一般都是多生产多消费,这个参数不建议更改
配置地点 <dubbo:consumer>、<dubbo:reference> 、<dubbo:provider>、<dubbo:service>
3.3 源码导读

首先项目初始化的时候会根据connections参数初始化连接,过程在DubboProtocol类的getClients()方法中,下图是debug跟进的初始化结果。可以看到用于储存连接的数组最后返回的是两个连接实例

在这里插入图片描述
连接使用发生在类DubboInvoker中,该类的方法doInvoke()用于执行调用逻辑。使用的连接就是在DubboProtocol类中getClients()初始化出来并在方法refer()中放入DubboInvoker对象的连接。如下图所示是DubboInvoker中doIncoke()使用连接的关键代码
在这里插入图片描述

四:生产端accepts

消费者可以通过connections参数设置连接的数量,但是如果生产者不进行自我保护,采用默认的无限制连接策略。高并发情况下生产者可能就会因为连接数量巨大崩溃,这时可以通过参数accepts限制生产者可接受最大连接数量

4.1 配置示例

accepts用于生产者限制最大连接数量保护自身服务可用性,可以在标签<dubbo:protocol>中进行配置。这时候在<dubbo:reference>中设置connections超过accepts值,用于方便后续的源码跟进

在这里插入图片描述
在这里插入图片描述

4.2 参数详解
描述 备注
作用 限制生产者最大可接受连接数量,用于保护生产者自身
实现 消费者初始化创建连接时会打开创建链接,这时候就会根据限制参数判断
默认值 0表示没有限制,比较危险的配置
配置地点 <dubbo:protocol>
4.3 源码导读

生产者启动初始化过程中可以看到开启连接的时候获取了参数accepts的设置,过程在AbstractServer类构造函数中可以看到

在这里插入图片描述
消费端初始化的时候当超过生产者限制连接数量后,在AbstractClient类中可以看到,构造函数中调用方法connect()创建连接。这时候会抛出异常,因为异常原因是等待创建连接超时3000ms。验证参数accepts效果
在这里插入图片描述

五:生产端线程池

多线程并发操作一定离不开线程池,Dubbo自身提供了支持了四种线程池类型支持。生产者<dubbo:protocol>标签中可配置线程池关键参数,线程池类型、阻塞队列大小、核心线程数量等

5.1 iothreads、threads
  • iothreads:限制的是io线程池大小,该线程池线程用于处理Dubbo框架自身业务逻辑。默认值为CPU+1,不建议更改设置
  • threads:用于指定下面讲到的业务线程池线程数量,这个才是业务需要关心的线程数量。默认大小200
5.2 threadpool

参数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参数值 后面会有专门文章研究这个线程池实现
5.3 注意

Dubbo官网文档只描述了fixed/cached,四种线程池默认支持的是fixed

六:生产端executes

一个只能在生产者即dubbo:service亦或是其子标签dubbo:method中配置的属性,消费者中配置不会生效。这个参数主要目的是在生产者端限制应用线程使用数量

6.1 配置示例

限制该服务每个方法并发不超过10,其中dubboProtocolGetMethod方法并发不超过2。方法级别的配置优先级高于服务配置

在这里插入图片描述

6.2 参数详解
配置地点 生产者dubbo:service标签或其子标签dubbo:method
默认值 0表示没有限制
作用 服务提供者每个方法只能占用线程池中配置数量线程,超出则抛出异常
实现 过滤器Filter
6.3 源码导读
  • 主要涉及类:ExecuteLimitFilter,关注相关类RpcStatus、URL
  • 主要方法:getMethodParameter()、beginCount()、getStatus()
    在这里插入图片描述
  1. 处理请求参数,URL为Dubbo封装的一个请求对象类,包含Map<String, String>类型属性numbers,该属性中含有executes配置
  2. 提取executes参数值,numbers -- paramters -- 默认值顺序返回
  3. 比较executes值数量,RpcStatus类封装生产者调用状态,AtomicInteger原子类型active属性存储当前调用数量
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改