自定义名称解析
解释了标准名称解析、自定义名称解析器接口以及如何编写实现。
自定义名称解析
概述
名称解析从根本上来说是关于服务发现的。当发送 gRPC 请求时,客户端必须确定服务名称的 IP 地址。通常认为名称解析与 DNS 相同。然而在实践中,DNS 通常会通过扩展来增强,或者被完全替换以启用名称解析。
当使用 gRPC 客户端发出请求时,默认情况下使用 DNS 名称解析。但是,可以使用各种其他名称解析机制
解析器 | 示例 | 注意 |
---|---|---|
DNS | grpc.io:50051 | 默认情况下,假定使用 DNS。 |
DNS | dns:///grpc.org.cn:50051 | 额外的斜杠用于提供授权。 |
Unix 域套接字 | uds:///run/containerd/containerd.sock | |
xDS | xds:///wallet.grpcwallet.io | |
IPv4 | ipv4:198.51.100.123:50051 | 仅在某些语言中支持 |
注意
如果您习惯于 HTTP 的双斜杠,例如https://grpc.org.cn
,那么上面的三斜杠 (///
) 可能看起来很陌生。这些目标字符串遵循 RFC-3986 URI 的格式。前两个斜杠之后和第三个斜杠之前的字符串(如果有第三个斜杠的话)是授权。授权字符串标识一个包含所有资源 URI 的服务器。在传统的 HTTP 请求中,URI 的授权是请求将发送到的服务器。在其他情况下,授权将是名称解析服务器的身份,而资源本身位于其他服务器上。某些名称解析器不需要授权。在这种情况下,授权字符串为空,从而导致连续出现三个斜杠。一些语言支持一个接口,允许用户定义自己的名称解析器,以便您可以定义如何解析任何给定的名称。一旦注册,当目标字符串以 my-resolver:
开头时,将选择带有方案 my-resolver
的名称解析器。例如,对 my-resolver:///my-service
的请求现在将使用 my-resolver
名称解析器实现。
自定义名称解析器
当您想要增强或替换 DNS 以进行服务发现时,您可以考虑使用自定义名称解析器。例如,过去曾使用此接口来使用 Apache Zookeeper 来查找服务名称。它还被用于直接与 Kubernetes API 服务器接口,以根据无头服务资源进行服务查找。
使用自定义名称解析器而不是标准 DNS 的一个特别有用的原因是此接口是响应式的。在标准 DNS 中,客户端在连接开始时查找特定服务的地址,并在连接的整个生命周期内保持与该地址的连接。但是,自定义名称解析器可能是基于监视的。也就是说,它们可以随着时间的推移从名称服务器接收更新,因此可以智能地响应后端故障以及后端扩展和后端缩减。
此外,自定义名称解析器可以为客户端连接提供服务配置。服务配置是一个 JSON 对象,它定义了任意配置,指定流量应如何路由到特定服务并如何在特定服务上进行负载均衡。最基本的情况是,可以使用它来指定特定服务应使用轮询负载均衡策略还是首选策略。但是,当自定义名称解析器与任意服务配置和自定义负载均衡策略结合使用时,可以构建非常复杂的流量管理系统,例如 xDS。
目标字符串的生命周期
虽然自定义名称解析器的确切接口因语言而异,但总体结构是相同的。客户端在进程开始时,将名称解析器提供程序的实现注册到进程全局注册表中。gRPC 库将使用用于自定义名称解析器的目标字符串调用名称解析器提供程序。给定该目标字符串,名称解析器提供程序将返回一个名称解析器的实例,该实例将与客户端连接交互,以根据目标字符串定向请求。
sequenceDiagram
Client ->> gRPC: Request to my-resolver:///my-service
gRPC ->> NameResolverProvider: requests NameResolver
NameResolverProvider -->> gRPC: returns NameResolver
gRPC ->> NameResolver: delegates resolution
NameResolver -->> gRPC: addresses
语言支持
语言 | 示例 |
---|---|
Java | 示例 |
Go | 示例 |
C++ | 不支持 |
Python | 不支持 |