转载

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

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

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

二:消费端actives

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

2.1 配置示例

  • dubbo:consumer 中配置针对所有服务所有方法生效
  • dubbo:consumer 中配置针对该服务所有方法生效
  • dubbo:method 中配置针对该方法生效
    Dubbo调优(二) -- 限流策略

2.2 参数详解

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

2.3 源码导读

Dubbo调优(二) -- 限流策略
  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验证,生产端的配置确实会通过注册中心传递给消费端生效

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

3.2 参数详解

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

3.3 源码导读

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

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

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

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

四:生产端accepts

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

4.1 配置示例

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

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

4.2 参数详解

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

4.3 源码导读

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

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

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

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

五:生产端线程池

多线程并发操作一定离不开线程池,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 中配置的属性,消费者中配置不会生效。这个参数主要目的是在生产者端限制应用线程使用数量

原文  https://juejin.im/post/5dae79225188252f0c4d0883
正文到此结束
Loading...