zoukankan      html  css  js  c++  java
  • (8)ASP.NET Core3.1 Ocelot Consul服务注册与发现

    1.服务注册与发现(Service Discovery)

    ●服务注册:我们通过在每个服务实例写入注册代码,实例在启动的时候会先去注册中心(例如Consul、ZooKeeper、etcd、Eureka)注册一下,那么客户端通过注册中心可以知道每个服务实例的地址,端口号,健康状态等等信息,也可以通过注册中心删除服务实例。这里注册中心相当于是负责维护服务实例的管控中心。
    ●服务发现:服务实例在注册中心注册之后,客户端通过注册中心可以了解这些服务实例运行状况。

    2.Consul

    如果要实现服务注册与发现,需要一个注册中心,这里主要介绍是Consul。
    Consul官网:https://www.consul.io/,它主要功能有:服务注册与发现、健康检查、Key/Value、多数据中心。
    如果在Windows上部署Consul,在consul.exe目录下执行consul.exe agent -dev命令行即可。
    如果在Linux上部署Consul,大伙可以移步我之前写过这篇文章“Consul在linux环境的集群部署”参考下。

    3.Asp.Net Core向Consul注册服务实例

    Asp.Net Core向Consul注册服务实例调用过程如下图所示(图片来源于https://www.cnblogs.com/zhouandke/p/10534836.html):

    Asp.Net Core向Consul注册服务实例需要在Gateway项目中引用Consul支持的NuGet软件包,安装命令如下:

    Install-Package Ocelot.Provider.Consul

    然后将以下内容添加到您的ConfigureServices方法中:

    services.AddOcelot().AddConsul();

    在Ocelot服务发现项目示例中,通过APIGateway项目GlobalConfiguration选项可以配置服务注册与发现,文件配置具体代码如下:

    {
      "Routes": [
        {
          "UseServiceDiscovery": true,
          "DownstreamPathTemplate": "/{url}",
          "DownstreamScheme": "http",
          "ServiceName": "MyService",
          "LoadBalancerOptions": {
            "Type": "RoundRobin"
          },
          "UpstreamPathTemplate": "/{url}",
          "UpstreamHttpMethod": [ "Get" ],
          "ReRoutesCaseSensitive": false
        }
      ],
      "GlobalConfiguration": {
        //服务发现配置
        "ServiceDiscoveryProvider": {
          //注册中心Consul地址
          "Host": "192.168.113.128",
          //注册中心Consul端口号
          "Port": 8500,
          "Type": "Consul",
          //以毫秒为单位,告诉Ocelot多久调用一次Consul来更改服务配置。
          "PollingInterval": 100,
          //如果你有在Consul上配置key/value,则在这里输入配置key。
          "ConfigurationKey": "MyService_AB"
        }
      }
    }

    ServiceDiscoveryProvider选项说明:
    ●Host:注册中心Consul地址。
    ●Port:注册中心Consul端口号。
    ●Type:注册中心类型。
    ●PollingInterval:以毫秒为单位,告诉Ocelot多久调用一次Consul来更改服务配置。
    ●ConfigurationKey:如果你有在Consul上配置key/value,则在这里输入配置key。

    4.项目演示

    4.1APIGateway项目

    ConfigureServices添加Ocelot、Consul注入:

    services.AddOcelot().AddConsul();

    Configure添加使用Ocelot:

    app.UseOcelot().Wait();

    服务发现配置如Ocelot服务发现项目示例一样。

    4.2Common项目

    先安装Consul的NuGet软件包,安装命令如下:

    Install-Package Consul

    在该项目添加一个AppExtensions扩展类,用来对服务APIServiceA、APIServiceB项目在Consul注册实例,为了展示效果,具体代码稍作修改如下:

    public static class AppExtensions
    {
        public static IServiceCollection AddConsulConfig(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddSingleton<IConsulClient, ConsulClient>(p => new ConsulClient(consulConfig =>
            {
                var address = configuration.GetValue<string>("Consul:Host");
                consulConfig.Address = new Uri(address);
            }));
            return services;
        }
        public static IApplicationBuilder UseConsul(this IApplicationBuilder app, string host = null, string port = null)
        {
            //获取consul客户端实例
            var consulClient = app.ApplicationServices.GetRequiredService<IConsulClient>();
            var logger = app.ApplicationServices.GetRequiredService<ILoggerFactory>().CreateLogger("AppExtensions");
            var lifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
    
            if (!(app.Properties["server.Features"] is FeatureCollection features)) return app;
    
            //var addresses = features.Get<IServerAddressesFeature>();
            //var address = addresses.Addresses.FirstOrDefault();
            //if (address == null)
            //{
            //    return app;
            //}
    
            var address = host + ":" + port;
            if (string.IsNullOrWhiteSpace(host) || string.IsNullOrWhiteSpace(port))
            {
                Console.WriteLine($"host或者port为空!");
                return app;
            }
    
            Console.WriteLine($"address={address}");
            var uri = new Uri(address);
            Console.WriteLine($"host={uri.Host},port={uri.Port}");
    
            var registration = new AgentServiceRegistration()
            {
                ID = $"MyService-{uri.Port}",
                Name = "MyService",
                Address = $"{uri.Host}",
                Port = uri.Port,
                Check = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
                    Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔
                    HTTP = $"{address}/HealthCheck",//健康检查地址
                    Timeout = TimeSpan.FromSeconds(5)//超时时间
                }
            };
            logger.LogInformation("Registering with Consul");
            logger.LogInformation($"Consul RegistrationID:{registration.ID}");
            //注销
            consulClient.Agent.ServiceDeregister(registration.ID).ConfigureAwait(true);
            //注册
            consulClient.Agent.ServiceRegister(registration).ConfigureAwait(true);
            //应用程序关闭时候
            lifetime.ApplicationStopping.Register(() =>
            {
                //正在注销
                logger.LogInformation("Unregistering from Consul");
                consulClient.Agent.ServiceDeregister(registration.ID).ConfigureAwait(true);
            });
            //每个服务都需要提供一个用于健康检查的接口,该接口不具备业务功能。服务注册时把这个接口的地址也告诉注册中心,注册中心会定时调用这个接口来检测服务是否正常,如果不正常,则将它移除,这样就保证了服务的可用性。
            app.Map("/HealthCheck", s =>
            {
                s.Run(async context =>
                {
                    await context.Response.WriteAsync("ok");
                });
            });
            return app;
        }
    }

    4.3APIServiceA项目

    项目添加一个Get方法,对应APIGateway项目的路由上下游配置,具体代码如下:

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            var port = Request.Host.Port;
            return new string[] { "value1", "value2", port.Value.ToString() };
        }
    }

    appsettings.json配置加入Consul地址:

    "Consul": {
      "Host": "http://192.168.113.128:8500"
    }

    4.4APIServiceB项目

    项目添加一个Get方法,对应APIGateway项目的路由上下游配置,具体代码如下:

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            var port = Request.Host.Port;
            return new string[] { "value3", "value4", port.Value.ToString() };
        }
    }

    appsettings.json配置加入Consul地址:

    "Consul": {
      "Host": "http://192.168.113.128:8500"
    }

    4.5项目运行

    在APIServiceA、APIServiceB项目的ConfigureServices添加Consul配置:

    services.AddConsulConfig(Configuration);

    在Configure添加Consul服务注册:

    APIServiceA:app.UseConsul("http://172.168.18.73", "9999");
    APIServiceB:app.UseConsul("http://172.168.18.73", "9998");

    把APIGateway、APIServiceA、APIServiceB三个项目部署到IIS上:

    三个项目运行起来后,通过浏览器Consul客户端可以看到MyService节点服务情况:

    点击打开MyService节点可以看到注册到Consul的APIServiceA、APIServiceB服务状况:

    如果把APIServiceB服务实例站点停掉:

    通过Consul客户端会看到APIServiceB服务实例已经被剔除了:

    如果输入CTRL+C把集群中某一个Consul服务关闭,那么集群会重新选举一个新的leader,负责处理所有服务实例的查询和事务:



    参考文献:
    Ocelot官网

  • 相关阅读:
    python while循环语句 结合 if else pass temp语句求触发的余数 的练习题
    IF函数多个条件判断及嵌套
    Python 字符串 加减乘除
    Python条件语句 -- if ,else ( 如果 ,那么)
    input 变量名命名规则
    Python解释器的头部编码用途
    switch留个爪,之后还需要再研究下
    面向对象+JAVA基础
    爱因斯坦台阶
    成功的拆开了SELECT里JOIN个SELECT是啥
  • 原文地址:https://www.cnblogs.com/wzk153/p/14109705.html
Copyright © 2011-2022 走看看