背景
服务通常需要调用其他服务。单体应用中,服务通过语言级别的方法或者过程调用另外的服务。在传统的分布式部署中,服务运行在固定,已知的地址(主机和端口),因此可以请求的通过HTTP/REST或其他RPC机制调用。然而,一个现代的微服务应用通常运行在虚拟或者容器环境,服务实例数和它们的地址都在动态改变。
因此,你需要实现一种机制,允许服务的客户端向动态变更的一组短暂的服务实例发起请求。
问题
如何让服务的客户端 - API网关或者其他服务 - 发现服务实例的地址
限制
- 每个服务在特定地址(主机和端口)实例暴露一个远程API,比如HTTP/REST,或者Thrift等等
- 服务实例的数量和他们的地址动态改变。
- 虚拟机和容器通常分配动态IP。
- 服务实例数可能动态变化。比如,EC2 Autoscaling Group基于负载确定实例数。
解决方案
当对一个服务发起请求时,客户端对运行在一个已知地址的路由(也叫做负载均衡)发起请求。路由查询服务注册中心,可能构建在路由内,将请求转发给可用的服务实例。
下图介绍了这个模式的结构。
示例
AWS Elastic Load Balancer(ELB)是服务端服务发现路由的一个例子。客户端对ELB发起HTTP(s)请求(或者开放的TCP连接),这将在一组EC2实例间负载均衡这些请求。ELB不进可以负载均衡外部请求,如果部署在VPC,也可以负载均衡内部请求。ELB通常也有服务注册中心一样的功能。EC2实例通过API调用直接注册,或者作为auto-scaling group的一部分自动注册。
一些集群解决方案,比如Kubernetes 和 Marathon 在每个主机都运行一个代理,拥有服务端服务发现路由的功能。为了访问服务,客户端采用分配给服务的端口来里恩杰本地代理。本地代理将这部分请求转发到集群中运行在某处的服务实例。
结果
服务端服务发现有几个优势:
- 对比客户端服务发现,由于客户端不在处理服务发现,因此代码更简单。相反,客户端简单的对路由发起请求
- 一些云环境提供了这部分功能,比如AWS Elastic Load Balancer
服务端服务发现也有如下弊端:
- 除非它是云环境的一部分,路由必须是另外的系统组件,需要安装和配置。它也需要备份以满足可用性和容量。
- 路由必须实现必要的通信协议(比如HTTP,gRPC,Thrift等等),除非他是个基于TCP协议的路由
- 比起使用客户端服务发现,需要更多的网络跳数