服务注册与发现
服务发现(Service Discovery)
理由:
服务通常需要相互调用。在单片应用程序中,服务通过语言级的方法或过程调用彼此调用。在传统的分布式系统部署中,服务在固定的、众所周知的位置(主机和端口)运行,因此可以使用HTTP/REST或一些RPC机制轻松地相互调用。然而,现代的基于微服务的应用程序通常在虚拟化或容器化的环境中运行,其中服务的实例数量及其位置会动态变化。
- 每个服务实例对外需要暴露远程调用的API或或者RPC机制的服务调用
- 有许多服务实例他们的IP是动态变化的
- 虚拟机和容器通常分配的是动态IP
服务实例的网络地址是动态分配的。而且,由于自动扩展,失败和更新,服务实例的配置也经常变化。这样一来,你的客户端代码需要一套更精细的服务发现机制。
服务发现机制通过服务注册表实时获取可用服务的信息。
两种模式
- 客户端服务发现(client-side discovery)
- 服务器端服务发现(server-side discovery)
客户端服务发现(client-side discovery)
客户端负责决定可用的服务实例的网络地址,以及围绕他们的负载均衡。
客户端向服务注册表(service registry)发送一个请求,服务注册表是一个可用服务实例的数据库。
一个服务实例被启动时,它的网络地址会被写到注册表上;当服务实例终止时,再从注册表中删除。这个服务实例的注册表通过心跳机制动态刷新。
优点:
- 这个模式相对更直接一点,除了服务注册中心,没有要改变的地方;
- 并且,因为客户端了解可用的服务实例,它能做出智能、针对特定应用的负载均衡决策,比如使用一致性哈希。
缺点:
- 这种模式的一个重要的缺陷是它将客户端与服务注册中心耦合在一起。你必须为服务客户端使用的每种编程语言和框架都实现服务发现逻辑;
服务器端服务发现模式(server-side discovery)
客户端通过负载均衡器向一个服务发送请求,这个负载均衡器会查询服务注册表,并将请求路由到可用的服务实例上。通过客户端的服务发现,服务实例在服务注册表上被注册和注销。
AWS的ELB(Elastic Load Blancer)就是一个服务器端服务发现路由器。一个ELB通常被用来均衡来自互联网的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一个客户端通过ELB发送请求(HTTP或TCP)时,使用的是DNS,ELB会均衡这些注册的EC2实例或ECS(EC2 Container Service)容器的流量。没有另外的服务注册表,EC2实例和ECS容器也只会在ELB上注册。
HTTP服务器和类似Nginx、Nginx Plus的负载均衡器也可以被用做服务器端服务发现负载均衡器。例如,Consul Template可以用来动态配置Nginx的反向代理。
优点:
- 服务发现的细节从客户端抽象出来,客户端只需要给负载均衡器发请求即可。这种方式避免为服务客户端使用的每种编程语言和框架都实现服务发现逻辑;
- 一些部署环境免费提供了这种功能;
缺点:
- 除非部署环境提供负载均衡器,否则它又是另一个需要设置和管理的高度可用的系统组件;
服务注册表 (Service Registry)
服务注册表是服务发现的关键部分,是一个包含了服务实例的网络地址的数据库,必须是高可用和最新的。
客户端可以缓存从服务注册表处获得的网络地址。但是,这些信息最终会失效,客户端会找不到服务实例。所以,服务注册表由一个服务器集群组成,通过应用协议来保持一致性。
Netflix Eureka是一个服务注册表的好例子。它提供了一个REST API用来注册和查询服务实例。一个服务实例通过POST请求来注册自己的网络位置,每隔30秒要通过一个PUT请求重新注册。注册表中的一个条目会因为一个HTTP DELETE请求或实例注册超时而被删除,客户端通过一个HTTP GET请求来检索注册的服务实例。
服务注册中心的其他例子:
- etcd:高度可用,分布式,一致性的键值存储,用来共享配置或作为服务注册中心。Kubernetes和Cloud Foundry 这两个著名的项目使用了它;
- Consul:一个发现和配置服务的工具,提供了API允许客户端注册并发现服务,也能通过健康检查来确定服务的可用性;
- Apache ZooKeeper:用于分布式应用的广泛使用的、高性能的协调服务。开始作为Hadoop的子项目,但是现在是一个独立的顶级项目;
服务注册(Service Registration)
服务实例必须实现从服务注册中心注册和注销。
需要考虑的点:
- 服务实例必须在服务注册表注册及注销
- 服务实例必须在崩溃的时候从服务注册表注销
- 服务实例必须在虽然处于服务通但不能正常做反馈的时候从服务注册表注销
两种模式
- 自我注册模式
- 第三方注册模式
自我注册模式(service registration)
服务实例自己负责从服务注册中心注册和注销。并且如果必要的话,服务实例要发送心跳请求来防止注册过期。
优点:
- 相对简单,并且不要求额外的系统组件;
- 服务实例知道自己处于什么状态,可以控制自己的状态;
缺点:
- 将服务实例和服务注册中心耦合,导致为服务使用的每种编程语言和框架都实现服务注册逻辑;
- 正在运行但无法正常处理请求的服务实例通常缺乏从服务注册中心注销自身的自我意识。
第三方注册模式(3rd party registration)
当使用第三方注册模式时,服务实例不负责注册自己到服务注册中心,而是通过其他称为服务注册组件的系统组件来处理服务注册。
服务注册组件通过轮询部署环境或者订阅事件来追踪运行实例的集合的变化。当它注意到有新的可用的服务实例时,就会将该实例注册到服务注册中心。服务注册组件也可以注销终止的服务实例。
运用:
- Netflix Prana - a “side car” application that runs along side a non-JVM application and registers the application with Eureka.
- AWS Autoscaling Groups automatically (un)registers EC2 instances with Elastic Load Balancer
- Joyent’s Container buddy runs in a Docker container as the parent process for the service and registers it with the registry
- Registrator - registers and unregisters Docker containers with various service registries
- Clustering frameworks such as Kubernetes and Marathon (un)register service instances with the built-in/implicit registry
优点:
- 一个主要的优点是服务与服务注册中心解耦,不需要为服务使用的每种编程语言和框架都实现服务注册逻辑。服务注册逻辑通过一个专门的服务以集中的方式处理;
- 可以通过健康检查来实现服务的注册与注销。
缺点:
- 对服务实例的状态只知道是否正在运行,不能知道是否可以正常访问;
- 除非该注册组件在部署环境中内建,需要设置和管理一个高可用的系统组件;
服务注册逻辑。服务注册逻辑通过一个专门的服务以集中的方式处理;
- 可以通过健康检查来实现服务的注册与注销。
缺点:
- 对服务实例的状态只知道是否正在运行,不能知道是否可以正常访问;
- 除非该注册组件在部署环境中内建,需要设置和管理一个高可用的系统组件;