在Dubbo的'人生'中, 无论它是在自己的'亲爸爸'阿里家族成长, 还是'寄养'在Apache家族里, Dubbo的底层通信一直使用高性能的Netty框架.
Dubbo在阿里家族一直成长到v2.6.9版本之后,就被送到Apache家族了.
通过Maven官网搜索Dubbo版本, 如下
从上面两张图看出, Dubbo在阿里家族的Maven最高版本是v2.6.9, 在Apache家族的Maven最低版本是v2.7.0, 正好衔接.
在之前的Netty在Dubbo中使用了哪些Handler文章中, 介绍了在服务端或客户端启动之后, 流程的处理过程涉及哪些Handler. 下面提供一张更全面的图
上面这张图, 涉及了Dubbo使用Netty作为客户端和服务端时启动的主要核心代码, 包括核心类, 以及心跳等内容. 接下来逐一说下每个部分内容.
图中代码的对应Dubbo版本是v2.6.9
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.9</version>
</dependency>
图中内容分成三个区域, 左边和右边分别对应启动服务端和启动客户端时对应 的Netty代码, 包括使用的Handler. 中间部分涉及客户端和服务端的
HeaderExchangeServer和HeaderExchangeClient, 还有心跳相关.
在服务端启动过程中, 会创建一个HeaderExchangeServer类,
它有一个NettyServer属性, 还有一个ScheduledExecutorService属性.
NettyServer就是负责监听客户端连接以及读写IO操作(具体是由Netty相关的类实现的). 当有数据到达服务端的时候, 从图上来看, 就会从上到下经过每个Handler, 当需要向客户端写数据的时候, 就会从下到上经过每个Handler.
ScheduledExecutorService类是一个定时任务相关的线程池. 当客户端没有向服务端发送请求的时候, 也就意味着没有数据到达服务端了. 通过这个定时任务可以定时向客户端发送心跳包, 正常情况, 客户端收到服务端的心跳包之后, 会响应一个心跳包给服务端, 服务端接收到客户端的响应心跳包之后, 什么业务也不会做. 不管是正常的业务数据发送和接收, 还是心跳包的发送和接收, 接收到包就会更新最后读的时间, 发送包就会更新最后写的时间. 根据最后读或者写的时间来判断, 经过了这么久还是没有收到对端的响应包, 那么服务端最后就会断开与客户端的连接. 简单说明就是, 服务端会根据最后一次读/写的时间判断, 比如已经过了1分钟了, 客户端还是没有给服务端发送数据, 那么服务端就会给客户端发送心跳包, 发了几次心跳包之后(至于发送几次是根据时间大小判断的)还是没有收到客户端的心跳包, 那么服务端就会断开连接.
在客户端启动过程中, 会创建一个HeaderExchangeClient类, 它有一个NettyClient属性, 还有一个ScheduledExecutorService属性.NettyClient是负责读写IO操作(具体是由Netty相关的类实现的). 当有数据到达客户端的时候, 从图上来看, 就会从上到下经过每个Handler, 当需要向服务端写数据的时候, 就会从下到上经过每个Handler.
在创建NettyClient的时候,会创建一个ScheduledThreadPoolExecutor. 这个线程池负责重连服务端, 它也是定时的检查连接是否关闭, 如果关闭了那么就会重连服务端.
在v2.6.9版本, 即阿里家族的版本, 实现心跳检测是通过客户端和服务端互发心跳包的方式实现的, 更具体的说是通过JDK的线程池实现定时检测的.
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor();
而就在v2.7.0版本, 也就是Dubbo捐献给Apache的第一个版本, 心跳检测的实现使用的是时间轮(HashedWheelTimer)的方式. 只是实现的方式不同而已, 但是服务端依然会发送心跳包.
可是到了v2.7.3版本, 不仅仅增加了使用Netty的IdleStateHandler类进行空闲检测, 虽然还使用了时间轮, 但是服务端已经不再发送心跳包了, 服务端一旦发现连接空闲, 直接断开连接了.
杂谈结束...