Appearance
服务发现-客户端与服务端模式
看在前面
- 「Chris Richardson 微服务系列」服务发现的可行方案以及实践案例:http://blog.daocloud.io/microservices-4/
本文译自 Nginx 官方博客 Chris Richardson 的微服务系列(四)。讲微服务架构中服务发现的可行方案(客户端发现、服务端发现)以及实践案例。
为什么要使用服务发现?
传统应用运行在物理硬件上,服务实例的网络位置相对固定。代码可以从偶尔更新的配置文件中读取网络位置;
在云端的现代化微服务应用中,服务实例的网络位置是动态分配的。由于扩展、失败和升级,实例会频繁动态改变。因此客户端需要更复杂的服务发现机制;
服务发现有两大模式:客户端发现模式和服务端发现模式。
客户端发现模式
客户端自行决定服务实例的网络位置,并对请求实现负载均衡:
┌────────────────────┐
服务实例注册/ │ 服务注册表 │
心跳刷新/注销 │ (可用实例数据库) │
┌──────┐ └────────▲────────────┘
│实例 A │──注册─────────┘
└──────┘
┌──────┐ 2.查询可用实例
│实例 B │───────────────────┐
└──────┘ │
1.查询注册表 3.负载均衡算法选择实例,发请求
客户端 ───────────────────────────────────────> 目标服务实例服务实例启动时,网络位置被记录到服务注册表,终止时删除;注册信息通常用心跳机制定期刷新;
客户端查询服务注册表(一个可用服务实例的数据库),使用负载均衡算法选择一个实例。然后发出请求。
典型范例:Netflix OSS。Eureka 作为服务注册表,提供 REST API 管理服务实例的注册与查询;Ribbon 是 IPC 客户端,与 Eureka 配合实现负载均衡。
优点:相对直接,除服务注册外无需其它变动。客户端知晓可用实例,可以实现智能的、客户端侧的负载均衡(如一致性哈希)。
缺点:客户端与服务注册机制绑定,需要针对每种编程语言和框架分别实现客户端发现逻辑。
服务端发现模式
客户端向负载均衡器发出请求,负载均衡器查询服务注册表,将每个请求转发到可用的服务实例:
┌──────┐ 注册/心跳 ┌────────────┐
│实例 A │ ──────────> │ 服务注册表 │
└──────┘ └─────▲──────┘
┌──────┐ │ 2.查询
│实例 B │ 1.请求 │ 3.转发请求
└──────┘ ┌────────┴──────┐
客户端 ─────────> │ 负载均衡器 │ ──────────> 目标实例
└───────────────┘典型例子:
AWS ELB:客户端通过 DNS 向 ELB 发送 HTTP/TCP 请求。ELB 在已注册的 EC2 实例或 ECS 容器之间均衡流量。这里没有独立的服务注册表,实例直接注册在 ELB 上;
NGINX/NGINX Plus:可用作服务端发现的负载均衡器。Consul Template 定期从注册表生成 nginx.conf,文件变化后触发 NGINX 重载;NGINX Plus 还支持通过 HTTP API 或 DNS 动态配置 upstream;
Kubernetes、Marathon:在每台集群主机上运行一个代理(proxy),充当服务端发现的负载均衡器。客户端通过主机 IP 和分配的端口向代理发起请求。代理将请求透明地转发到该服务一个可用的实例。
优点:客户端无需关注服务发现的细节,只需向负载均衡器发送请求。减少了每种语言/框架都要实现发现逻辑的负担。某些部署环境免费提供该功能。
缺点:除非负载均衡器由部署环境提供,否则它是一个需要配置和管理的高可用系统组件。
服务注册表
服务注册表是服务发现的核心部分:一个包含服务实例网络地址的数据库。注册表必须高可用且随时最新。客户端可以缓存从注册表中获取的网络地址,但信息最终会过时。因此注册表由一组服务端组成,使用复制协议来保持一致性。
Netflix Eureka 高可用实践:
提供完整的 REST API:服务实例用 POST 请求注册网络地址,每 30 秒通过 PUT 刷新注册信息。通过 HTTP DELETE 或实例注册超时来移除。客户端通过 HTTP GET 检索可用实例;
每个 AWS 可用域(availability zone)运行一个或多个 Eureka 服务,各运行在有弹性 IP 的 EC2 实例上。DNS TXT 记录保存 Eureka 集群配置(可用域列表及各域服务器地址列表)。Eureka 服务启动时查询 DNS 获取集群配置、定位同伴、并尝试占用未使用的弹性 IP;
Eureka 客户端查询 DNS 来发现 Eureka 服务的网络地址。优先使用同一个可用域的服务,当前域服务不可用时回退到其它域。
其它常见注册表组件:
etcd:高可用、分布式、一致性的键值存储,用于共享配置和服务发现,Kubernetes 和 Cloud Foundry 使用它;
consul:另一个服务发现和配置工具,通过健康检查机制判断服务的可用性,支持 DNS 和 HTTP 接口;
Apache ZooKeeper:被广泛使用的高性能协调服务,最初是 Hadoop 的子项目,现在是 Apache 顶级项目。
另外,Kubernetes、Marathon、AWS 这些环境没有明确的外置服务注册表,注册功能内置于基础设施中。
服务注册的方式
自注册模式
服务实例自己负责在服务注册表中注册和注销,必要时发送心跳保证注册信息不过期。
案例:Netflix Eureka 客户端处理实例的注册与注销;Spring Cloud 通过 @EnableEurekaClient 注解简化自动注册;
优点:简单直接,不需要其它系统组件;
缺点:服务实例与注册表耦合,必须在使用的每种编程语言和框架内实现注册代码。
第三方注册模式
服务实例不自己注册,由称为"服务注册器(registrar)"的另一个系统模块处理。注册器通过查询部署环境或订阅事件来跟踪运行实例的变更。发现新实例即注册,实例终止则注销。
案例:
Registrator:开源项目,自动注册/注销被 Docker 容器化的服务实例,支持 etcd、Consul 等多种注册表;
NetflixOSS Prana:面向非 JVM 服务,与服务实例并行部署运行,代表服务通过 Eureka 完成注册注销;
部署环境内置:AWS 中由 Autoscaling Group 创建的 EC2 实例自动向 ELB 注册;Kubernetes 中服务自动注册并可被发现;
优点:服务与注册表解耦,无需逐语言实现注册逻辑,由专有组件对所有服务集中管理;
缺点:除非内置于部署环境,否则它是一个需要配置和管理的高可用额外组件。
总结
微服务中实例网络地址动态变化,客户端必须使用服务发现机制(服务注册表 + 查询机制);
两种发现模式。客户端发现:客户端查注册表、选实例、发请求。服务端发现:路由器/负载均衡器查注册表并转发请求;
两种注册方式:自注册模式与第三方注册模式;
有些部署环境(Kubernetes、Marathon)内置服务发现,包括实例的注册注销和集群主机上的代理路由。其它环境则需自建 Eureka、etcd、Consul、ZooKeeper 等设施;
NGINX 类负载均衡器可以用作服务端发现的均衡器。通过 Consul Template 推送路由信息并触发配置更新。NGINX Plus 还支持 DNS 获取实例信息和远程配置 API。
内容来源:原文镜像(原 DaoCloud 链接已失效)· 2026-10 整理回填。