本文介绍如何使用 Microsoft.Extensions.ServiceDiscovery
库。服务发现是开发人员使用逻辑名称而不是物理地址(IP 地址和端口)来引用外部服务的一种方法。
开始使用
若要在 .NET 中开始使用服务发现,请安装 Microsoft.Extensions.ServiceDiscovery NuGet 包。
dotnet add package Microsoft.Extensions.ServiceDiscovery --prerelease
用法示例
在项目的 Program.cs 文件中调用 AddServiceDiscovery
扩展方法,以将服务发现添加到主机,并配置默认服务终结点解析程序:
builder.Services.AddServiceDiscovery();
通过调用 UseServiceDiscovery
扩展方法将服务发现添加到单个 IHttpClientBuilder:
builder.Services.AddHttpClient<CatalogServiceClient>(static client =>
{
client.BaseAddress = new("http://catalog");
})
.UseServiceDiscovery();
或者,在默认情况下,可以将服务发现添加到所有 HttpClient 实例:
builder.Services.ConfigureHttpClientDefaults(static http =>
{
// Turn on service discovery by default
http.UseServiceDiscovery();
});
从配置解析服务终结点
默认情况下,AddServiceDiscovery
扩展方法会添加基于配置的终结点解析程序。此解析程序从 .NET 配置系统读取终结点。库通过 appsettings.json、环境变量或任何其他 IConfiguration 源支持配置。
以下示例演示如何通过 appsettings.json
为名为 catalog 的服务配置终结点:
{
"Services": {
"catalog": [
"localhost:8080",
"10.46.24.90:80",
]
}
}
上面的示例为名为 catalog 的服务添加两个终结点:localhost:8080
和 "10.46.24.90:80"
。每次解析 catalog 时,都会选择其中一个终结点。
如果使用 IServiceCollection 上的 AddServiceDiscoveryCore
扩展方法将服务发现添加到主机,则可以通过在 IServiceCollection
上调用 AddConfigurationServiceEndPointResolver
扩展方法来添加基于配置的终结点解析程序。
配置
配置解析程序是使用 ConfigurationServiceEndPointResolverOptions
类配置的,该类提供以下配置选项:
SectionName:包含服务终结点的配置节的名称。默认为
"Services"
。ApplyHostNameMetadata:用于确定是否应将主机名元数据应用于已解析终结点的委托。它默认为返回
false
的函数。
若要配置这些选项,可以对应用程序的 Startup
类或 Program
文件中的 IServiceCollection
使用 Configure
扩展方法:
上面的示例演示如何为服务终结点设置自定义节名称,并提供一个基于条件应用主机名元数据的自定义逻辑。
使用平台提供的服务发现解析服务终结点
某些平台(如 Azure 容器应用和 Kubernetes(如果已相应地配置))提供服务发现功能,而无需服务发现客户端库。如果在此类环境中部署了应用程序,使用平台的内置功能可能很有利。直通解析程序旨在帮助实现此方案。它可以在不同的环境(如开发人员的计算机)中启用替代解析程序(如配置)。重要的是,无需进行任何代码修改或实现条件防护,即可实现这种灵活性。
直通解析程序不执行外部解析,而是通过返回以 DnsEndPoint
表示的输入服务名称来解析终结点。
通过 AddServiceDiscovery
扩展方法添加服务发现时,默认会配置直通提供程序。
如果使用 IServiceCollection
上的 AddServiceDiscoveryCore
扩展方法将服务发现添加到主机,则可以通过调用 IServiceCollection
上的 AddPassThroughServiceEndPointResolver
扩展方法来添加直通提供程序。
使用终结点选择器进行负载均衡
每次通过 HttpClient
管道解析终结点时,都会从所请求服务的所有已知终结点集选择一个终结点。如果有多个终结点可用,则可能需要在所有此类终结点之间平衡流量。为此,可以使用可自定义的终结点选择器。默认情况下,终结点是按轮循顺序选择的。若要使用不同的终结点选择器,请向 UseServiceDiscovery
方法调用提供 IServiceEndPointSelector
实例。例如,若要从解析的终结点集选择一个随机终结点,请将 RandomServiceEndPointSelector.Instance
指定为终结点选择器:
Microsoft.Extensions.ServiceDiscovery
包包含以下终结点选择器提供程序:
Pick-first:始终选择第一个终结点:
PickFirstServiceEndPointSelectorProvider.Instance
Round-robin:循环选择终结点:
RoundRobinServiceEndPointSelectorProvider.Instance
Random:随机选择终结点:
RandomServiceEndPointSelectorProvider.Instance
Power-of-two-choices:尝试根据用于分布式负载均衡的二次幂选择算法选取负载最低的终结点,在提供的任一终结点都没有
IEndPointLoadFeature
特征时,会降级为随机选择终结点:PowerOfTwoChoicesServiceEndPointSelectorProvider.Instance
终结点选择器是通过 IServiceEndPointSelectorProvider
实例创建的,例如之前列出的提供程序。调用提供程序的 CreateSelector()
方法来创建选择器,这是 IServiceEndPointSelector
的实例。使用 SetEndPoints(ServiceEndPointCollection collection)
方法解析 IServiceEndPointSelector
实例时,将为其提供已知终结点集。若要从集合中选择终结点,需调用 GetEndPoint(object? context)
方法,这会返回单个 ServiceEndPoint
。传递给 GetEndPoint
的 context
值用于提供可能对选择器有用的额外上下文。例如,在 HttpClient
案例中,传递了 HttpRequestMessage
。提供的 IServiceEndPointSelector
实现都不会检查上下文,除非使用选择器(这样就不会该实现),否则可以忽略它。
解析顺序
在解析服务终结点时,将按注册顺序调用每个已注册的解析程序,并且你有机会修改返回给调用方的 ServiceEndPoint
集合。如果在调用 Microsoft.Extensions.ServiceDiscovery
系列包中包含的提供程序时集合中存在现有的终结点,则这些提供程序会跳过解析。例如,假设注册了以下提供程序:配置、DNS SRV、直通。解析发生时,将按顺序调用这些提供程序。如果配置提供程序未发现任何终结点,则 DNS SRV 提供程序执行解析,并可能会添加一个或多个终结点。如果 DNS SRV 提供程序向集合添加终结点,则直通提供程序将跳过其解析并立即返回。