首页 > 编程语言 >Asp .Net Core 系列: 集成 Consul 实现 服务注册与健康检查

Asp .Net Core 系列: 集成 Consul 实现 服务注册与健康检查

时间:2024-01-12 22:55:56浏览次数:37  
标签:Core Asp 服务 Consul options consulOptions services public

目录

什么是 Consul?

官网:https://www.consul.io/

Consul 是一款开源的服务发现和配置管理工具,它能够监控应用程序和服务之间的通信,并提供了一组 API 和 Web UI,用于管理服务和配置。

Consul 是分布式的、高可用的、可横向扩展的,具备以下特性:

  1. 服务发现:Consul 通过 DNS 或者 HTTP 接口使服务注册和服务发现变得很容易,一些外部服务,例如 saas 提供的也可以一样注册。
  2. 健康检查:健康检测使 Consul 可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
  3. 键/值存储:一个用来存储动态配置的系统。提供简单的 HTTP 接口,可以在任何地方操作。
  4. 多数据中心:无需复杂的配置,即可支持任意数量的区域。

Consul 的优势:

  1. 使用 Raft 算法来保证一致性,比复杂的 Paxos 算法更直接。
  2. 支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟、分片等情况等。
  3. 支持健康检查。
  4. 支持 http 和 dns 协议接口。
  5. 官方提供 web 管理界面。
  6. 安装和部署简单,使用起来也较为简单。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 实现服务注册和服务发现,可以按照以下步骤进行操作:

  1. 安装 Consul 客户端 SDK 和 Asp .Net Core 扩展包

首先,需要在 ASP.NET Core 应用程序中安装 Consul 客户端 SDK。可以通过 NuGet 包管理器来安装,在包管理器控制台中输入以下命令:

Install-Package Consul
Install-Package Consul.AspNetCore
  1. 配置服务注册
    在应用程序启动时,需要将服务注册到 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提供的注入方式注册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
    }
}

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提供的注入方式注册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;
        }

效果

image

image

标签:Core,Asp,服务,Consul,options,consulOptions,services,public
From: https://www.cnblogs.com/vic-tory/p/17961740

相关文章

  • 聊一聊如何整合Microsoft.Extensions.DependencyInjection和Castle.Core(三)
    前言今天的第三篇,感觉没啥人看呀,难道没有兄弟跟我有同样的整合需求吗???手动,本文会简短一些,介绍下CastleCore作为代理库的一些缺点甚至是硬伤异步支持先上代码///<summary>///异常捕获、日志记录和耗时监控拦截器2024-1-1221:28:22///</summary>publicclassCatch......
  • netcore webpi 通过signalr 给vue项目推送消息
     最近项目上需要做个服务给前端推消息,首先就想到了signalr,关于signalr详情可以参考微软官方文档(ASP.NETCoreSignalR概述|MicrosoftLearn),微软现在也有使用教程(ASP.NETCoreSignalR入门|MicrosoftLearn)微软教程是通过使用库管理器(LibMan)从unpkg 获取客户端库,如......
  • .NET Core MemoryCache缓存批量获取Key或者删除
    .NetCore下使用缓存,除了大家耳熟能详的Redis做分布式缓存外,本地内存缓存也会一起结合来使用,它存取更快,使我们的应用达到极致性能要求。这也是我们经常提到的3级或者4级缓存,每一层都有自己的使用场景,优缺点,结合业务特点来选择合适的才是王道。这里我们就使用Net原生的Microsoft......
  • 无涯教程-Redis - ZSCORE 命令函数
    RedisZSCORE命令返回键排序后的元素的得分,如果元素不存在于排序集中,或者键不存在,则返回nil。ZSCORE-返回值返回元素的分数值。ZSCORE-语法以下是RedisZSCORE命令的基本语法。redis127.0.0.1:6379>ZSCOREkeymemberZSCORE-示例redis127.0.0.1:6379>ZADDm......
  • 无涯教程-Redis - ZREMRANGEBYSCORE 命令函数
    RedisZREMRANGEBYSCORE命令删除存储在键中的排序集中的所有元素,这些元素的分数介于最小和最大(含)之间。ZREMRANGEBYSCORE-返回值返回删除的元素数量。ZREMRANGEBYSCORE-语法以下是RedisZREMRANGEBYSCORE命令的基本语法。redis127.0.0.1:6379>ZREMRANGEBYSCORE......
  • AWS IoT Core 实战指南
    AmazonWebServices(AWS)提供了全球范围内的托管服务,其中包括AWSIoTCore,专为连接和管理物联网设备而设计。这个实战指南将带你一步步了解如何使用AWSIoTCore来注册设备、提高安全性、进行通信以及利用设备影子功能。设备注册1.创建Thing(设备)在AWSIoT控制台中,创建一......
  • openGauss学习笔记-188 openGauss 数据库运维-常见故障定位案例-core问题定位
    openGauss学习笔记-188openGauss数据库运维-常见故障定位案例-core问题定位188.1磁盘满故障引起的core问题188.1.1问题现象TPCC运行时,注入磁盘满故障,数据库进程gaussdbcore掉,如下图所示。188.1.2原因分析数据库本身机制,在磁盘满时,Xlog日志无法进行写入,通过panic日志退......
  • aspnetcore使用websocket实时更新商品信息
    先演示一下效果,再展示代码逻辑。中间几次调用过程省略。。。暂时只用到了下面四个项目1.产品展示页面中第一次通过接口去获取数据库的列表数据///<summary>///获取指定的商品目录///</summary>///<paramname="pageSize"></param>///<paramname="pageIndex"></p......
  • 第5章 在 ASP.NET Core Web 应用进程中使用 EF Core
    本章涵盖在ASP.NETCore中使用EFCore在ASP.NETCore中使用依赖注入在ASP.NET核心MVC操作中访问数据库使用EFCore迁移更新数据库使用async/await提高可扩展性在本章中,您将使用ASP.NETCore构建一个真正的Web应用进程,将所有内容集成在一起。当然,使用ASP.N......
  • 第4章 在业务逻辑中使用 EF Core
    本章涵盖了解业务逻辑及其对EFCore的使用从简单到复杂的三种业务逻辑审查每种类型的业务逻辑,包括优缺点添加一个步骤,用于在将数据写入数据库之前验证数据使用事务以菊花链方式连接代码串行实际应用进程旨在提供一组服务,从在计算机上保存简单的事物列表到类似管理核反应......