工作流涉及到服务提供者(Provider),注册中心(Registration),网络(Network)和服务消费者(Consumer):
服务提供者在启动的时候,会通过读取一些配置将服务实例化。
Proxy 封装服务调用接口,方便调用者调用。客户端获取 Proxy 时,可以像调用本地服务一样,调用远程服务。
Proxy 在封装时,需要调用 Protocol 定义协议格式,例如:Dubbo Protocol。
将 Proxy 封装成 Invoker,它是真实服务调用的实例。
将 Invoker 转化成 Exporter,Exporter 只是把 Invoker 包装了一层,是为了在注册中心中暴露自己,方便消费者使用。
将包装好的 Exporter 注册到注册中心。
服务消费者建立好实例,会到服务注册中心订阅服务提供者的元数据。元数据包括服务 IP 和端口以及调用方式(Proxy)。
消费者会通过获取的 Proxy 进行调用。通过服务提供方包装过程可以知道,Proxy 实际包装了 Invoker 实体,因此需要使用 Invoker 进行调用。
在 Invoker 调用之前,通过 Directory 获取服务提供者的 Invoker 列表。在分布式的服务中有可能出现同一个服务,分布在不同的节点上。
通过路由规则了解,服务需要从哪些节点获取。
Invoker 调用过程中,通过 Cluster 进行容错,如果遇到失败策略进行重试。
调用中,由于多个服务可能会分布到不同的节点,就要通过 LoadBalance 来实现负载均衡。
Invoker 调用之前还需要经过 Filter,它是一个过滤链,用来处理上下文,限流和计数的工作。
生成过滤以后的 Invoker。
用 Client 进行数据传输。
Codec 会根据 Protocol 定义的协议,进行协议的构造。
构造完成的数据,通过序列化 Serialization 传输给服务提供者。
Request 已经到达了服务提供者,它会被分配到线程池(ThreadPool)中进行处理。
Server 拿到请求以后查找对应的 Exporter(包含有 Invoker)。
由于 Export 也会被 Filter 层层包裹
通过 Filter 以后获得 Invoker
最后,对服务提供者实体进行调用。
Zookeeper和dubbo交互
ZookeeperRegistry 在实例化时,调用父类构造函数。在父类构造函数中,会创建一个定时任务,每隔5S执行retry( ) 方法。
在retry( ) 方法中,重试那些失败的动作。重试的动作包括:
Provider向zookeeper注册自身的url,生成一个临时的znode
Provider从Dubbo容器中退出,停止提供RPC调用。也就是移除zookeeper内自身url对应的znode
Consumer订阅 " /dubbo/…Service/providers" 目录的子节点,生成ChildListener
Consumer从Dubbo容器中退出,移除之前创建的ChildListener