首页 > 其他分享 >.NET服务发现(Microsoft.Extensions.ServiceDiscovery)集成Consul

.NET服务发现(Microsoft.Extensions.ServiceDiscovery)集成Consul

时间:2024-04-11 15:47:00浏览次数:22  
标签:Consul Extensions var ServiceDiscovery logger Microsoft

随着Aspire发布preview5的发布,Microsoft.Extensions.ServiceDiscovery随之更新,

服务注册发现这个属于老掉牙的话题解决什么问题就不赘述了,这里主要讲讲Microsoft.Extensions.ServiceDiscovery(preview5)以及如何扩展其他的中间件的发现集成 .

Microsoft.Extensions.ServiceDiscovery官方默认提供的Config,DNS,YARP三种Provider,使用也比较简单 :

builder.Services.AddServiceDiscovery();

builder.Services.AddHttpClient<CatalogServiceClient>(static client =>
    {
        client.BaseAddress = new("http://todo");
    });

builder.Services.ConfigureHttpClientDefaults(static http =>
{
    // 全局对HttpClient启用服务发现
    http.UseServiceDiscovery();
});

然后 appsettings.json 为名为 todo 的服务配置终结点:

  "Services": {
    "todo": {
      "http": [
        "http://localhost:5124"
      ]
    }
  }

然后使用服务发现:


#region 模拟服务端的todo接口: 
var sampleTodos = new Todo[] {
    new(1, "Walk the dog"),
    new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
    new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
    new(4, "Clean the bathroom"),
    new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
};

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());
#endregion

public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

#region 测试服务发现和负载

app.MapGet("/test", async (IHttpClientFactory clientFactory) =>
{
    //这里服务发现将自动解析配置文件中的服务
    var client = clientFactory.CreateClient("todo");
    var response = await client.GetAsync("/todos");
    var todos = await response.Content.ReadAsStringAsync();
    return Results.Content(todos, contentType: "application/json");
});

#endregion

运行程序后将会发现成功执行:
image

当然对于这样写死配置的服务发现一点都不灵活,因此应运而生了 YARP和DNS这些Provider, 目前服务注册发现使用Consul的还是挺多的,当然还有很多其他的轮子就不赘述了,这里我们来扩展一个Consul的服务发现Provider :

实现核心接口IServiceEndPointProvider

internal class ConsulServiceEndPointProvider(ServiceEndPointQuery query, IConsulClient consulClient, ILogger logger)
        : IServiceEndPointProvider, IHostNameFeature
    {
        const string Name = "Consul";
        private readonly string _serviceName = query.ServiceName;
        private readonly IConsulClient _consulClient = consulClient;
        private readonly ILogger _logger = logger;

        public string HostName => query.ServiceName;

#pragma warning disable CA1816 // Dispose 方法应调用 SuppressFinalize
        public ValueTask DisposeAsync() => default;

        public async ValueTask PopulateAsync(IServiceEndPointBuilder endPoints, CancellationToken cancellationToken)
        {
            var flag = ServiceNameParts.TryParse(_serviceName, out var serviceNameParts);
            var sum = 0;
            if (flag)
            {
                var queryResult = await _consulClient.Health.Service(serviceNameParts.Host, string.Empty, true, cancellationToken);
                foreach (var serviceEntry in queryResult.Response)
                {
                    var address = $"{serviceEntry.Service.Address}:{serviceEntry.Service.Port}";
                    var isEndpoint = ServiceNameParts.TryCreateEndPoint(address, out var endPoint);
                    if (isEndpoint)
                    {
                        ++sum;
                        var serviceEndPoint = ServiceEndPoint.Create(endPoint!);
                        serviceEndPoint.Features.Set<IServiceEndPointProvider>(this);
                        serviceEndPoint.Features.Set<IHostNameFeature>(this);
                        endPoints.EndPoints.Add(serviceEndPoint);
                        _logger.LogInformation($"ConsulServiceEndPointProvider Found Service {_serviceName}:{address}");
                    }
                }
            }

            if (sum == 0)
            {
                _logger.LogWarning($"No ConsulServiceEndPointProvider were found for service '{_serviceName}' ('{HostName}').");
            }
        }

        /// <inheritdoc/>
        public override string ToString() => Name;
    }

实现 IServiceEndPointProviderFactory:


internal class ConsulServiceEndPointProviderFactory(IConsulClient consulClient, ILogger<ConsulServiceEndPointProviderFactory> logger) : IServiceEndPointProviderFactory
    {
        private readonly IConsulClient _consulClient = consulClient;
        private readonly ILogger<ConsulServiceEndPointProviderFactory> _logger = logger;

        public bool TryCreateProvider(ServiceEndPointQuery query, [NotNullWhen(true)] out IServiceEndPointProvider? resolver)
        {
            resolver = new ConsulServiceEndPointProvider(query, _consulClient, _logger);
            return true;
        }
    }

接着扩展一下IServiceCollection


public static IServiceCollection AddConsulServiceEndpointProvider(this IServiceCollection services)
{
	services.AddServiceDiscoveryCore();
	services.AddSingleton<IServiceEndPointProviderFactory, ConsulServiceEndPointProviderFactory>();
	return services;
}

最后添加一行代码 :

// 使用Microsoft.Extensions.ServiceDiscovery实现负载均衡
builder.Services.AddServiceDiscovery()
    .AddConfigurationServiceEndPointResolver() //config
    .AddConsulServiceEndpointProvider(); //consul

下面是Consul中注册完成的服务:
image

然后我们请求 ./test 调用服务,观察调试日志,成功了!

image

完整的代码:
https://github.com/vipwan/Biwen.Microsoft.Extensions.ServiceDiscovery.Consul

当然你也可以直接使用nuget引用 Biwen.Microsoft.Extensions.ServiceDiscovery.Consul 我已经发布到了nuget上 , 最后因为Aspire还在不停的迭代所以Biwen.Microsoft.Extensions.ServiceDiscovery.Consul后面还会存在一些变化, 前面的几个早期版本我都做了适配以最新的为准

标签:Consul,Extensions,var,ServiceDiscovery,logger,Microsoft
From: https://www.cnblogs.com/vipwan/p/18129361

相关文章

  • consul:啥?我被优化没了?AgileConfig+Yarp替代Ocelot+Consul实现服务发现和自动网关配置
    现在软件就业环境不景气,各行各业都忙着裁员优化。作为一个小开发,咱也不能光等着别人来优化咱,也得想办法优化下自己。就拿手头上的工作来说吧,我发现我的微服务应用里,既有AgileConfig这个配置中心组件,又有一个Consul服务发现组件。本来吧他俩也没啥事,各干个的。但是,我在操作AgileCo......
  • consul:啥?我被优化没了?AgileConfig+Yarp替代Ocelot+Consul实现服务发现和自动网关配置
    现在软件就业环境不景气,各行各业都忙着裁员优化。作为一个小开发,咱也不能光等着别人来优化咱,也得想办法优化下自己。就拿手头上的工作来说吧,我发现我的微服务应用里,既有AgileConfig这个日志组件,又有一个Consul服务发现组件。本来吧他俩也没啥事,各干个的。但是,我在操作AgileConfig......
  • feign.net 使用consul服务发现 配置
    所有依赖 <ProjectSdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><In......
  • Consul服务注册发现集群搭建
    Consul是一种用于服务发现、配置和分布式一致性的开源工具和平台。它由HashiCorp公司开发和维护,旨在简化构建和维护分布式系统的任务。Consul提供了许多功能,包括:服务发现:Consul允许服务注册和发现。当服务启动时,它可以向Consul注册自己的位置和元数据。其他服务可以通过Co......
  • prometheus + consul 服务注册+报警 最佳实践
    一、说明本文主要将prometheus和consul结合起来使用,通过conusl注册服务至prometheus,实现服务统一注册,统一报警管理等。整个架构思路consul+consul_export+prometheus+alertmanager,consul通过check检测服务状态,然后通过consul_export暴露给prometheus,prometheus通过alert规则......
  • 注册中心-consul
    目录一、注册中心1.1服务注册与发现1.2分布式一致性算法1.3注册中心选型二、Consul2.1介绍2.2consul特点2.3安装(1)普通安装i.winii.mac(2)docker安装三、常用API3.1服务注册(1)使用postman注册演示(2)Go语言注册3.2服务删除(1)使用postman注册演示(2)go代码3.3设置健康检查3.4获......
  • Springboot2+consul启动时报错,读取的SystemConfig类的值全部为null
    【错误描述】     解决方案:检查是否已经在pom.xml配置了consul的相关jar包引用。 排查过程:检查了启动的日志,跟旧项目的正常日志进行对比,发现缺少了读取配置boostrap文件的日志。怀疑没有启动consul服务去远端读取consul的内容。 ......
  • SpringBoot3+Consul配置,启动后,居然不读bootstrap.yml的配置文件,直接连本地localhost:8
    问题描述如题。bootstrap.yml的配置文件: consul控制台打印的日志: 解决方案:booststrap.yml的配置文件缩进搞错了,所以压根就没有读到配置。正确的缩进:  ......
  • Ocelot+Consul的使用配置
    客户端代码配置"ConsulRegisterOptions":{"Address":"http://localhost:8500",//"http://host.docker.internal:8500",//Consul客户端地址"HealthCheck":"/healthcheck",//健康检查地址"Name":......
  • 1.微服务注册中心Consul
     Consul是HashiCorp公司推出的开源工具,Consul由Go语言开发,部署起来非常容易,只需要极少的可执行程序和配置文件,具有绿色、轻量级的特点。Consul是分布式的、高可用的、可横向扩展的用于实现分布式系统的服务发现与配置。中文网:Consul中文文档-Consul中文文档(gitb......