这是关于使用微服务架构建立应用系列的第四篇文章。第一篇介绍了微服务架构的模式,讨论了使用微服务架构的优缺点。第二和第三篇描述了微服务架构内部的通信机制。这篇文章中,咱们将会探讨服务发现相关问题。html
设想一下,咱们正在写代码使用了提供REST API或者Thrift API的服务,为了完成一次服务请求,代码须要知道服务实例的网络位置(IP地址和端口)。传统应用都运行在物理硬件上,服务实例的网络位置都是相对固定的。例如,代码能够从一个常常变动的配置文件中读取网络位置。
而对于一个现代的,基于云微服务的应用来讲,这倒是一个很麻烦的问题。其架构如图所示:nginx
服务实例的网络位置都是动态分配的,并且由于扩展、失效和升级等需求,服务实例会常常动态改变,所以,客户端代码须要使用一种更加复杂的服务发现机制。
目前有两大类服务发现模式:客户端发现和服务端发现。
咱们先来来讨论一下客户端发现。git
当使用客户端发现模式时,客户端负责决定相应服务实例的网络位置,而且对请求实现负载均衡。客户端从一个服务注册服务中查询,其中是全部可用服务实例的库。客户端使用负载均衡算法从多个服务实例中选择出一个,而后发出请求。
下图显示的是这种模式的架构图:github
服务实例的网络位置是在启动时注册到服务注册表中,而且在服务终止时从注册表中删除。服务实例注册信息通常是使用心跳机制来按期刷新的。
Netflix OSS提供了一种很是棒的客户端发现模式。Netflix Eureka是一个服务注册表,为服务实例注册管理和查询可用实例提供了REST API接口。Netflix Ribbon是一种IPC客户端,与Eureka合同工做实现对请求的负载均衡。咱们会在后面详细讨论Eureka。
客户端发现模式也是优缺点分明。这种模式相对比较直接,并且除了服务注册表,没有其它改变的因素。除此以外,由于客户端知道可用服务注册表信息,所以客户端能够经过使用哈希一致性(hashing consistently)变得更加聪明,更加有效的负载均衡。
而这种模式一个最大的缺点是须要针对不一样的编程语言注册不一样的服务,在客户端须要为每种语言开发不一样的服务发现逻辑。
咱们分析过客户端发现后,再看看服务端发现。算法
另一种服务发现的模式是服务端发现模式(server-side discovery pattern),下图展示了这种模式的架构图:docker
客户端经过负载均衡器向某个服务提出请求,负载均衡器向服务注册表发出请求,将每一个请求转发往可用的服务实例。跟客户端发现同样,服务实例在服务注册表中注册或者注销。
AWS Elastic Load Balancer(ELB)是一种服务端发现路由的例子,ELB通常用于均衡从网络来的访问流量,也可使用ELB来均衡VPC内部的流量。客户端使用DNS,经过ELB发出请求(HTTP或者TCP)。ELB负载均衡器负责在注册的EC2实例或者ECS容器之间均衡负载,并不存在一个分离的服务注册表,而EC2实例和ECS实例也向ELB注册。
HTTP服务和相似NGINX和NGINX Plus的负载均衡器均可以做为服务端发现均衡器。例如,这篇博文就描述如何使用Consul Template来动态配置NGINX反向代理。Consul Template是周期性从存放在Consul Template注册表中配置数据重建配置文件的工具。当文件发生变化时,会运行一个命令。在如上博客中,Consul Template产生了一个nginx.conf文件,用于配置反向代理,而后运行一个命令,告诉NGINX从新调入配置文件。更复杂的例子能够用HTTP API或者DNS动态从新配置NGINX Plus。
某些部署环境,例如Kubernetes和Marathon在集群每一个节点上运行一个代理,此代理做为服务端发现负载均衡器。为了向服务发出请求,客户端使用主机IP地址和分配的端口经过代理将请求路由出去。代理将次请求透明的转发到集群中可用的服务实例。
服务端发现模式也有优缺点。最大的优势是客户端无需关注发现的细节,客户端只须要简单的向负载均衡器发送请求,实际上减小了编程语言框架须要完成的发现逻辑。并且,如上说所,某些部署环境免费提供以上功能。
这种模式也有缺陷,除非部署环境提供负载均衡器,不然负载均衡器是另一个须要配置管理的高可用系统功能。数据库
服务注册表是服务发现很重要的部分,它是包含服务实例网络地址的数据库。服务注册表须要高可用并且随时更新。客户端能够缓存从服务注册表得到的网络地址。然而,这些信息最终会变得过期,客户端也没法发现服务实例。所以,服务注册表由若干使用复制协议保持同步的服务器构成。
如前所述,Netflix Eureka是一个服务注册表很好地例子,提供了REST API注册和请求服务实例。 服务实例使用POST请求注册网络地址,每30秒必须使用PUT方法更新注册表,使用HTTP DELETE请求或者实例超时来注销。能够想见,客户端可使用HTTP GET请求接受注册服务实例信息。
Netflix经过在每一个AWS EC2域运行一个或者多个Eureka服务实现高可用性,每一个Eureka服务器都运行在拥有弹性IP地址的EC2实例上。DNS TEXT记录用于存储Eureka集群配置,其中存放从可用域到一系列Eureka服务器网络地址的列表。当Eureka服务启动时,向DNS请求接受Eureka集群配置,确认同伴位置,给本身分配一个未被使用的弹性IP地址。
Eureka客户端—服务和服务客户端—向DNS请求发现Eureka服务的网络地址,客户端首选使用同一域内的服务。然而,若是没有可用服务,客户端会使用另一个可用域的Eureka服务。
另一些服务注册表例子包括:apache
另外,前面强调过,某些系统,例如Kubernetes、Marathon和AWS并无独立的服务注册表,对他们来讲,服务注册表只是一个内置的功能。
如今咱们来看看服务注册表的概念,看看服务实例是如何在注册表中注册的。编程
如前所述,服务实例必须向注册表中注册和注销,如何注册和注销也有一些不一样的方式。一种方式是服务实例本身注册,也叫自注册模式(self-registration pattern);另一种方式是为其它系统提供服务实例管理的,也叫第三方注册模式(third party registration pattern)。咱们来看看自注册模式。缓存
当使用自注册模式时,服务实例负责在服务注册表中注册和注销。另外,若是须要的话,一个服务实例也要发送心跳来保证注册信息不会过期。下图描述了这种架构:
一个很好地例子是 Netflix OSS Eureka client。Eureka客户端负责处理服务实例的注册和注销。Spring Cloud project,实现了多种模式,包括服务发现,使得向Eureka服务实例自动注册时更容易。能够用@EnableEurekaClient注释Java配置类。
自注册模式也有优缺点。一个优势是,相对简单,不须要其余系统功能。而一个主要缺点则是,把服务实例跟服务注册表联系起来。必须在每种编程语言和框架内部实现注册代码。
另一个方法,不须要链接服务和注册表,则是第三方注册模式。
当使用第三方注册模式时,服务实例并不负责向服务注册表注册,而是由另一个系统模块,叫作服务管理器,负责注册。服务管理器经过查询部署环境或订阅事件来跟踪运行服务的改变。当管理器发现一个新可用服务,会向注册表注册此服务。服务管理器也负责注销终止的服务实例。下图是这种模式的架构图。
一个服务管理器的例子是开源项目Registrator,负责自动注册和注销被部署为Docker容器的服务实例。Reistrator支持多种服务管理器,包括etcd和Consul。
另一个服务管理器例子是NetflixOSS Prana,主要面向非JVM语言开发的服务,也称为附带应用(sidecar application),Prana使用Netflix Eureka注册和注销服务实例。
服务管理器是部署环境内置的模块。有自动扩充组建立的EC2实例能够自向ELB自动注册,Kubernetes服务自动注册而且对发现服务可用。
第三方注册模式也是优缺点都有。主要的优势是服务跟服务注册表是分离的,不须要为每种编程语言和架构完成服务注册逻辑,替代的,服务实例是经过一个集中化管理的服务进行管理的。
一个缺点是,除非这种服务被内置于部署环境中,不然也须要配置管理一个高可用的系统。
在一个微服务应用中,服务实例运行环境是动态变化的。实例网络地址也是动态变化的,所以,客户端为了访问服务必须使用服务发现机制。
服务发现关键部分是服务注册表,也就是可用服务实例的数据库。服务注册表提供一种注册管理API和请求API。服务实例使用注册管理API来实现注册和注销。
请求API用于发现可用服务实例,相对应的,有两种主要服务发现模式:客户端发现和服务端发现。
在使用客户端发现的系统中,客户端向服务注册表发起请求,选择可用实例,而后发出服务请求
而在使用服务端发现的系统中,客户端经过路由转发请求,路由器向服务注册表发出请求,转发此请求到某个可用实例。
服务实例注册和注销主要有两类方式。一种是服务实例自动注册到服务注册表中,也就是自注册模式;另一种则是某个系统模块负责处理注册和注销,也就是第三方注册模式。
在某些部署环境中,须要配置本身的服务发现架构,例如:Netflix Eureka、etcd或者Apache ZooKeeper。而在另一些部署环境中,则自带了这种功能,例如Kubernetes和Marathon 负责处理服务实例的注册和注销。他们也在每一个集群节点上运行代理,来实现服务端发现路由器的功能。
HTTP反向代理和负载据衡器(例如NGINX)能够用于服务发现负载均衡器。服务注册表能够将路由信息推送到NGINX,激活一个实时配置更新;例如,可使用 Consul Template。NGINX Plus 支持额外的动态从新配置机制,可使用DNS,将服务实例信息从注册表中拉下来,而且提供远程配置的API。
在将来的博客中,咱们还将深刻探讨微服务其它特色。能够注册NGINX邮件列表来得到最新产品更新提示。
此篇其它博客译文参见以下地址:
来自:http://dockone.io/article/771