官网:https://www.consul.io/
Consul 是一款开源的服务发现和配置管理工具,它能够监控应用程序和服务之间的通信,并提供了一组 API 和 Web UI,用于管理服务和配置。
Consul 是分布式的、高可用的、可横向扩展的,具备以下特性:
Consul 的优势:
下载地址:https://developer.hashicorp.com/consul/install?product_intent=consul#Windows
运行 consul,指定为开发环境
consul agent -dev
web 界面:http://localhost:8500/ui
要在 ASP.NET Core 应用程序中集成 Consul 实现服务注册和服务发现,可以按照以下步骤进行操作:
首先,需要在 ASP.NET Core 应用程序中安装 Consul 客户端 SDK。可以通过 NuGet 包管理器来安装,在包管理器控制台中输入以下命令:
Install-Package Consul Install-Package Consul.AspNetCore
/// <summary> /// 向容器中添加Consul必要的依赖注入 /// </summary> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddMCodeConsul(this IServiceCollection services) { var configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>(); // 配置consul服务注册信息 var consulOptions = configuration.GetSection("Consul").Get<ConsulOptions>(); // 通过consul提供的注入方式注册consulClient services.AddConsul(options => options.Address = new Uri($"http://{consulOptions.ConsulIP}:{consulOptions.ConsulPort}")); // 通过consul提供的注入方式进行服务注册 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔 HTTP = $"http://{consulOptions.IP}:{consulOptions.Port}/health",//健康检查地址 Timeout = TimeSpan.FromSeconds(10) }; // Register service with consul services.AddConsulServiceRegistration(options => { options.Checks = new[] { httpCheck }; options.ID = Guid.NewGuid().ToString(); options.Name = consulOptions.ServiceName; options.Address = consulOptions.IP; options.Port = consulOptions.Port; options.Meta = new Dictionary<string, string>() { { "Weight", consulOptions.Weight.HasValue ? consulOptions.Weight.Value.ToString() : "1" } }; options.Tags = new[] { $"urlprefix-/{consulOptions.ServiceName}" }; //添加 }); return services; }
ConsulOptions 配置类
public class ConsulOptions { /// <summary> /// 当前应用IP /// </summary> public string IP { get; set; } /// <summary> /// 当前应用端口 /// </summary> public int Port { get; set; } /// <summary> /// 当前服务名称 /// </summary> public string ServiceName { get; set; } /// <summary> /// Consul集群IP /// </summary> public string ConsulIP { get; set; } /// <summary> /// Consul集群端口 /// </summary> public int ConsulPort { get; set; } /// <summary> /// 权重 /// </summary> public int? Weight { get; set; } }
appsettings.json
{ "Consul": { "ConsulIP": "127.0.0.1", "ConsulPort": "8500", "ServiceName": "ConsulDemoService", "Ip": "localhost", "Port": "5014", "Weight": 1 } }
可以看到通过 ConsulClientFactory 类创建和配置 Consul 的客户端实例,ConsulClientFactory 通过 IOptionsMonitor 读取应用程序的配置更改
IOptionsMonitor: 是 ASP.NET Core 的一个接口,它提供了一种方式来观察和监视应用程序的配置更改。通过实现 IOptionsMonitor 接口,你可以创建自定义的配置监视器,以便在配置更改时自动更新应用程序的设置
public static class ServiceCollectionExtensions { public static IServiceCollection AddConsul(this IServiceCollection services) { return services.AddConsul(delegate { }); } public static IServiceCollection AddConsul(this IServiceCollection services, Action<ConsulClientConfiguration> configure) { return services.AddConsul(Options.DefaultName, configure); } public static IServiceCollection AddConsul(this IServiceCollection services, string name, Action<ConsulClientConfiguration> configure) { services.Configure(name, configure); services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>(); services.TryAddSingleton((IServiceProvider sp) => sp.GetRequiredService<IConsulClientFactory>().CreateClient(name)); return services; } 。。。 } public class ConsulClientFactory : IConsulClientFactory { private readonly IOptionsMonitor<ConsulClientConfiguration> _optionsMonitor; public ConsulClientFactory(IOptionsMonitor<ConsulClientConfiguration> optionsMonitor) { _optionsMonitor = optionsMonitor; } public IConsulClient CreateClient() { return CreateClient(Options.DefaultName); } public IConsulClient CreateClient(string name) { return new ConsulClient(_optionsMonitor.Get(name)); } }
可以看出使用 AgentServiceRegistrationHostedService 类定义应用程序的后台服务,用于注册和取消注册 Consul 实例
public static class ServiceCollectionExtensions { public static IServiceCollection AddConsulServiceRegistration(this IServiceCollection services, Action<AgentServiceRegistration> configure) { AgentServiceRegistration agentServiceRegistration = new AgentServiceRegistration(); configure(agentServiceRegistration); return services.AddSingleton(agentServiceRegistration).AddHostedService<AgentServiceRegistrationHostedService>(); } } public class AgentServiceRegistrationHostedService : IHostedService { private readonly IConsulClient _consulClient; private readonly AgentServiceRegistration _serviceRegistration; public AgentServiceRegistrationHostedService(IConsulClient consulClient, AgentServiceRegistration serviceRegistration) { _consulClient = consulClient; _serviceRegistration = serviceRegistration; } public Task StartAsync(CancellationToken cancellationToken) { return _consulClient.Agent.ServiceRegister(_serviceRegistration, cancellationToken); } public Task StopAsync(CancellationToken cancellationToken) { return _consulClient.Agent.ServiceDeregister(_serviceRegistration.ID, cancellationToken); } }
/// <summary> /// 配置Consul检查服务 /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder UseConsulCheckService(this IApplicationBuilder app) { app.Map("/health", app => { app.Run(async context => { await Task.Run(() => context.Response.StatusCode = 200); }); }); return app; }
/// <summary> /// 向容器中添加Consul必要的依赖注入 /// </summary> /// <param name="services"></param> /// <param name="configuration"></param> /// <returns></returns> public static IServiceCollection AddMCodeConsul(this IServiceCollection services) { var configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>(); // 配置consul服务注册信息 var consulOptions = configuration.GetSection("Consul").Get<ConsulOptions>(); // 通过consul提供的注入方式注册consulClient services.AddConsul(options => options.Address = new Uri($"http://{consulOptions.ConsulIP}:{consulOptions.ConsulPort}")); // 通过consul提供的注入方式进行服务注册 var httpCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔 HTTP = $"http://{consulOptions.IP}:{consulOptions.Port}/health",//健康检查地址 Timeout = TimeSpan.FromSeconds(10) }; // Register service with consul services.AddConsulServiceRegistration(options => { options.Checks = new[] { httpCheck }; options.ID = Guid.NewGuid().ToString(); options.Name = consulOptions.ServiceName; options.Address = consulOptions.IP; options.Port = consulOptions.Port; options.Meta = new Dictionary<string, string>() { { "Weight", consulOptions.Weight.HasValue ? consulOptions.Weight.Value.ToString() : "1" } }; options.Tags = new[] { $"urlprefix-/{consulOptions.ServiceName}" }; //添加 }); //var applicationLifetime =services.BuildServiceProvider().GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>(); //var consulClient = services.BuildServiceProvider().GetRequiredService<IConsulClient>(); //var agentServiceRegistration = services.BuildServiceProvider().GetRequiredService<AgentServiceRegistration>(); ////程序停止时取消注册Consul //applicationLifetime.ApplicationStopping.Register(async () => //{ // await consulClient.Agent.ServiceDeregister(agentServiceRegistration.ID); //}); return services; } /// <summary> /// 配置Consul检查服务 /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder UseConsulCheckService(this IApplicationBuilder app) { app.Map("/health", app => { app.Run(async context => { await Task.Run(() => context.Response.StatusCode = 200); }); }); return app; }