dubbo的通信过程

本文详细解析了Dubbo框架中的RPC通信流程,包括服务端与客户端的启动过程、消息派发机制以及序列化实现等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看看dubbo的整体分层
  • config,配置层,对外配置接口,以ServiceConfig, ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类
  • proxy,服务代理层,服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory
  • registry,注册中心层,封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory, Registry, RegistryService
  • cluster,路由层,封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster, Directory, Router, LoadBalance
  • monitor,监控层,RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory, Monitor, MonitorService
  • protocol,远程调用层,封将RPC调用,以Invocation, Result为中心,扩展接口为Protocol, Invoker, Exporter
  • exchange,信息交换层,封装请求响应模式,同步转异步,以Request, Response为中心,扩展接口为Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • transport,网络传输层,抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel, Transporter, Client, Server, Codec
  • serialize,数据序列化层,可复用的一些工具,扩展接口为Serialization, ObjectInput, ObjectOutput, ThreadPool

前面已经分析了从配置层到protocol层的调用过程,这篇来分析protocol层到serialize层的dubbo通信的过程。
这里以默认的dubbo协议,netty通讯框架为例,讨论dubbo的通信过程。

提供者服务端的启动过程
1. (protocol层) DubboProtocol中createServer方法创建返回,并传入ExchangeHandler回调reply方法,处理客户端的请求。 server = Exchangers.bind(url, requestHandler)
2. (exchange层 调用HeaderExchanger的bind方法,创建一个HeaderExchangeServer
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
3. 传入的ChannelHandler 通过包装的方法,形成一个调用链, DecodeHandler中是对数据的反序代操作,HeaderExchangeHandler中对dubbo协议的数据进行处理,并回调reply方法。
4. (transport层)构造方法中,调用Transporters.bind(),通过spi查找,会调用NettyTransporter.bind()方法, 并直接实例代一个NettyServer。
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
5. NettyServer调用父类AbstractServer的构造方法, 从url中拿的一系统参数,回调doOpen方法开启服务,NettyServer的doOpen方法则是调用netty的api,开启了netty的服务端。
public NettyServer(URL url, ChannelHandler handler) throws RemotingException{
super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}
6. ChannelHandlers.wrapInternal对handler再一次进行了包装,MultiMessageHandler负责对多条消息的处理,HeartbeatHandler负责心跳包的处理,spi构造出AllChannelHandler,负责对事件进行派发。
protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {
return new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)));
}
7. 第2步中实例代HeaderExchangeServer对象,构造方法中会调用startHeatbeatTimer方法,启动一个定时器线程,定时发送心跳包。


消费者客户端的启动过程
1. (protocol层DubboProtocol.refer()方法根据接口类型与提供者地址实例代DubboInvoker,
并调用initClient方法初始代客户端连接。
2. (exchange层 调用HeaderExchanger的connect方法,创建一个HeaderExchangeClient。
3. (同服务端一样)传入的ChannelHandler 通过包装的方法,形成一个调用链, DecodeHandler中是对数据的反序代操作,HeaderExchangeHandler中对dubbo协议的数据进行处理,并回调reply方法。
4. (transport层)构造方法中,调用Transporters.connect(),通过spi查找,会调用NettyTransporter.connect()方法, 并直接实例代一个NettyClient。
5. NettyClient调用父类AbstractClient的构造方法, 从url中拿的一系统参数,回调doOpen方法开启服务,NettyClient的doOpen方法则是调用netty的api,开启了netty的客户端。接回调doConnect方法创建与客户端的连接。
6. (同服务端一样)ChannelHandlers.wrapInternal对handler再一次进行了包装,MultiMessageHandler负责对多条消息的处理,HeartbeatHandler负责心跳包的处理,spi构造出AllChannelHandler,负责对事件进行派发。
7. 第2步中实例代HeaderExchangeClient对象,构造方法中会调用startHeatbeatTimer方法,启动一个定时器线程,定时发送心跳包。
8. 第1步实例代的DubboInvoker的doInvoke方法中客户端会请求服务端的, 实际调用HeaderExchangeClient.send()->NettyChannel.send()->org.jboss.netty.channel.Channel.write(),最终调用netty的api发送请求。



消息的派发
消息的派发由spi机制查找具体的Dispatcher来实现
ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)
如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识,则直接在IO线程上处理更快,因为减少了线程池调度。但如果事件处理逻辑较慢,或者需要发起新的IO请求,比如需要查询数据库,则必须派发到线程池,否则IO线程阻塞,将导致不能接收其它请求。
如果用IO线程处理事件,又在事件处理过程中发起新的IO请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁。
  • Dispatcher
  • all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
  • direct 所有消息都不派发到线程池,全部在IO线程上直接执行。
  • message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。
  • execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。
  • connection 在IO线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
  • ThreadPool
  • fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
  • cached 缓存线程池,空闲一分钟自动删除,需要时重建。
  • limited 可伸缩线程池,但池中的线程数只会增长不会收缩。(为避免收缩时突然来了大流量引起的性能问题)。

协议编码方式
dubbo的编解码由Codec接口来实现,,执行的入口在启动netty服务时设置的handler回调。
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", adapter.getDecoder());
pipeline.addLast("encoder", adapter.getEncoder());
pipeline.addLast("handler", nettyHandler);
return pipeline;
具体实现在InternalEncoder与InternalDecoder中,调用Codec的encode与decode..


数据的序列代实现

序列代的执行在编解码之前执行,具体实现在ExchangeCodec的encodeRequest,encodeResponse等方法中。
public static Serialization getSerialization(URL url) {
return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(
url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION));
}
通过spi机制获取序列代器,对编码之后的数据进行序列代操作。
### Dubbo 集群通信机制原理 Dubbo 是一个高性能、轻量级的开源微服务框架,其集群通信机制是构建分布式系统的重要组成部分。Dubbo通信机制涵盖了多个关键组件,包括基于 Netty 的高效网络通信、多协议支持、请求调用的完整生命周期管理、序列化与反序列化、注册中心驱动的服务发现,以及负载均衡与容错策略等[^1]。 #### 1. **基于 Netty 的高效网络通信** Dubbo 使用 Netty 作为底层网络通信框架,Netty 是一个异步事件驱动的高性能网络库,能够高效处理大量的并发连接。Dubbo 利用 Netty 的非阻塞 I/O 特性,实现了高效的网络通信,支持 TCP、HTTP、REST 等多种通信协议[^1]。 #### 2. **多协议支持** Dubbo 支持多种通信协议,包括 Dubbo 协议、HTTP、REST、RMI 等。其中,Dubbo 协议是 Dubbo 框架的核心协议,它基于 TCP 长连接,采用二进制编码,具有高效的序列化和反序列化能力,适用于高性能的远程服务调用场景[^1]。 #### 3. **请求调用的完整生命周期管理** 在 Dubbo 中,请求调用的生命周期管理涵盖了从服务消费者发起请求到服务提供者处理请求并返回结果的全过程Dubbo 通过 Invocation 和 Result 对象来封装请求和响应,确保了请求的完整性和一致性。服务调用过程中,Dubbo 会根据服务消费者的配置选择合适的服务提供者,并通过网络通信将请求发送到目标服务提供者[^4]。 #### 4. **序列化与反序列化** 为了在网络上传输数据,Dubbo 使用了多种序列化和反序列化机制,如 JSON、Hessian、Protobuf 等。这些机制确保了数据能够在服务消费者和服务提供者之间高效地传输和解析,减少了网络传输的开销。 #### 5. **注册中心驱动的服务发现** Dubbo 依赖注册中心来实现服务的注册与发现。服务提供者在启动时会向注册中心注册自己的服务信息,而服务消费者则通过注册中心查找可用的服务提供者。Dubbo 支持多种注册中心,如 ZooKeeper、Nacos、Eureka 等,确保了服务发现的灵活性和可靠性[^1]。 #### 6. **负载均衡与容错策略** Dubbo 提供了丰富的负载均衡策略,如随机、轮询、最少活跃调用等,确保了服务请求能够在多个服务提供者之间合理分配。此外,Dubbo 还支持多种容错策略,如失败重试、快速失败、熔断等,确保了系统的高可用性[^1]。 #### 7. **Protocol、Invoker 和 Exporter 的扩展接口** Dubbo通信机制还依赖于 Protocol、Invoker 和 Exporter 等核心扩展接口。Protocol 是服务域的核心接口,负责服务的暴露和引用,管理 Invoker 的生命周期。Invoker 是 Dubbo 的核心模型,代表一个可执行体,可以是一个本地实现、远程实现或集群实现。Exporter 则负责将服务暴露给外部调用者,确保服务能够被正确地访问和调用[^4]。 #### 8. **服务治理** Dubbo通信机制不仅仅是简单的网络通信,还包括了服务治理的功能。服务治理涵盖了服务的注册与发现、负载均衡、容错、服务路由、日志输出等多个方面,确保了分布式系统的稳定性和可维护性[^3]。 ### 示例代码:Dubbo 服务调用的基本流程 ```java // 定义服务接口 public interface DemoService { String sayHello(String name); } // 服务提供者实现 public class DemoServiceImpl implements DemoService { public String sayHello(String name) { return "Hello, " + name; } } // 服务消费者调用 public class Consumer { public static void main(String[] args) throws Exception { // 创建服务引用 ReferenceConfig<DemoService> reference = new ReferenceConfig<>(); reference.setApplication(new ApplicationConfig("consumer-app")); reference.setRegistry(new RegistryConfig("zookeeper://192.168.1.100:2181")); reference.setInterface(DemoService.class); // 获取服务代理 DemoService demoService = reference.get(); // 调用服务 String result = demoService.sayHello("World"); System.out.println(result); } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值