Dubbo——服务消费的实现原理
单注册中心消费原理
整体RPC的消费原理:
ReferenceCnofig
↓
Protocol ----> Dubbo、injvm等
↓
Invoker -----> DubboInvoker等
↓
ProxyFactoy -----> Javassist、JDK动态代理
↓
Ref
在整体上看,Dubbo框架做服务消费也分为两大部分:
- 第一部分通过持有远程服务实例生成Invoker,这个Invoker在和护短是核心的远程代理对象。
- 第二步会把Invoker通过动态代理转换成实现用户接口的动态代理引用。这里的Invoker承载了网络连接、服务调用和重试等功能,在客户端,它可能是一个远程的实现,也可能是一个集群实现。
框架真正进行服务引用的入口点在ReferenceBan#getObject
,不管是XML还是注解,都会转换成ReferenceBean,它继承自ReferenceConfig,在服务消费前也会按照覆盖策略生效,主要处理思路就是遍历服务的所有方法,如果没有值则会尝试从 -D 选项中读取,如果还没有则自动从配置文件dubbo.properties中读取。
Dubbo支持多注册中心同时消费,如果配置了服务同时注册多个注册中心,则会在ReferenceConfig#createProxy
中合并成一个Invoker:
多协议多注册中心暴露:
- 在①中会优先判断是否在同一个JVM中包含要消费的服务,默认场景下,Dubbo会通过②找出内存中injvm协议的服务,其实injvm协议是比较好理解的,服务实例都放到内存map中,消费也是直接获取实例调用而已。
- ③:主要在注册中心中追加消费者元数据信息,应用启动时订阅注册中心、服务提供者参数等合并时会用到这部分信息。
- ④:处理只有一个注册中心的场景,这种场景在客户端中是最常见的,客户端启动拉去服务元数据,订阅provider、路由和配置变更。
- ⑤和⑥:分别处理多注册中心的场景。
当经过注册中心消费时,主要通过RegistryProtocol#refer
触发数据拉取、订阅和服务Invoker转换等操作,其中最核心的数据结构是RegistryDirectory:
Dubbo通过注册中心消费:
这段逻辑主要完成了注册中心实例的创建,元数据注册到注册中心及订阅的功能。
- 在①中会根据用户指定的注册中心进行协议替换,具体注册中心协议会在启动时用registry存储对应值。
- 在②中会创建注册中心实例,这里的URL其实是注册中心地址,真实消费方的元数据信息是放在refer属性中存储的。
- 在③中主要提取消费方refer中保存的元数据信息,如果包含多个分组值则会把调用结果值则会把调用结果值做合并处理。
- 在④中触发真正的服务订阅和Invoker转换。
- 在⑤中
RegistryDirectory实现了NotifyListen接口,服务变更会触发这个类回调notify方法,用于重新引用服务
。 - 在⑥中负责把消费方元数据信息注册到注册中心,比如消费方法应用名、IP和端口号等。
- 在⑦中处理provider、路由和动态配置订阅。
- 在⑧中除了通过Cluster将多个服务合并,同时默认也会启动FailoverCluster策略进行服务调用重试。
具体远程Invoker是在哪里创建的呢?客户端调用拦截器又是在哪里构造的呢?
当在⑦中第一次发起订阅时会进行一次数据拉取操作,同时触发RegistryDirectory#notify
方法,这里的通知护具是某一个类别的全量数据,比如provders和routers类别数据。当通知providers数据时,在RegistryDirectory#toInvokers
方法内完成Invoker转换:
Dubbo框架允许在消费方配置只消费指定协议的服务,具体协议过滤在①中进行处理,支持多消费多个协议,允许消费多个协议时,在配置Protocol值时用逗号分隔即可。在②中消费信息是客户端处理的,需要合并服务端相关信息,比如远程IP和端口等信息,通过注册中心获取这些信息,解耦了消费方帮强绑定配置。在③中消除重复推送的服务列表,防止重复引用。在④中使用具体的协议发起远程连接等操作。在真实远程连接建立后也会发起拦截器构建操作,处理逻辑在PtocolFileterWrapper#refer
中触发链式构造。
具体Invoker创建爱你是在DubboProtocol#refer中实现的,Dubbo协议在返回DubboInvoker对象之前会先初始化客户端连接对象。Dubbo支持客户端是否立即服务建立TCP连接是由参数是否配置了lazy属性决定的,默认会全部连接。DubboProtocol#refer内部会调用DubboProtocol#initClient
负责建立客户端连接和初始化Handler:
多注册中心消费原理
多注册中心消费原理比较简单,每个单独注册中心抽象成一个单独的Invoker,多个注册中心实例最终通过StaticDirectory保存所有的Invoker,最终通过Cluster合并成一个Invoker。
多注册中心集群策略:
在①中实现doInvoker实际持有的Invoker列表是注册中心实例,比如配置了Zookeeper和etcd3注册中心,实际调用的invokers列表只有2个元素。
在②中会判断具体注册中心是否有服务可用,这里发起的invoke实际上会通过注册中心RegitryDirectory获取真实provider机器列表进行路由和负载均衡调用。
直接服务消费原理
Dubbo可以绕过注册中心直接指定服务(直接指定目标IP和端口)发起RPC调用,使用直连模式可以方便在某些场景下使用,比如压测指定机器等。Dubbo框架也支持同时指定直连多台机器进行服务调用:
ReferenceConfig#createProxy:
在1中允许用分号指定多个直连机器地址,多个直连机器调用你会使用负载均衡,更多场景是单个直连,但是不建议在生产环境中使用直连模式,因为上游服务发布会影响服务调用方。
在2中允许配置注册中心地址,这样可以通过注册中心发现服务消费。
在3中指定服务调用协议、IP和端口,注意这里的URL没有添加refer和注册中心协议,默认是Dubbo会慧姐触发DubboProtocol进行远程消费,不会经过RegistryProtocol去做服务发现。