第 8 章:访问应用程序:服务、路由和服务发现

本章围绕云原生应用的服务抽象、动态路由和服务发现展开,重点分析服务端与客户端负载均衡的区别,并通过实际案例说明如何构建可扩展、高可用的系统。

本章要点

  • 单个服务代表多个应用程序实例
  • 服务器端负载均衡与客户端负载均衡
  • 服务实例的动态路由
  • 服务发现机制

服务抽象与应用实例

在云原生环境中,一个服务通常由多个应用实例组成。每组实例作为一个逻辑实体运行,确保系统具备弹性和可扩展性。下图展示了示例系统中三个应用的多个实例。

图 8.1 在云原生软件中,应用程序被部署为多个实例。为了让软件可以正常运行,你会希望每一组实例都作为一个单独的逻辑实体来运行。
图 8.1 在云原生软件中,应用程序被部署为多个实例。为了让软件可以正常运行,你会希望每一组实例都作为一个单独的逻辑实体来运行。

在实际部署中,应用实例之间的连接方式决定了系统的健壮性。通过引入服务抽象,可以消除微服务之间的脆弱耦合。如下图所示,每组实例由逻辑实体表示,并用应用名称标记。

图 8.2 每一组应用程序实例,都由一个定义了应用程序行为的逻辑实体来表示。
图 8.2 每一组应用程序实例,都由一个定义了应用程序行为的逻辑实体来表示。

进一步抽象后,软件系统可视为一组相互连接的服务,每个服务由一组实例实现。

图 8.3 你的软件被定义为多个服务的组合。每个服务都是由一组服务实例来实现的。
图 8.3 你的软件被定义为多个服务的组合。每个服务都是由一组服务实例来实现的。

服务寻址、路由与服务发现

服务抽象的左侧是服务寻址和发现,右侧是路由和负载均衡。服务发现让客户端能通过名称找到服务,动态路由则将请求分发到不断变化的实例集合。

图 8.4 由一组应用程序实例所表示的单独的逻辑实体,我们称之为一个服务。让客户端可以找到和访问相关服务的方法,我们称为服务发现。在多个应用程序实例间分发请求的方法,我们称为动态路由。
图 8.4 由一组应用程序实例所表示的单独的逻辑实体,我们称之为一个服务。让客户端可以找到和访问相关服务的方法,我们称为服务发现。在多个应用程序实例间分发请求的方法,我们称为动态路由。

服务寻址、路由和服务发现的设计通常在部署阶段决定。理解这些技术有助于做出合理的架构选择。

服务示例分析

用 Google 进行搜索

当你在浏览器输入 www.google.com 时,DNS 将域名解析为 IP 地址,客户端通过该地址访问服务。实际部署中,IP 地址通常指向负载均衡器,由平台维护最新的实例路由列表。

图 8.5 通过域名 www.google.com 找到 Google 搜索服务,该域名会通过 DNS 映射到一个具体的 IP 地址。Google 平台会维护一份最新的搜索服务实例的路由列表,并将请求负载均衡到这些实例上。
图 8.5 通过域名 www.google.com 找到 Google 搜索服务,该域名会通过 DNS 映射到一个具体的 IP 地址。Google 平台会维护一份最新的搜索服务实例的路由列表,并将请求负载均衡到这些实例上。

博客聚合器示例

在博客聚合器中,相关帖子服务通过硬编码 IP 地址访问帖子服务,缺乏服务发现机制,导致部署脆弱。Kubernetes 通过标签和选择器动态维护实例列表,实现路由自动更新。

图 8.6 到目前为止,你的博客聚合软件还没有使用任何服务发现的功能,并且通过 IP 地址将相关帖子服务与帖子服务绑定。这会让部署变得很脆弱。
图 8.6 到目前为止,你的博客聚合软件还没有使用任何服务发现的功能,并且通过 IP 地址将相关帖子服务与帖子服务绑定。这会让部署变得很脆弱。

动态路由与负载均衡

服务端负载均衡

服务端负载均衡通过集中式组件(如 F5、nginx、云厂商负载均衡服务)分发请求。负载均衡器维护所有实例的路由列表,采用轮询或随机等算法分发流量。集中式实现技术成熟,配置简单,但需避免单点故障。

图 8.7 使用集中式或者服务端负载均衡的方法,客户端请求一般由一组负载均衡器来处理,它们拥有服务所有实例的路由列表。负载均衡器会将客户端的请求分发到不同的应用程序实例。
图 8.7 使用集中式或者服务端负载均衡的方法,客户端请求一般由一组负载均衡器来处理,它们拥有服务所有实例的路由列表。负载均衡器会将客户端的请求分发到不同的应用程序实例。

客户端负载均衡

客户端负载均衡将路由逻辑嵌入客户端,每个客户端实例维护自己的路由列表,直接向服务实例发送请求。该模式减少网络跳转,提升性能,但配置和升级更复杂,需结合具体框架(如 Netflix Ribbon、Istio Sidecar)。

图 8.8 通过客户端的负载均衡,客户端可以直接向服务实例发送请求,并将请求分发到所有的实例上。客户端自身会维护一个实例的路由列表。
图 8.8 通过客户端的负载均衡,客户端可以直接向服务实例发送请求,并将请求分发到所有的实例上。客户端自身会维护一个实例的路由列表。

路由刷新机制

路由列表需实时更新,反映实例的实际状态。平台通过健康检查和标签选择器自动维护路由表,确保请求始终分发到可用实例。

图 8.9 帖子(抽象)服务及其实例的清单。服务实例的路由列表会通过一个控制循环来保持更新,并通过选择器来找到满足某个指定条件(在本例中是标签 app:posts)的所有应用程序实例。
图 8.9 帖子(抽象)服务及其实例的清单。服务实例的路由列表会通过一个控制循环来保持更新,并通过选择器来找到满足某个指定条件(在本例中是标签 app:posts)的所有应用程序实例。

在 Minikube 环境中,Kube Proxy 作为负载均衡器,动态维护实例 IP 地址列表,实现服务端负载均衡。

图 8.10 帖子服务在 Minikube 中的具体实现。Kube 代理是一个负载均衡器的实现,它包含帖子服务所有实例的 IP 地址列表。
图 8.10 帖子服务在 Minikube 中的具体实现。Kube 代理是一个负载均衡器的实现,它包含帖子服务所有实例的 IP 地址列表。

服务发现机制

服务发现通过名称服务(如 DNS)将服务名称与 IP 地址解耦,提升系统弹性。名称服务优先保证可用性,可能存在短暂的不一致,客户端需实现重试机制以应对过期记录。

图 8.11 在访问服务时,服务发现协议允许客户端通过名称来指向某个服务,从而在两者之间建立起更加灵活的联系。
图 8.11 在访问服务时,服务发现协议允许客户端通过名称来指向某个服务,从而在两者之间建立起更加灵活的联系。

当 DNS 记录未及时更新时,客户端可通过重试和重新查询获取最新地址,提升访问成功率。

图 8.12 服务发现协议必须考虑到域名系统的最终一致性。
图 8.12 服务发现协议必须考虑到域名系统的最终一致性。

服务发现的实际应用

Web 服务发现

Web 应用通过 DNS 显式注册名称与 IP 地址映射,部署流程自动添加记录。如下图所示,CloudDNS 控制台展示了多条名称与 IP 地址的映射。

图 8.13 将域名映射到 IP 地址的 DNS 记录
图 8.13 将域名映射到 IP 地址的 DNS 记录

客户端负载均衡与服务发现

客户端负载均衡框架(如 Ribbon)允许通过服务名称引用依赖服务,服务发现协议用于更新客户端路由列表。服务注册与查询通常结合 Eureka 等服务发现框架实现。

例如,在 Spring 框架中,可通过注解和配置实现服务注册与发现,具体代码可参考 Ribbon 和 Eureka 官方文档。

Kubernetes 服务发现

Kubernetes 默认集成 CoreDNS,自动为服务注册名称与地址。所有 Pod 配置 CoreDNS 地址,服务名称解析自动完成。服务发现协议的注册和查询流程均由平台自动管理。

图 8.15 Kubernetes 提供了服务发现协议的一个实现,其中包含一个域名服务,以及一个自动创建并访问其中记录的流程。
图 8.15 Kubernetes 提供了服务发现协议的一个实现,其中包含一个域名服务,以及一个自动创建并访问其中记录的流程。

实际案例:消除脆弱配置

通过服务发现协议,服务间不再通过 IP 地址绑定,客户端可直接通过服务名称访问依赖服务。部署清单中环境变量统一采用服务名称,简化配置,提升弹性。

例如,相关帖子服务的环境变量可配置为:

  • CONNECTIONPOSTSCONTROLLER_POSTURL: "http://posts-svc/posts?userIds="
  • REDIS_HOSTNAME: "redis-svc"
  • SPRING_CLOUD_CONFIG_URI: "http://sccs-svc:8888"

Redis 服务端口号设置为 6379,服务名称与 CoreDNS 关联,实现东西向流量路由,提升内部通信效率。

具体部署和配置流程可参考 Kubernetes 官方文档和相关 YAML 清单示例。

总结

  • 服务抽象将客户端与依赖服务松耦合,提升系统弹性。
  • 负载均衡分为服务端和客户端两种模式,各有优缺点。
  • 路由列表需动态自动更新,确保请求分发到可用实例。
  • DNS 等名称服务是服务发现协议核心,需考虑最终一致性和重试机制。
  • 服务发现协议显著提升云原生软件的部署弹性和可维护性。

参考文献

  1. Cloud Native Patterns - manning.com
  2. Kubernetes 官方文档 - kubernetes.io
  3. Spring Cloud 官方文档 - spring.io
  4. Netflix Ribbon - github.com
  5. Netflix Eureka - github.com

文章导航

独立页面

这是书籍中的独立页面。

书籍首页

评论区