服务发现

当在上游集群中定义了 配置 时,Envoy 需要知道如何解析集群的成员。这被称为服务发现

支持的服务发现类型

静态

静态是最简单的服务发现类型。配置显式指定每个上游主机的解析网络名称(IP 地址/端口、Unix 域套接字等)。

严格 DNS

使用严格 DNS 服务发现时,Envoy 将持续且异步地解析指定的 DNS 目标。DNS 结果中返回的每个 IP 地址都将被视为上游集群中的显式主机。这意味着如果查询返回三个 IP 地址,Envoy 将假设集群有三个主机,并且所有三个主机都应进行负载均衡。如果主机从结果中删除,Envoy 假设它不再存在,并将从任何现有连接池中排空流量。因此,如果成功的 DNS 解析返回 0 个主机,Envoy 将假设集群没有任何主机。请注意,Envoy 永远不会在转发路径中同步解析 DNS。以最终一致性的代价,永远不会担心在长时间运行的 DNS 查询上阻塞。

如果单个 DNS 名称解析为同一 IP 多次,这些 IP 将被去重。

如果多个 DNS 名称解析为同一 IP,则健康检查不会共享。这意味着如果对解析为同一 IP 的 DNS 名称使用主动健康检查,应该注意:如果 IP 在 DNS 名称之间重复多次,可能会对上游主机造成不必要的负载。

如果启用了 respect_dns_ttl,则使用 DNS 记录 TTL 和 dns_refresh_rate 来控制 DNS 刷新速率。对于严格的 DNS 集群,如果所有记录 TTL 的最小值为 0,则 dns_refresh_rate 将用作集群的 DNS 刷新速率。如果没有指定,dns_refresh_rate 默认值为 5000ms。 dns_failure_refresh_rate 控制失败期间的刷新频率,如果没有配置,则将使用 DNS 刷新速率。

DNS 解析会发出 集群统计信息 字段update_attemptupdate_successupdate_failure

逻辑 DNS

逻辑 DNS 使用与严格 DNS 类似的异步解析机制。但是,逻辑 DNS 集群并不严格地采用 DNS 查询的结果并假设它们构成了整个上游集群,而只是在需要启动新连接时使用返回的第一个 IP 地址。因此,单个逻辑连接池可能包含到各种不同上游主机的物理连接。连接永远不会被排空,包括在返回 0 个主机的成功 DNS 解析中。

这种服务发现类型非常适合必须通过 DNS 访问的大规模 Web 服务。此类服务通常使用循环 DNS 来返回许多不同的 IP 地址。通常,每次查询都会返回不同的结果。如果在这种情况下使用严格的 DNS,Envoy 将假设集群的成员在每个解析间隔期间都在发生变化,这会导致排空连接池、连接循环等。相反,使用逻辑 DNS,连接保持活动状态,直到它们被循环。与大规模 Web 服务交互时,这是所有可能情况中最好的:异步/最终一致的 DNS 解析、长期连接以及转发路径中的零阻塞。

如果启用了 respect_dns_ttl,则使用 DNS 记录 TTL 和 dns_refresh_rate 来控制 DNS 刷新速率。对于逻辑 DNS 集群,如果第一个记录的 TTL 为 0,则 dns_refresh_rate 将用作集群的 DNS 刷新速率。如果没有指定,dns_refresh_rate 默认值为 5000ms。 dns_failure_refresh_rate 控制失败期间的刷新频率,如果没有配置,则将使用 DNS 刷新速率。

DNS 解析会发出 集群统计信息 字段update_attemptupdate_successupdate_failure

原始目的地

当通过 iptables REDIRECT 或 TPROXY 目标,或使用代理协议将传入连接重定向到 Envoy 时,可以使用原始目的地集群。在这些情况下,路由到原始目的地集群的请求将转发到上游主机,如重定向元数据所述,没有任何显式主机配置或上游主机发现。到上游主机的连接将被池化,并且在它们未被任何连接池使用的时间超过 cleanup_interval(默认值为 5000ms)后,未使用的主机将被清除。如果原始目的地地址不可用,则不会打开上游连接。Envoy 还可以从 HTTP 标头 中获取原始目的地。原始目的地服务发现必须与原始目的地 负载均衡器 一起使用。当对 HTTP 上游使用原始目的地集群时,请将 idle_timeout 设置为 5 分钟以限制上游 HTTP 连接的持续时间。

端点发现服务 (EDS)

端点发现服务基于 gRPC 或 REST-JSON API 服务器的 xDS 管理服务器,Envoy 使用它来获取集群成员。集群成员在 Envoy 术语中称为“端点”。对于每个集群,Envoy 从发现服务中获取端点。EDS 是首选的服务发现机制,原因有以下几点

  • Envoy 明确了解每个上游主机(与通过 DNS 解析的负载均衡器路由相比),并且可以做出更明智的负载均衡决策。

  • 发现 API 响应中为每个主机携带的额外属性向 Envoy 提供了有关主机负载均衡权重、金丝雀状态、区域等的额外信息。这些附加属性在 Envoy 网格中全局使用,用于负载均衡、统计信息收集等。

Envoy 项目在 JavaGo 中都提供了 EDS 和 其他发现服务 的参考 gRPC 实现。

自定义集群

Envoy 还支持自定义集群发现机制。自定义集群使用集群配置上的 cluster_type 字段 指定。

通常,主动健康检查与最终一致的服务发现服务数据一起使用,以做出负载均衡和路由决策。这将在下一节中进一步讨论。

关于最终一致的服务发现

许多现有的 RPC 系统将服务发现视为一个完全一致的过程。为此,它们使用完全一致的领导者选举支持存储,例如 Zookeeper、etcd、Consul 等。我们的经验是,大规模操作这些支持存储很痛苦。

Envoy 从一开始就被设计为服务发现不需要完全一致。相反,Envoy 假设主机以最终一致的方式进出网格。我们推荐的服务到服务 Envoy 网格配置部署方式使用最终一致的服务发现以及 主动健康检查(Envoy 显式地对上游集群成员进行健康检查)来确定集群健康状况。这种模式有很多好处

  • 所有健康决策都是完全分布式的。因此,网络分区得到优雅地处理(应用程序是否优雅地处理分区是另一个问题)。

  • 当为上游集群配置健康检查时,Envoy 使用一个 2x2 矩阵来确定是否要路由到主机

发现状态

健康检查正常

健康检查失败

已发现

路由

不路由

不存在

路由

不路由 / 删除

主机已发现 / 健康检查正常

Envoy 将路由到目标主机。

主机不存在 / 健康检查正常

Envoy 将路由到目标主机。这非常重要,因为设计假设发现服务可以随时失败。如果主机在从发现数据中消失后继续通过健康检查,Envoy 仍然会进行路由。虽然在这种情况下不可能添加新主机,但现有主机将继续正常运行。当发现服务恢复正常运行时,数据最终会重新收敛。

主机已发现 / 健康检查失败

Envoy 将不路由到目标主机。假设健康检查数据比发现数据更准确。

主机不存在 / 健康检查失败

Envoy 将不路由,并将删除目标主机。这是 Envoy 将清除主机数据的唯一状态。