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

news2024/10/2 14:28:18

文章目录

    • 什么是 Consul?
    • 安装和运行 Consul
    • Asp .Net Core 如何集成 Consul 实现服务注册和健康检查
    • Consul.AspNetCore 中的 AddConsul 和 AddConsulServiceRegistration 方法 究竟做了什么?
      • AddConsul 方法
      • AddConsulServiceRegistration 方法
    • 配置 Consul 检查服务
    • 封装成扩展
    • 效果

什么是 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}" }; //添加
            });


            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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1378070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【回顾2023,展望2024】砥砺前行

2023年总结 转眼间&#xff0c;迎来了新的一年2024年&#xff0c;回顾2023&#xff0c;对于我来说是一个充满平凡但又充实又幸运的一年。这一年经历了很多的事情&#xff0c;包括博客创作、技术学习、出书、买房等&#xff0c;基本上每件事情都是一个前所未有的挑战和机遇、使…

科研学习|论文解读——信息世界映射方法

题目&#xff1a;信息世界映射的下一步是什么&#xff1f;在情境中理解信息行为/实践的国际化和多学科方法&#xff08;What is next for information world mapping? International and multidisciplinary approaches to understanding information behaviors/ practices in …

Jmeter Linux环境压测Lottery接口

1、把Dubbo插件放到Linux中Jmeter的lib/ext目录下 2、参数化 3、设置线程数 4、把测试计划中的Dubbo路径替换成Linux中的路径 /home/apache-jmeter-5.5/lib/ext 5、上传压测脚本到压力机 6、执行压测&#xff0c;观察是否有消息积压 ①Jmeter中执行压测脚本 ②检查mq控制台是…

flask框架基本使用

一、使用pycharm创建项目 1.创建项目 2.调整默认终端 3.打开虚拟终端 打开终端可以看出使用的是p1的虚拟机终端了 4.pyCharm小技巧 在flask种输入一个完整并且存在的函数名称或者类明&#xff0c; 然后 Alt 回车&#xff0c;pycharm可以自动导包&#xff0c;不用在手动在代…

【java八股文】之多线程篇

1、简述线程、进程的基本概念。以及他们之间关系是什么 进程&#xff1a;是程序的一次执行的过程&#xff0c;是系统运行的基本单位&#xff0c;其中包含着程序运行过程中一些内存空间和系统资源。进程在运行过程中都是相互独立&#xff0c;但是线程之间运行可以相互影响。 线程…

Docker安装Redis 配置文件映射以及密码设置

安装直接docker pull redis即可&#xff0c;默认redis最新版 设置两个配置文件路径 mkdir -p /root/docker/redis/data mkdir -p /root/docker/redis/conf touch redis.conf // 容器挂载用conf配置文件 bind 0.0.0.0 protected-mode yes port 6379 tcp-backlog 511 timeout…

人工智能技术的突破性进展使得AI数字人的出现成为可能

随着科技的飞速发展&#xff0c;人机交互已成为当今社会中的热门话题。近年来&#xff0c;人工智能技术的突破性进展使得AI数字人的出现成为可能&#xff0c;其将开启一个全新的人机交互时代。 AI数字人是一种利用人工智能技术创建的虚拟人物&#xff0c;能够模拟真实人类的思…

androj studio安装及运行源码

抖音教学视频 目录 1、 jdk安装 2、下载安装androj studio 3 、打开源码安装运行相关组件 4、 安装模拟器 1、 jdk安装 安卓项目也是java开发的&#xff0c;运行在虚拟机上&#xff0c;安装jdk及运行的时候&#xff0c;就会自动生成虚拟机&#xff0c; jdk前面已经讲过&…

自己动手写编译器:自顶向下的自动状态机

本节我们介绍编译原理中一种新的数据结构叫自顶向下的自动状态机。前面我们在做词法解析时接触了大量自动状态机&#xff0c;他们存在一个缺陷那就是无法对要识别的字符串进行计数&#xff0c;因此当我们要判断括号对是否匹配时&#xff0c;使用在词法解析的状态机就处理不了&a…

C++基础算法之枚举

星光不问赶路人 岁月不负有心人 &#x1f3a5;烟雨长虹&#xff0c;孤鹜齐飞的个人主页 &#x1f525;个人专栏 期待小伙伴们的支持与关注&#xff01;&#xff01;&#xff01; 目录 枚举算法的简介 枚举算法的运用 #特别数的和 题目描述# 输入描述# 输入输出样例# #找到最多…

机器学习+大数据项目

一、特征工程 特征清洗 特征监控 特征选择 计算每一个特征和响应变量的相关性 通过L1正则项来选择特征 训练能对特征打分的预选模型 通过特征组合后再来选择特征 通过深度学习来进行特征选择

Python笔记08-面向对象

文章目录 类和对象构造方法内置方法封装继承类型注解多态 类只是一种程序内的“设计图纸”&#xff0c;需要基于图纸生产实体&#xff08;对象&#xff09;&#xff0c;才能正常工作 这种套路&#xff0c;称之为&#xff1a;面向对象编程 类和对象 定义类的语法如下&#xff…

Qt 调试体统输出报警声

文章目录 前言一、方法1 使用 Qsound1.添加都文件 直接报错2.解决这个错误 添加 QT multimedia3. 加入代码又遇到新的错误小结 二、第二种方法1.引入库 总结 前言 遇到一个需求&#xff0c;使用Qt输出报警声&#xff0c;于是试一试能调用的方法。 一、方法1 使用 Qsound 1.…

Hive 数据同步

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据&#xff08;方案&#xff09; 1、环境&#xff1a;断直连模拟环境 2、操作机器&#xff1a;ETL 机器 XX.14.36.216 3、工作路径&#xff1a;cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令&#xff1a; 命令…

IPv6路由协议----BGP4+

BGP基本概念 边界网关协议BGP(Border Gateway Protocol)是一种实现自治系统AS(Autonomous System)之间的路由可达,并选择最佳路由的距离矢量路由协议。 MP-BGP是对BGP4进行了扩展达到在不同网络中应用的目的,BGP4原有的消息机制和路由机制并没有改变。MP-BGP在IPv6单播网…

如何在“Microsoft Visual Studio”中使用OpenCV构建应用程序

我在这里描述的所有内容都将应用于 OpenCV 的界面。我首先假设您已经阅读并成功完成了 Windows 中的安装教程。因此&#xff0c;在进一步操作之前&#xff0c;请确保您有一个包含 OpenCV 头文件和二进制文件的 OpenCV 目录&#xff0c;并且您已按照此处所述设置环境变量 设置 O…

每日一题——LeetCode1103.分糖果 ||

方法一 个人方法&#xff1a; 有多少人就创建多大的数组并把数组的所有元素初始化为0&#xff0c;只要还有糖果&#xff0c;就循环给数组从头到尾添加糖果&#xff0c;每次分的糖果数递增1&#xff0c;最后可能刚好分完也可能不够&#xff0c;不够就还剩多少给多少。 var dis…

力扣刷题记录(28)LeetCode:797、200、463

797. 所有可能的路径 解题思路&#xff1a;回溯算法&#xff0c;当收集到的路径的最后一个值等于n-1时&#xff0c;收集答案。 参数&#xff1a;图、当前结点 class Solution { public:vector<int> path;vector<vector<int>> ans;void dfs(vector<vector…

Java获取IP地址及对应的归属地

目录 前言 一、获取访问的IP地址 二、通过IP地址获取对应的归属地 2.1 Ip2region 2.1.1 高达 99.9 % 的查询准确率 2.1.2 Ip2region V2.0 特性 2.1.3 多语言以及查询客户端的支持 2.2 Ip2region xdb Java 查询客户端实现 2.2.1 引入 Maven 仓库 2.2.2 ip2region.xdb …

从Scroll怒喷社区用户事件,看L2龙头ZKFair的做事格局

这两天&#xff0c;随着美国SEC正式批准所有11只比特币现货ETF的消息公布&#xff0c;吸引了传统主流增量资金的入场&#xff0c;比特币多头一举将比特币干到了48000刀的位置&#xff0c;并随时向着前高发起了冲击。比特币的强势带动了其他加密资产的保障&#xff0c;整个加密市…