你好,我是姚秋辰。

从今天开始,我们的课程就正式进入Spring Cloud环节了。我先带你学习微服务架构中一个最重要的原理概念:服务治理。在概念讲解之后,我还会向你介绍Nacos服务注册中心的体系结构。通过这节课的学习,你可以了解微服务的完整生命周期,知晓服务注册中心在微服务架构中发挥了什么作用,这些内容能让你对Nacos的体系架构有一个比较全面的认识。

首先,让我通过一个例子告诉你服务治理解决了什么问题。

我的系统包含两个微服务(服务A和服务B),每一个微服务有10个虚拟节点,两个服务组成了一个20台虚拟机的微服务集群。如果此时微服务A想要调用微服务B,我们怎么来发起这个调用呢?

一种通用做法是:在服务A的配置文件中添加一个指向服务B的地址,但这个地址并不直接指向任何一台服务B集群中的节点,而是指向一个VIP(虚拟IP地址)或者是一个网关。这个VIP或网关背后维护了B集群的服务节点列表,VIP层通过负载均衡策略再将请求转到后面配置的某一台服务器。我画了一幅图来描述这个服务调用过程。

从上面的图中我们可以看出,服务A与服务B之间互相不直接通信,服务调用完全依靠VIP作为中间人来完成。我们如果想要为服务集群扩容或缩容,必须将服务器配置到对应的VIP地址上。如果你的应用是一个由数百个微服务组成的大型应用,光是管理这些VIP Pool的人力成本就够网络运维团队喝上一壶了。

那在微服务架构中,怎么才能实现一种简单可靠的远程服务调用,不让VIP中间商赚差价呢?这就要说到我们的服务治理理论了。

服务治理初探

如果我们要解决中间商赚差价的问题,那么最好的办法就是让双方直连。因此,服务治理要解决的首要任务就是服务注册服务发现,通过这两项技术,我们就能让微服务之间发起面对面的直接调用。

那么服务A怎么知道服务B中每台机器的地址呢?为了让服务A拿到服务B的机器清单,我们需要搭建一个中心化的服务注册中心,服务B只要将自己的信息添加到注册中心里,服务A就能够从注册中心获取到服务B的所有节点列表。我画了一张图来帮助你更好地理解这个过程。

从上图中的步骤中我们可以看出,首先,服务B集群向注册中心发起了注册,将自己的地址信息上报到注册中心,这个过程就是服务注册。接下来,每隔一段时间,服务A就会从服务中心获取服务B集群的服务列表,或者由服务中心将服务列表的变动推送给服务A,这个过程叫做服务发现;最后,服务A根据本地负载均衡策略,从服务列表中选取某一个服务B的节点,发起服务调用。

在这个过程中,注册中心的角色是一个中心化的信息管理者,所有的微服务节点在启动后都会将自己的地址信息添加到注册中心。在服务注册的过程中,有两个关键信息是最为重要的,我把它们列在了这里。

  1. 服务名称:服务名称通常默认是spring.application.name属性,在服务注册过程中我们必须将应用服务名上报到注册中心,这样其他服务才能根据服务名称找到对应的服务节点列表;
  2. 地址信息:包括服务节点的IP地址和端口。

通过上面这两个信息,调用方就能精准定位到目标微服务。除此之外,服务注册请求中还包含一些额外的注册信息,我将在Nacos的实战环节为你详细讲解这些注册参数。

通过服务注册和服务发现,我们已经能够实现端到端的服务调用链路,但这个方案似乎还并不完善,因为它缺少了异常容错的机制。

如果服务B集群因为未知的网络故障导致无法响应服务,这时候服务A向服务B发起了服务调用,就会发生超时或者服务无响应的异常情况。那我们如何在服务治理方案中规避这类问题呢?

业界通用的解决方案是“heathcheck”或者“heartbeat”,又叫“服务探活”或“心跳检查”。注册中心可以通过这种机制来标记异常服务,这样一来,Client端在发送服务请求的时候就能避开异常节点。

我将这些异常处理的步骤添加到了服务注册流程中,并画了一个完整的微服务生命周期的图,你可以参考一下。

看了图片,你可能会问,怎么还有一个“服务剔除”呢?它是怎么实现的?

先说一个大前提。所有的服务都要在注册中心进行注册,而且每个节点都需要每隔一段时间向注册中心同步自己当前的状态,我们很形象地称这个过程为heartbeat(心跳)。

如果节点持续发送心跳信息,则一切正常,服务可以被发现;如果注册中心在一段时间内没有收到Client的心跳包,注册中心就会将这个节点标记为下线状态,进而将该服务从服务列表中剔除。

这里我再补充一句,我们上面说的“服务剔除”是由注册中心主导的“被动下线”场景。除此之外还有一类服务“主动下线”的场景,也就是当服务节点关闭或者重启的时候,通过发送一条“服务下线”指令给到注册中心,将当前节点标记为下线状态。

到这里,相信你已经完全理解了微服务生命周期各个状态间的流转,也知道了服务注册中心在微服务生命周期中扮演了什么角色。

接下来,我们来了解Spring Cloud中的服务注册中心Nacos。

Nacos体系架构

Nacos有三个核心知识点:领域模型、数据模型和基本架构,这是我们整体把握Nacos架构的关键。下面我们来依次看看。

领域模型

Nacos领域模型描述了服务与实例之间的边界和层级关系。Nacos的服务领域模型是以“服务”为维度构建起来的,这个服务并不是指集群中的单个服务器,而是指微服务的服务名。

“服务”是Nacos中位于最上层的概念,在服务之下,还有集群和实例的概念。为了方便你理解这三者的层级关系,我画了一张图,你可以参考一下。

从上面的图中你可以看出,Nacos的服务领域模型从上到下分为了服务、集群和实例三层,我分别介绍一下这三个层次所包含的重要数据内容。

  1. 服务

在服务这个层级上我们可以配置元数据和服务保护阈值等信息。服务阈值是一个0~1之间的数字,当服务的健康实例数与总实例的比例小于这个阈值的时候,说明能提供服务的机器已经没多少了。这时候Nacos会开启服务保护模式,不再主动剔除服务实例,同时还会将不健康的实例也返回给消费者。尽管这样做可能造成请求失败,但间接保证了最低限度的服务可用性。

  1. 集群

一个服务由很多服务实例组成,在每个服务实例启动的时候,我们可以设置它所属的集群,在集群这个层级上,我们也可以配置元数据。除此之外,我们还可以为持久化节点设置健康检查模式。

所谓持久化节点,是一种会保存到Nacos服务端的实例,即便该实例的客户端进程没有在运行,实例也不会被服务端删除,只不过Nacos会将这个持久化节点状态标记为不健康,Nacos可以采用一种“主动探活”的方式来对持久化节点做健康检查。

除了持久化节点以外,大部分服务节点在Nacos中以“临时节点”的方式存在,它是默认的服务注册方式,从名字中我们就可以看出,这种节点不会被持久化保存在Nacos服务器,临时节点通过主动发送heartbeat请求向服务器报送自己的状态。

  1. 实例

这里所说的实例就是指服务节点,我们可以在Nacos控制台查看每个实例的IP地址和端口、编辑实例的元数据信息、修改它的上线/下线状态或者配置路由权重等等。

你会发现,在这三个层级上都有“元数据”这一数据结构,你可以把它理解为一组包含了服务描述信息(如服务版本等)和自定义标签的数据集合。Client端通过服务发现技术可以获取到每个服务实例的元数据,你可以将自定义的属性加入到元数据并在Client端实现某些定制化的业务场景。

了解了领域模型之后,你知道服务调用的发起方是如何定位到领域模型中的服务实例的吗?这就要说起Nacos的数据模型了。

数据模型

Nacos的数据模型有三个层次结构,分别是Namespace、Group和Service/DataId,我画了一幅图,帮你理解这三个层次之间的包含关系:

从上图中你可以看出,Namespace、Group和Service/DataId是一个依次包含的结构,我分别对每一层做一个简单介绍。

通过Namespace + Group + Service/DataID,我们就可以精准定位到一个具体的微服务。比如,我想调用生产环境下A分组的订单服务,那么对应的服务寻址的Key就是类似Production.A.orderService的组合。

了解了Nacos的数据模型之后,我再来带你看一下Nacos的基本架构,这样你就对Nacos的功能模块有一个更全面的认识。

Nacos基本架构

Nacos的核心功能有两个,一个是 Naming Service,也就我们用来做服务发现的模块;另一个是 Config Service,用来提供配置项管理、动态更新配置和元数据的功能,关于配置管理的内容我会放到课程中的配置管理阶段为你详细讲解。

我这里用一张Nacos社区的基本架构图来作为示例,带你看一下Nacos在功能模块层面的基本架构。

从上面的图中你可以看出,Provider APP和Consumer APP通过Open API和Nacos服务器的核心模块进行通信。这里的Open API是一组对外暴露的RESTful风格的HTTP接口。如果你对Open API里具体的接口感兴趣,可以从Nacos官方网站获取更多的关于Open API的详细信息。

在Nacos和核心模块里,Naming Service提供了将对象和实体的“名字”映射到元数据的功能,这是服务发现的基础功能之一。例如,我想要调用OrderService,我手里有这个服务的Namespace和Group信息,那么我就可以通过Naming Service定位到这个服务对应的实例列表。同理,如果我有一个DNS名称,同样可以借助Naming Service获取DNS背后配置的IP列表。以上两个场景就分别对应了服务发现和DNS功能,这两个场景都是Naming Service的核心场景。

Nacos还有一个相当重要的模块:Nacos Core 模块。它可以提供一系列的平台基础功能,是支撑Nacos上层业务场景的基石。我挑选了几个Nacos Core中包含的重要功能,你可以看一下。

除了Nacos Core提供的这些功能以外,Nacos还有一个“一致性协议”,用来确保Nacos集群中各个节点之间的数据一致性。Nacos内部支持两种一致性协议,一种是侧重一致性的Raft协议,基于集群中选举出来的Leader节点进行数据写入;另一种是针对临时节点的Distro协议,它是一个侧重可用性(或最终一致性)的分布式一致性协议。

到这里,我们就完成了Nacos的基本架构部分的学习。

总结

现在,我们来回顾一下这节课的重点内容。今天我带你了解了服务治理所解决的问题。在这个问题解决的过程中,你自然建立起了对微服务生命周期各个状态的了解,你也能清楚地感受到服务注册中心Nacos的重要程度。为了让你更全面地认识 Nacos的功能体系,我为你讲解了领域模型、数据模型和基础架构。

此外,我要给你一个小提示,虽然这节课我并没有深入介绍Nacos底层一致性协议的原理,但一致性协议是近年来面试中常问到的热点问题,我建议你借这个机会,去主动了解一些常见的经典协议。

在后面的课程中,我将带你搭建一个Nacos服务器集群,通过对Spring Boot项目的Nacos服务化改造,将实战项目里的本地方法调用改为微服务架构下的远程调用。通过实战环节的动手练习,你将对本节课的理论内容有更深的理解。

思考题

如果你正在开发的业务系统采用的是微服务架构,那么你如何实现远程服务调用呢?欢迎在留言区写下你的技术方案和技术选型,最好能再描述下背后的原理。

好啦,这节课就结束啦。欢迎你把这节课分享给更多对Spring Cloud感兴趣的朋友。我是姚秋辰,我们下节课再见!

评论