dubbo的provider有2种线程池: 

  • IO处理线程池。(直接通过netty等来配置)
  • 服务调用线程池。

  如果事件处理的逻辑能迅速完成,并且不会发起新的 IO 请求,比如只是在内存中记个标识,则直接在 IO 线程上处理更快,因为减少了线程池调度。

  但如果事件处理逻辑较慢,或者需要发起新的 IO 请求,比如需要查询数据库,则必须派发到线程池,否则 IO 线程阻塞,将导致不能接收其它请求。

  如果用 IO 线程处理事件,又在事件处理过程中发起新的 IO 请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁。

因此,需要通过不同的派发策略和不同的线程池配置的组合来应对不同的场景:

<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
  • Dispatcher

all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
direct 所有消息都不派发到线程池,全部在 IO 线程上直接执行。
message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
connection 在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。

  • ThreadPool

fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
cached 缓存线程池,空闲一分钟自动删除,需要时重建。
limited 可伸缩线程池,但池中的线程数只会增长不会收缩。只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。
eager 优先创建Worker线程池。在任务数量大于corePoolSize但是小于maximumPoolSize时,优先创建Worker来处理任务。当任务数量大于maximumPoolSize时,将任务放入阻塞队列中。阻塞队列充满时抛出RejectedExecutionException。(相比于cached:cached在任务数量超过maximumPoolSize时直接抛出异常而不是将任务放入阻塞队列)

  上面是摘自官方的解释,下面进行研究:

producer.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="hello-world-app">
<!-- 关闭QOS:Quality of Service -->
<dubbo:parameter key="qos.enable" value="false" />
<dubbo:parameter key="qos.accept.foreign.ip" value="true" />
<dubbo:parameter key="qos.port" value="2222" />
</dubbo:application> <dubbo:registry address="zookeeper://127.0.0.1:2181"
subscribe="false" dynamic="false" /> <!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/> <!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="dubbo.DubboService" ref="demoService"
timeout="500000" /> <!-- 和本地bean一样实现服务 -->
<bean id="demoService" class="dubbo.DubboServiceImpl" />
</beans>

consumer.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="consumer-of-helloworld-app">
<!-- 关闭QOS:Quality of Service -->
<dubbo:parameter key="qos.enable" value="false" />
</dubbo:application> <!-- 使用multicast广播注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="dubboService" interface="dubbo.DubboService" />
</beans>

Consumer.java开启20个线程消费服务

package dubbo;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Consumer { private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); public static void main(String[] args) throws InterruptedException {
final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "consumer.xml" });
context.start();
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() { @Override
public void run() {
DubboService service = (DubboService) context.getBean("dubboService");
LOGGER.info(service.sayHello(" china "));
}
}).start();
} CountDownLatch countDownLatch = new CountDownLatch(1);
countDownLatch.await();
}
}

多次访问之后,消费者线程数量会一直增加,并且消费完成之后线程并不会结束,并且每次访问结束都会增加20个线程。如下:

(1)测试  direct  所有消息都不派发到线程池,全部在 IO 线程上直接执行。(多个线程同时请求是一种同步执行的方式,服务端始终只有一条线程处理请求),如下:

    <!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" dispatcher="direct"/>

查看线程信息:

(2)使用固定fixed线程池处理并且大小定为20

    <!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" dispatcher="all"
threadpool="fixed" threads="20" />

多次访问线程数量仍然定在最高的20,不会增加。(这种情况适用于最大并发量是20的请求)

如果同时访问超过20个,会报下面错误:

Exception in thread "Thread-0" com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service dubbo.DubboService. Tried 3 times of the providers [192.168.0.232:20880] (1/13) from the registry 127.0.0.1:2181 on the consumer 192.168.0.232 using the dubbo version 2.6.6. Last error is: Failed to invoke remote method: sayHello, provider: dubbo://192.168.0.232:20880/dubbo.DubboService?anyhost=true&application=consumer-of-helloworld-app&bean.name=dubbo.DubboService&check=false&dubbo=2.0.2&dynamic=false&generic=false&interface=dubbo.DubboService&methods=sayHello&pid=5132&qos.enable=false&register.ip=192.168.0.232&remote.timestamp=1554373603443&side=consumer&timeout=500000&timestamp=1554374765210, cause: Server side(192.168.0.232,20880) threadpool is exhausted ,detail msg:Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-192.168.0.232:20880, Pool Size: 20 (active: 20, core: 20, max: 20, largest: 20), Task: 67 (completed: 47), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://192.168.0.232:20880!
at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:102)
(3)limited  在同时访问超过线程数的时候多余请求被拒绝

  并且在生产者控制台打印如下信息

18:54:22 [com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport]-[WARN]  [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-192.168.0.232:20880, Pool Size: 20 (active: 20, core: 0, max: 20, largest: 20), Task: 21 (completed: 1), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://192.168.0.232:20880!, dubbo version: 2.6.6, current host: 192.168.0.232

  多余的客户端请求报错同上面一样,

Server side(192.168.0.232,20880) threadpool is exhausted ,detail msg:Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-192.168.0.232:20880, Pool Size: 20 (active: 20, core: 0, max: 20, largest: 20), Task: 21 (completed: 1), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://192.168.0.232:20880!

dubbo线程模型的更多相关文章

  1. 第十章 dubbo线程模型

    一 netty的线程模型 在netty中存在两种线程:boss线程和worker线程. 1 boss线程 作用: accept客户端的连接: 将接收到的连接注册到一个worker线程上 个数: 通常情 ...

  2. dubbo线程模型配置

    首先了解一下dubbo线程模型 如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识.则直接在IO线程上处理更快,因为减少了线程池调度. 但如果事件处理逻辑较慢,或者需要发 ...

  3. Dubbo入门到精通学习笔记(十一):Dubbo服务启动依赖检查、Dubbo负载均衡策略、Dubbo线程模型(结合Linux线程数限制配置的实战分享)

    文章目录 Dubbo服务启动依赖检查 Dubbo负载均衡策略 Dubbo线程模型(结合Linux线程数限制配置的实战分享) 实战经验分享( ** 属用性能调优**): Dubbo服务启动依赖检查 Du ...

  4. Dubbo学习笔记8:Dubbo的线程模型与线程池策略

    Dubbo默认的底层网络通讯使用的是Netty,服务提供方NettyServer使用两级线程池,其中 EventLoopGroup(boss) 主要用来接受客户端的链接请求,并把接受的请求分发给 Ev ...

  5. Dubbo -- 系统学习 笔记 -- 示例 -- 线程模型

    Dubbo -- 系统学习 笔记 -- 目录 示例 想完整的运行起来,请参见:快速启动,这里只列出各种场景的配置方式 线程模型 事件处理线程说明 如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求 ...

  6. 【原创】Dubbo 2.7.5在线程模型上的优化

    这是why技术的第30篇原创文章 这可能是全网第一篇解析Dubbo 2.7.5里程碑版本中的改进点之一:客户端线程模型优化的文章. 先劝退:文本共计8190字,54张图.阅读之前需要对Dubbo相关知 ...

  7. 彻底搞懂 netty 线程模型

    编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等.本文就netty线程模型展开 ...

  8. 面试官:Netty的线程模型可不只是主从多Reactor这么简单

    笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...

  9. 一文弄懂-Netty核心功能及线程模型

    目录 一. Netty是什么? 二. Netty 的使用场景 三. Netty通讯示例 1. Netty的maven依赖 2. 服务端代码 3. 客户端代码 四. Netty线程模型 五. Netty ...

随机推荐

  1. 19 python初学(os 模块,sys 模块,hashlib 模块)

    os 模块: # _author: lily # _date: 2019/1/13 import os print(os.getcwd()) # 得到当前的工作目录 # print(os.chdir( ...

  2. Java Scanner 类

    下面是创建 Scanner 对象的基本语法: Scanner s = new Scanner(System.in); Scanner -是java类库的一个基础类,一个可以使用正则表达式来解析基本类型 ...

  3. JS深度判断两个对象字段相同

    代码: /** * 判断此对象是否是Object类型 * @param {Object} obj */ function isObject(obj){ return Object.prototype. ...

  4. EQueue

    EQueue 2.3.2版本发布(支持高可用) - dotNET跨平台 - CSDN博客https://blog.csdn.net/sD7O95O/article/details/78097193 E ...

  5. Python——转义字符解释

    转义字符 解释 ASCII值 \a 响铃 7 \b 退格 8 \f 换页 12 \n 换行 10 \r 回车 13 \t 水平制表 9 \v 垂直制表 11 \\ 一个反斜线字符 92 \' 一个单引 ...

  6. Android学习第九天

    为什么需要内容提供者 a)        如何创建数据库 b)        文件权限 c)         Chmod linux修改权限 内容提供者原理 a)        内容提供者把数据进行封 ...

  7. this指针详解

    什么是this this是一个const指针,存的是当前对象的地址,指向当前对象,通过this指针可以访问类中的所有成员. 当前对象是指正在使用的对象,比如a.print(),a就是当前对象. 关于t ...

  8. Linux基本命令总结(五)

    接上篇: 21,在lunix系统里,文件或目录的权限的掌控以拥有者及所诉群组来管理.可以使用chgrp指令取变更文件与目录所属群组,这种方式采用群组名称或群组识别码都可以.Chgrp命令就是chang ...

  9. pta编译总结1

    打印沙漏 (20 分) 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打印 ***** *** * *** ***** 所谓“沙漏形状”,是指每行输出奇数个符号: ...

  10. lombok系列(一)

    如果在类上面使用@Builder注解, @Builder public class A { } controller中使用: public String test(@RequestBody A a){ ...