如何把握分布式服务发布和服务引用流程?

在分布式系统和微服务架构中,系统的能力来自于服务与服务之间的交互和集成。为了实现这一过程,就需要服务提供者对外暴露可以访问的入口,而服务消费者就基于这些入口对服务提供者发起访问。

我们来举一个例子,如果我们想要发布一个DemoService,那么可以使用这样的代码。

DemoService service = new…;

RpcServer server = new…;

server.export(DemoService.class, demo, options);

而对DemoService服务进行导入的表现形式可以采用如下所示的代码风格。

RpcClient client =

DemoService service = client.refer(DemoService.class);

service.call(“how are you?”);

显然,就这两段代码而言,我们都觉得很简单。但事实上,想要实现这样的效果,开发人员要做的事情非常多。今天,我们就将从这个简单的示例出发,探讨背后的服务发布和引用流程。

服务发布和引用

在当前主流的分布式服务框架中,无论是Dubbo还是Spring Cloud,都提供了类似上面介绍的服务发布和引用功能。通过对这些框架的实现机制进行抽象和体量,我们实际上可以梳理出一套统一的设计和开发流程。接下来,让我们先来看服务的发布流程

服务发布

先抛开具体的技术和框架,我们可以简单抽象出如下图所示的服务发布整体流程。


上图中包含了服务发布过程中的各个核心组件,包括发布启动器、动态代理、发布管理器、协议服务器和中心。我们先对这些核心组件做一一展开。

  1. 发布启动器

发布启动器(Launcher)的核心作用有两点,一个是确定服务的发布形式,一个是启动服务发布过程。在目前主流的开发框架中,配置化、API调用和使用注解是最常见的三种发布形式。


以上三种方式各有利弊,在日常开发过程中,配置和注解比较常用,而API调用则主要完成服务与服务之间的集成。

讲完发布形式,我们来讨论如何启动服务发布过程。


可以看到,我们可以使用Spring容器来完成基于配置化和注解形式下的服务启动过程。而对于API调用而言,由于不一定会借助于容器,所以可以直接使用main函数来实现这一目标。

  1. 动态代理

动态代理是远程过程调用中非常核心的一个技术组件,在服务发布和服务引用过程中都会用到,其主要作用就是为了简化服务发布和引用的开发难度,以及确保能够对发布过程进行扩展和定制。

  1. 发布管理器

服务发布过程需要使用专门的组件来进行统一管理,这个组件就是发布管理器。该组件需要判断本次发布是否成功,然后在服务发布成功之后,把服务的地址信息注册到注册中心。这而这里的服务地址信息则来自于协议服务器。

  1. 协议服务器

在服务发布过程中,在物理上真正建立网络连接,并对网络端口到进行绑定和释放的组件是协议服务器。协议服务器还会对检测网络心跳以及在连接失败之后进行重连操作。


用于发布服务的常见协议包括HTTP、RMI、Hessian等。我们也可以自己定义这样的协议,例如Dubbo框架就实现了一套自定义的Dubbo协议。

  1. 注册中心

注册中心的作用是存储和管理服务定义的各类元数据,并能感知到这些元数据的变化。注册中心的核心机制就是服务注册和发现,业界也存在一批主流的注册中心实现工具。


以上所示的服务发布流程图有一定的共性,可以通过转化映射到具体的某个框架。事实上,基于Dubbo的服务发布流程与上述过程非常类似。我们在今天后面的内容中会做进一步分析。

服务引用

相较服务发布,服务的引用是一个导入(Import)的过程,整体流程如下图所示。


从上图中,我们可以看到服务调用流程与服务发布流程呈对称结构,所包含的组件包括:

  1. 调用启动器

调用启动器和发布启动器是对应的,这里不再重复介绍。

  1. 动态代理

在服务引用过程中,动态代理的作用就是确保远程调用过程的透明化,即开发人员可以使用本次对象来完成对远程对象的处理。


  1. 调用管理器

和发布管理器相比,调用管理器的核心功能是提供了一种缓存机制,从而确保根据保存在服务调用者本地的远程服务地址信息来发起调用。

  1. 协议客户端

和协议服务器相对应,协议客户端会创建与服务端的网络连接,发起请求并获取结果。

  1. 注册中心

注册中心在这里的作用是提供查询服务定义元数据的入口。

以上所示的服务引用流程图同样有一定的共性,可以通过转化映射到具体的某个框架。事实上,基于Dubbo的服务引用流程与上述过程也比较类似。

对比服务发布,服务引用的实现过程通常会更加复杂一点。这在Dubbo框架中体现的就比较明显。接下来,我们就以Dubbo框架为例,分析它的服务发布和引用流程。

Dubbo中的服务发布和引用

Dubbo中的服务发布

Dubbo中的服务发布基本遵循上我们前面所抽象的服务发布流程,但也添加了一些优化措施。体现在两方面,一方面是发布的时效性,另一方面是发布的作用范围。

我们先来讨论Dubbo暴露服务的两种时效,一种是延迟暴露,一种是正常暴露。


你可能会问,Dubbo为什么要考虑发布时效这个问题呢?主要原因在于为了提供平滑发布机制。如果Dubbo服务本身还没有完全启动成功,那这时候对外暴露服务是没有意义的,我们可以通过设置延迟时间来确保服务在发布的时间点上就是可用的。

另一方面,在Dubbo中提供了四种发布作用范围的选项。


可以看到,如果我们把scope配置为none,则不发布这个Dubbo服务;如果配置local,则说明该服务只会在当前JVM中进行暴露,从而可以提高服务调用的效率;如果配置scope=remote,那么该服务就会进行远程暴露;而如果不配置或者不配置为以上三种中的任何一种,则Dubbo会既暴露本地服务又暴露远程服务。

Dubbo中的服务引用

正如前面所提到的,与服务发布相比,Dubbo等分布式服务框架中的服务调用整体过程会更加复杂一点。原因在于,在服务调用过程中,因为面对的服务一般都会部署成集群模式,势必涉及到负载均衡。而如果调用超时或失败,还会采用集群容错机制。

接下来来看Dubbo中如何实现服务引用。我们在ReferenceConfig的init方法中找到了如下所示的createProxy方法。这个createProxy方法是理解Dubbo服务引用的关键入口,我们梳理它的主体结构如下所示。

private T createProxy(Map<String, String> map) {

       if (isJvmRefer) {

//生成本地引用URL,使用injvm协议进行本地调用

        }else {           

//URL不为空,执行点对点调用

} else {

//加载注册中心URL          

}

                

if (urls.size() == 1) {

//单个服务提供者,直接调用               

       } else {   

//多个服务提供者,则构建集群      

         if (registryURL != null) {

                     // 如果注册中心链接不为空,则将通过注册中心执行集群调用                           } else {

                     //反之,直接执行集群调用

         }

// 生成服务代理类

         return (T) proxyFactory.getProxy(invoker);

}

在上述流程中,我们明确了Dubbo中服务引用的几种不同场景,这些场景对调用管理其的功能做了扩展,但整体流程是一致的。

在远程过程调用的实现思路上,主要包括服务发布和服务引用两大维度。今天的内容围绕远程服务的发布和引用流程展开了详细的讨论,这部分内容是我们构建分布式系统的基本前提。

同时,基于这套服务发布和引用流程,我们对Dubbo这款主流的分布式服务框架的内部实现原理,对如何进行远程/本地服务暴露、如何实现对远程服务的调用也进行分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值