一、dubbo的处理流程
二、服务注册
注册中心是Dubbo的重要组成部分,主要用于服务的注册与发现,我们可以选择Redis、Nacos、
Zookeeper作为Dubbo的注册中心,Dubbo推荐用户使用Zookeeper作为注册中心。单选择zookeeper作为注册中心的时候,服务注册之后,zookeeper的目录结构为:
+- dubbo
| +- com.lagou.service.HelloService
| | +- consumers
| | | +- consumer://192.168.1.102/com.lagou.service.HelloService?
application=dubbo-demo-annotationconsumer&
category=consumers&check=false&dubbo=2.0.2&init=false&interface=com.lag
ou.service.HelloService&methods=sayHello,sayHelloWithPrint,sayHelloWithTransmiss
ion,sayHelloWithException&pid=25923&release=2.7.5&side=consumer&sticky=false&tim
estamp=1583896043650
| | +- providers
| | | +- dubbo://192.168.1.102:20880/com.lagou.service.HelloService?
anyhost=true&application=dubbo-demo-annotationprovider&
deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.l
agou.service.HelloService&methods=sayHello,sayHelloWithPrint,sayHelloWithTransmi
ssion,sayHelloWithException&pid=25917&release=2.7.5&side=provider&telnet=clear,e
xit,help,status,log,ls,ps,cd,pwd,invoke,trace,count,select,shutdown×tamp=15
83896023597
| | +- configuration
| | +- routers
生产者注册过程
dubbo配置生产者,通过在接口上添加@Service注解或者
服务注册过程
首先 ServiceConfig 类拿到对外提供服务的实际类 ref,然后通过ProxyFactory 接口实现类中的 getInvoker 方法使用 ref 生成一个 AbstractProxyInvoker 实例,到这一步就完成具体服务到 Invoker 的转化。接下来就是 Invoker 转换到 Exporter 的过程。
我们可以看到,最终会调用Protocol的export方法生成Exporter并且注册到注册中心。先来看一下Protocol的export方法。通过断点我们可以看到最终调用的是RegistryProtocol.export方法。进入源码。
这里的override协议是一个动态更改配置的协议,服务提供者配置更改之后 可以按照最新的配置,重新建立invoker并销毁原来的invoker(了解overrider可以查看博客源码分析Dubbo配置规则机制(override协议) - JavaShuo)。进入register方法
根据断点,可以看到使用的registry是ZookeeperRegistry, 查看具体的ZookeeperRegistry的注册方法。这里可以看到继承了FailbackRegistry
FailbackRegistry是一个注册失败只有会有稍后重试机制的注册。
里面的两个方法分别是注册和重试注册。看一下注册的方法doRegister,这是方法通过ZookeeperRegister具体实现的。
三、服务的消费
首先 ReferenceConfig 类的 init 方法调用 createProxy() ,期间 使用Protocol 调用 refer 方法生
成 Invoker 实例(如上图中的红色部分),这是服务消费的关键。接下来使用ProxyFactory把 Invoker
转换为客户端需要的接口。
集群工作过程可分为两个阶段,第一个阶段是在服务消费者初始化期间,集群 Cluster 实现类为服务消费者创建 Cluster Invoker 实例,即上图中的 merge 操作。第二个阶段是在服务消费者进行远程调用时。以 FailoverClusterInvoker 为例,该类型 Cluster Invoker 首先会调用 Directory 的 list 方法列举Invoker 列表(可将 Invoker 简单理解为服务提供者)。Directory 的用途是保存 Invoker列表,可简单类比为 List。其实现类 RegistryDirectory 是一个动态服务目录,可感知注册中心配置的变化,它所持有的 Invoker 列表会随着注册中心内容的变化而变化。每次变化后,RegistryDirectory 会动态增删Invoker,并调用 Router 的 route 方法进行路由,过滤掉不符合路由规则的 Invoker。当FailoverClusterInvoker 拿到 Directory 返回的 Invoker 列表后,它会通过 LoadBalance 从 Invoker 列表中选择一个 Invoker。最后 FailoverClusterInvoker 会将参数传给 LoadBalance 选择出的 Invoker实例的 invoke 方法,进行真正的远程调用。
Dubbo 主要提供了这样几种容错方式:
根据上面的分析,我们知道消费者通过Cluster为调用的起点进行服务的调用。Cluster主要用于代理真正的invoker执行时做处理。而Invoker消费者服务会使用Protocol 调用 refer 方法生成 Invoker 实例。
这里主要调用的是doRefer方法,这里面就是最主要产生Directory并且注册和监听的主要代
码逻辑。
这里生成了RegistryDirectory,通过上面的流程图我们可以知道,RegistryDirectory缓存了所有的Invoker,Cluster会从RegistryDirectory中获取invoker列表。这里还有一步时buildRouterChain,这一步生成了路由过滤规则,在获取invoker列表的时候会通过路由规则对服务列表进行过滤。RegistryDirectory可以根据注册中心的服务提供者的变化而动态变化的。这里主要看一下里面的doList方法,也是选择服务列表的方法。
这里面有一个关键的步骤就是routerChain的route方法,这里就不展开去看了。主要是遍历所有的路由规则,选择满足条件的invoker。
回到刚开是说的服务的调用那快,我们说过服务调用依赖的是FailoverCluster,而FailoverCluster刚才上面已经分析过了通过doRefer方法已经生成了,现在我们就看一下FailoverCluster是怎么调用的。回到刚才的doJoin方法产生invoke的那里,我们进入方法。
最终生成了FailbackClusterInvoker。而 FailbackClusterInvoker最关键的是invoke方法,进入方法。这里是继承了一个抽象类AbstractClusterInvoker调用的invoke方法进入AbstractClusterInvoker的invoke方法。
这里有几个关键的步骤,list方会从RegistryDirectory中经过过滤获取到所有的invoker列表,然后获取负载均衡器,最后调用doInvoke方法,负载均衡是在doInvoke方法中执行的。
这里面实现了负载均衡和服务的调用。
我们可以看到,负载均衡策略都在select方发中。最后我们看最关键的一步,就是调用远程服务的方法。进入AbstractInvoker的invoke方法,这里调用了子类的doInvoke方法。invoke方法里面具体的细节这里就不讨论了,现在进入子了dubboIvoker查看doInvoke方法
这里面判断是否是同步还是异步,同步则调用currentClient的request方法并且同步等待结果,异步的情况则调用send方法。查看request方法
这里交给真正的渠道进行处理,这里的nettyChannel也是这里创建的。具体的细节这里就不讨论了。
到此dubbo的服务注册和消费以及信息缓存、路由、容错(Cluster组件)、负载均衡都粗略的说了一下。还有一个重要的内容就是dubbo的SPI,留到下一篇专门的讲述。