文章目录
- 什么是 Consul?
- 安装和运行 Consul
- Asp .Net Core 如何集成 Consul 实现服务注册和健康检查
- Consul.AspNetCore 中的 AddConsul 和 AddConsulServiceRegistration 方法 究竟做了什么?
- AddConsul 方法
- AddConsulServiceRegistration 方法
- 配置 Consul 检查服务
- 封装成扩展
- 效果
什么是 Consul?
官网:https://www.consul.io/
Consul 是一款开源的服务发现和配置管理工具,它能够监控应用程序和服务之间的通信,并提供了一组 API 和 Web UI,用于管理服务和配置。
Consul 是分布式的、高可用的、可横向扩展的,具备以下特性:
- 服务发现:Consul 通过 DNS 或者 HTTP 接口使服务注册和服务发现变得很容易,一些外部服务,例如 saas 提供的也可以一样注册。
- 健康检查:健康检测使 Consul 可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
- 键/值存储:一个用来存储动态配置的系统。提供简单的 HTTP 接口,可以在任何地方操作。
- 多数据中心:无需复杂的配置,即可支持任意数量的区域。
Consul 的优势:
- 使用 Raft 算法来保证一致性,比复杂的 Paxos 算法更直接。
- 支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟、分片等情况等。
- 支持健康检查。
- 支持 http 和 dns 协议接口。
- 官方提供 web 管理界面。
- 安装和部署简单,使用起来也较为简单。Consul 使用 Go 语言编写,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合 。
安装和运行 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 实现服务注册和服务发现,可以按照以下步骤进行操作:
- 安装 Consul 客户端 SDK 和 Asp .Net Core 扩展包
首先,需要在 ASP.NET Core 应用程序中安装 Consul 客户端 SDK。可以通过 NuGet 包管理器来安装,在包管理器控制台中输入以下命令:
Install-Package Consul
Install-Package Consul.AspNetCore
- 配置服务注册
在应用程序启动时,需要将服务注册到 Consul 中。这通常在 Startup 类的 ConfigureServices 方法中完成。首先,示例代码如下:
/// <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提供的注入方式注册consulClientservices.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 consulservices.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}
}
Consul.AspNetCore 中的 AddConsul 和 AddConsulServiceRegistration 方法 究竟做了什么?
AddConsul 方法
可以看到通过 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));}
}
AddConsulServiceRegistration 方法
可以看出使用 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);}
}
配置 Consul 检查服务
/// <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提供的注入方式注册consulClientservices.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 consulservices.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;}/// <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;}