在微服务简介篇,我们已经介绍过微服务架构中要解决的四个基本的问题。从本节课开始我们来学习如何实现服务的管理。
设想下,我们写了一些通过REST API或者Thrift API调用某个服务的代码,为了发起这个请求,代码需要知道服务实例的网络地址(IP 地址和端口号)。在传统运行在物理机器上的应用中,某个服务实例的网络地址一般是静态的,比如,代码可以从只会偶尔更新的配置文件中读取网络地址。
然而在现在流行的基于云平台的微服务应用中, 有更多如下图所示的困难问题需要去解决:
服务实例需要动态分配网络地址,而且,一组服务实例可能会因为自动扩展、失败或者升级发生动态变化,因此客户端代码应该使用更加精细的服务发现机制。
在生产实践中,主要有两种服务发现机制:客户端发现和服务端发现。我们分别来介绍这两种机制:
当我们使用客户端发现的时候,客户端负责决定可用服务实例的网络地址并且在集群中对请求负载均衡, 客户端访问服务登记表,也就是一个可用服务的数据库,然后客户端使用一种负载均衡算法选择一个可用的服务实例然后发起请求。该模式如下图所示:
该模式和我们之前在微服务简介章节介绍的服务发现机制中的客户端机制是一样的,如图所示:
服务实例的网络地址在服务启动的时候被登记到服务注册表中 ,当实例终止服务时从服务注册表中移除。服务实例的注册一般是通过心跳机制阶段性的进行刷新。
与客户端发现模式对应的,另外一种服务发现模式称之为服务端发现模式,整体架构如下:
在该种模式下,客户端通过一个负载均衡器向服务发送请求,负载均衡器查询服务注册表并把请求路由到一台可用的服务实例上。和客户端发现一样,服务实例通过服务注册表进行服务的注册和注销。
同样的,服务端发下模式也有优势和缺点:
服务注册表是服务发现的关键部分,它是一个包含服务实例网络地址的的数据库。一个服务注册表需要高可用和实时更新,客户端可以缓存从服务注册表获取的网络地址。然而,这样的话缓存的信息最终会过期,客户端不能再根据该信息发现服务实例。因此,服务注册表对集群中的服务实例使用复制协议来维护一致性。
举个例子:Netflix Eureka是典型的服务注册表的案例实现,它为服务实例的注册与查询提供了REST API:一个服务实例可以使用POST来注册自己的网络地址,它必须每30秒通过PUT去刷新,服务实例可以直接或者在服务实例注册超时的时候使用DELETE删除注册表中的信息,另外客户端可以使用HTTP GET获取注册实例的信息。
当然,除了Netflix Eureka以外,还有:
服务实例必须使用服务注册表来进行服务的注册和注销,在实践过程中有不同的方式来实现服务的注册和注销:
self-registration模式有一些优势也有一些劣势:优势之一是它相对简单,而且不强制使用其他的系统组件。然而,一个很大的劣势是 它使得服务实例和服务注册表强耦合 ,你必须在每一个使用服务的客户端编程语言和架构代码中实现注册逻辑。
third-party registration模式也有一些优势和劣势:主要优势是使得服务从服务注册表中被解耦,你不必为开发者使用的每种开发语言和框架实现服务注册的逻辑,相反,服务实例的注册被一个专有服务以集中式的方式处理。该模式的劣势是,除非它被内置在部署环境中,不然这又是一个需要被设置和管理的高可用系统组件。
在一个微服务应用中,一组运行的服务实例是动态变化的,实例有动态分配的网络地址,因此,为了使得客户端能够向服务发起请求,必须要要有服务发现机制。
服务发现的关键是服务注册表,服务注册表是可用服务实例的数据库,它提供了管理和查询使用的API。服务实例使用这些管理API进行服务的注册和注销,系统组件使用查询API来发现可用的服务实例。
我们选择Consul来进行学习。
Consul最新版本是v1.5.1版本。