Ocelot 网关 和 consul 服务发现

服务发现 Consul

一、安装和启动

下载 [Consul](https://www.consul.io/downloads.html)

下载完成后,解压,只有一个consul.exe,把目录添加到环境变量的PATH,注意添加到系统变量,仅仅加入用户变量不起作用。打开cmd,输入

consul agen -dev  // 启动Consul服务

二、在aspnetcore中注册Consul

1. 定义配置项
/// <summary>
/// Consul配置
/// </summary>
public class ConsulOptions
{
    /// <summary>
    /// Consul服务器的地址
    /// </summary>
    public string HttpEndPoint { get; set; }

    /// <summary>
    /// 数据中心名称
    /// </summary>
    public string DataCenter { get; set; }

    /// <summary>
    /// Dns服务器端点
    /// </summary>
    public DnsEndPoint DnsEndPoint { get; set; }
}
/// <summary>
/// Dns节点
/// </summary>
public class DnsEndPoint
{
    /// <summary>
    /// 服务器地址
    /// </summary>
    public string Address { get; set; }

    /// <summary>
    /// 端口
    /// </summary>
    public int Port { get; set; }

    /// <summary>
    /// 转换为IpEndPoint
    /// </summary>
    /// <returns></returns>
    public IPEndPoint ToIpEndPoint()
    {
        return new IPEndPoint(IPAddress.Parse(Address), Port);
    }
}
public class ServiceDiscoveryOptions
{
    /// <summary>
    /// 服务名称
    /// </summary>
    public string ServiceName { get; set; }

    /// <summary>
    /// Consul配置
    /// </summary>
    public ConsulOptions Consul { get; set; }
}
2. 在appsettings.json中添加配置
"ServiceDiscovery": {
    "ServiceName": "webapi1",
    "Consul": {
        "DataCenter": "dc1",
        "HttpEndPoint": "http://127.0.0.1:8500",
        "DnsEndPoint": {
          "Address": "127.0.0.1",
          "Port": 8600
        }
    }
}
3. 在startup中注册配置项
services.Configure<ServiceDiscoveryOptions>(
    Configuration.GetSection("ServiceDiscovery"));
4. 注册IConsulClient服务
services.AddSingleton<IConsulClient>(new ConsulClient(config =>
{
    config.Address = new Uri(Configuration["ServiceDiscovery:Consul:HttpEndPoint"]);
    config.Datacenter = Configuration["ServiceDiscovery:Consul:DataCenter"];
}));
5. 在Configure中将自身注册到Consul服务
ILifeTime的ApplicationStarted,程序启动时注册到Consul,
使用IApplicationBuilder的Feature获取当前启动的ip和端口,作为服务的ID
public static class ApplicationBuilderExtensions
{
    /// <summary>
    /// 获取当前启动应用绑定的IP和端口
    /// </summary>
    public static IEnumerable<Uri> GetAddress(this IApplicationBuilder app)
    {
        var features = app.Properties["server.Features"] as FeatureCollection;
        return features?.Get<IServerAddressesFeature>()
            .Addresses.Select(p => new Uri(p)) ?? new List<Uri>();
    }
}
public void Configure(
    IApplicationBuilder app, IHostingEnvironment env,
    IApplicationLifetime lifetime, IConsulClient consul,
    IOptions<ServiceDiscoveryOptions> serviceDiscoveryOptions)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    lifetime.ApplicationStarted.Register(() =>
    {
        var addresses = app.GetAddress();
        foreach (var address in addresses)
        {
            var serviceId =
            $"{serviceDiscoveryOptions.Value.ServiceName}_{address.Host}:{address.Port}";

            consul.Agent.ServiceRegister(new AgentServiceRegistration
            {
                ID = serviceId,
                Name = serviceDiscoveryOptions.Value.ServiceName,
                Address = address.Host,
                Port = address.Port,
                Check = new AgentServiceCheck
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
                    Interval = TimeSpan.FromSeconds(5),
                    HTTP = new Uri(address, "api/Health/Check").OriginalString,
                    Timeout = TimeSpan.FromSeconds(5)
                }
            }).Wait();

            lifetime.ApplicationStopped.Register(() =>
            {
                consul.Agent.ServiceDeregister(serviceId).Wait();
            });
        }
    });

    app.UseAuthentication();

    app.UseMvc();
}

三、在项目中使用Consul

1、 定义一个接口
public interface IServiceDiscoveryManager
{
    string GetApi(string serviceName);
}
2、 实现一个Consul的服务发现工具
public class ConsulServiceDiscoveryManager : IServiceDiscoveryManager
{
    private readonly IConsulClient _client;

    private readonly ILogger<ConsulServiceDiscoveryManager> _logger;

    // 手动高亮,忽略大小写,这个很重要
    private readonly ConcurrentDictionary<string, List<string>> _dict =
        new ConcurrentDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);

    private DateTime _syncTime = DateTime.Now.AddMinutes(-11);

    private static object _lock = new object();

    public ConsulServiceDiscoveryManager(IConsulClient client, ILogger<ConsulServiceDiscoveryManager> logger)
    {
        _client = client;
        _logger = logger;
    }

    private ConcurrentDictionary<string, List<string>> GetAllServices()
    {
        if (_syncTime < DateTime.Now.AddSeconds(-10) || !_dict.Keys.Any())
        {
            _dict.Clear();
            var services = _client.Agent.Services().Result.Response.Select(s => s.Value).GroupBy(s => s.Service);
            foreach (var service in services)
            {
                _dict.TryAdd(service.Key, service.Select(s => $"{s.Address}:{s.Port}").ToList());
            }
            _syncTime = DateTime.Now;
        }
        return _dict;
    }

    public List<string> GetApis(string serviceName)
    {
        if(!GetAllServices().TryGetValue(serviceName, out var hosts))
        {
            return new List<string>();
        }
        return hosts;
    }

    public string GetApi(string serviceName)
    {
        var hosts = GetApis(serviceName);

        var count = hosts.Count();
        if(count == 0)
        {
            return string.Empty;
        }
        else if(count == 1)
        {
            return hosts.First();
        }

        var ran = new Random().Next(0, count);
        return hosts.ElementAt(ran);
    }
}
3、 在ConfigureServices中注册IServiceDiscoveryManager。
捎带把 IHttpConlientFactory 也注册掉,
注意在 appsettings.json 里把之前的 ServiceDiscoverty 的配置项添加进去,
也可以只添加Consul的部分
services.AddSingleton<IConsulClient>(new ConsulClient(config =>
{
    config.Address = new Uri(Configuration["ServiceDiscovery:Consul:HttpEndPoint"]);
    config.Datacenter = Configuration["ServiceDiscovery:Consul:DataCenter"];
}));

services.AddSingleton<IServiceDiscoveryManager, ConsulServiceDiscoveryManager>();

services.AddHttpClient();
4、 在Controller中使用,也可以封装一个Client,后面可以直接用。
public class TestController : Controller
{
    private readonly ILogger<TestController> _logger;
    private readonly IHttpClientFactory _clientFactory;
    private readonly IServiceDiscoveryManager _serviceDiscoveryManager;

    public TestController(ILogger<TestController> logger,
        IConsulClient consul,
        IHttpClientFactory clientFactory,
        IServiceDiscoveryManager serviceDiscoveryManager)
    {
        _logger = logger;
        _clientFactory = clientFactory;
        _serviceDiscoveryManager = serviceDiscoveryManager;
    }

    public IActionResult Index()
    {
        var apiHost = _serviceDiscoveryManager.GetApi("WebApi1");
        using(var client = _clientFactory.CreateClient())
        {
            var result = client.GetAsync($"http://{apiHost}/api/values").Result;
            return Content(result.Content.ReadAsStringAsync().Result);
        }
    }
}

Ocelot 集成 Consul

一、 引入Nuget包
Ocelot
Ocelot.Provider.Consul
二、 在根目录下创建ocelog.json
{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "UseServiceDiscovery": true,
      "ServiceName": "WebApi1",
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询
      },
      "UpstreamPathTemplate": "/WebApi1/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://127.0.0.1:5010",
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    }
  }
}
三、 修改Program.cs,把刚刚创建好的ocelot.json添加到配置项
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(configuration =>
        {
            configuration.AddJsonFile("ocelot.json");
        })
        .UseUrls("http://localhost:5010")
        .UseStartup<Startup>();
四、 修改Startup,注册服务,使用ocelot的中间件
public void ConfigureServices(IServiceCollection services)
{
    services.AddOcelot().AddConsul();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseOcelot().Wait();
}
五、 一个比较全的配置项说明
{
  "ReRoutes": [
    {//官方文档ReRoutes全节点示例
      //Upstream表示上游请求,即客户端请求到API Gateway的请求
      "UpstreamPathTemplate": "/", //请求路径模板
      "UpstreamHttpMethod": [ //请求方法数组
        "Get"
      ],

      //Downstreamb表示下游请求,即API Gateway转发的目标服务地址
      "DownstreamScheme": "http", //请求协议,目前应该是支持http和https
      "DownstreamHost": "localhost", //请求服务地址,应该是可以是IP及域名
      "DownstreamPort": 51779, //端口号
      "DownstreamPathTemplate": "/", //下游请求地址模板
      "RouteClaimsRequirement": { //标记该路由是否需要认证
        "UserType": "registered" //示例,K/V形式,授权声明,授权token中会包含一些claim,如填写则会判断是否和token中的一致,不一致则不准访问
      },
      //以下三个是将access claims转为用户的Header Claims,QueryString,该功能只有认证后可用
      "AddHeadersToRequest": { //
        "UserType": "Claims[sub] > value[0] > |", //示例
        "UserId": "Claims[sub] > value[1] > |"//示例
      },
      "AddClaimsToRequest": {},
      "AddQueriesToRequest": {},

      "RequestIdKey": "", //设置客户端的请求标识key,此key在请求header中,会转发到下游请求中
      "FileCacheOptions": { //缓存设置
        "TtlSeconds": 15, //ttl秒被设置为15,这意味着缓存将在15秒后过期。
        "Region": "" //缓存region ,可以使用administrator API清除
      },
      "ReRouteIsCaseSensitive": false, //路由是否匹配大小写
      "ServiceName": "", //服务名称,服务发现时必填

      "QoSOptions": { //断路器配置,目前Ocelot使用的Polly
        "ExceptionsAllowedBeforeBreaking": 0, //打开断路器之前允许的例外数量。
        "DurationOfBreak": 0,                 //断路器复位之前,打开的时间(毫秒)
        "TimeoutValue": 0                     //请求超时时间(毫秒)
      },
      "LoadBalancerOptions": {
        "type": "RoundRobin"   // 负载均衡 RoundRobin(轮询)/LeastConnection(最少连接数)
      },
      "RateLimitOptions": { //官方文档未说明
        "ClientWhitelist": [], // 白名单
        "EnableRateLimiting": false, // 是否限流
        "Period": "1m", // 1s,4m,1h,1d
        "PeriodTimespan": 0, // 多少秒之后客户端可以充实
        "Limit": 0 // 一个时间周期最多可以请求的次数
      },
      "AuthenticationOptions": { //认证配置
        "AuthenticationProviderKey": "", //这个key对应的是代码中.AddJWTBreark中的Key
        "AllowedScopes": []//使用范围
      },
      "HttpHandlerOptions": {
        "AllowAutoRedirect": true, //指示请求是否应该遵循重定向响应。 如果请求应该自动遵循来自Downstream资源的重定向响应,则将其设置为true; 否则为假。 默认值是true。
        "UseCookieContainer": true //该值指示处理程序是否使用CookieContainer属性来存储服务器Cookie,并在发送请求时使用这些Cookie。 默认值是true。
      },
      "UseServiceDiscovery": false //使用服务发现,目前Ocelot只支持Consul的服务发现
    }
  ],
  "GlobalConfiguration": {}
}
六、 再来一个简单的不使用Consul的配置项
{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5001
        },
        {
          "Host": "localhost",
          "Port": 5002
        }
      ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "UpstreamPathTemplate": "/UserService/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ]
    }
  ]
}
七、熔断
引入Nuget包
Ocelot.Provider.Polly

原文地址:https://www.cnblogs.com/diwu0510/p/11706263.html

时间: 2024-10-08 21:01:19

Ocelot 网关 和 consul 服务发现的相关文章

微服务之:从零搭建ocelot网关和consul集群

原文:微服务之:从零搭建ocelot网关和consul集群 介绍 微服务中有关键的几项技术,其中网关和服务服务发现,服务注册相辅相成. 首先解释几个本次教程中需要的术语 网关 Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界上提供给外部访问内部接口服务的统一入口,简化了外部由于多服务协同完成任务时的繁琐配置.网关组件有Kong,ocelot, 服务发现:通过网关访问内部各个微服务,网关要找到所需服务的过程称为服务发现 服务注册:既然有服务发现,前提是要把所需服

.NET CORE2.2 下 Ocelot+Consul服务发现踩坑记录

历史原因,笔者所在公司的项目目前还在使用 .NET CORE 2.2版本,在所有业务应用升级完成服务注册发现之后,最后剩下 Ocelot 网关服务升级.在升级过程中,遇到一些问题,记录此文,以便有相同情况的同学参考. 1. Ocelot 升级服务发现 根据官方文档 ,通过简单的添加配置,既可以将原有配置方式改为服务发现: 安装插件 Install-Package Ocelot.Provider.Consul 13.5.2,.Net Core 2.x 最后一个版本 配置服务 s.AddOcelot

基于Docker的Consul服务发现集群搭建

原文:基于Docker的Consul服务发现集群搭建 在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架构示范,也会更加贴近于实际应用环境. 一.示例整体架构 此示例会由一个API Gateway, 一个Consul Client以及三个Consul Server组成,有关Consul的Client和Server这两种模式的Agent的背景知识,请

Ocelot(十一)- 服务发现

Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用相同的服务发现提供程序,以便在ReRoute级别指定ServiceName. Consul GlobalConfiguration中需要以下内容. 提供者是必需的,如果你没有指定主机和端口,默认使用Consul. "ServiceDiscoveryProvider": { "Ho

Redola.Rpc 集成 Consul 服务发现

Redola.Rpc 解决了什么问题? Redola.Rpc 是一个使用 C# 开发的 RPC 框架,代码开源在 GitHub 上.目前版本仅支持 .NET Framework 4.6 以上版本,未来待系统稳健后再考虑移植 .NET Standard 和 .NET Core. Redola.Rpc 在 0.3.2 版本中,尝试解决几个 RPC 设计问题: 我是谁?(Local Actor) 如何告诉别人我是谁?(Actor Directory) 我提供什么服务?(Service Catalog

Spring Cloud Consul—服务发现与Consul

服务发现是基于微服务架构的关键原则之一.尝试配置每个客户端或某种形式的约定可能非常困难,可以非常脆弱.Consul通过HTTP API和DNS提供服务发现服务.Spring Cloud Consul利用HTTP API进行服务注册和发现.这不会阻止非Spring Cloud应用程序利用DNS界面.Consul代理服务器在通过八卦协议进行通信的集群中运行,并使用Raft协议协议. 如何激活 要激活Consul服务发现,请使用组org.springframework.cloud和artifact i

一篇文章了解Consul服务发现实现原理

从 2016 年起就开始接触 Consul,使用的主要目的就是做服务发现,后来逐步应用于生产环境,并总结了少许使用经验. 最开始使用 Consul 的人不多,这两年微服务越来越火,使用 Consul 的人也越来越多. 经常有人会问一些问题,比如: 服务注册到节点后,其他节点为什么没有同步? Client 是干什么的?(Client 有什么作用?) 能不能直接注册到 Server?(是否只有 Server 节点就够了?) 服务信息是保存在哪里的? 如果节点挂了,健康检查能不能转移到别的节点? 有些

.NET Core微服务实施之Consul服务发现与治理

原文:.NET Core微服务实施之Consul服务发现与治理 Consul官网:https://www.consul.io Consul下载地址:https://www.consul.io/downloads.html Consul nuget 命令:Install-Package Consul 我的理解是,Consul是一个服务管理者,系统中所有使用到的服务他都帮你管理好,促销高峰需要新增服务的时候,服务开启来就自动注册到Consul中,服务下线关闭,也自动从Consul注销,无缝衔接,对于

安装-consul服务发现集群

centos 7.4.x consul  1.2.2 list: 172.16.16.103 172.16.16.112 172.16.16.115 下载: #cd /usr/local/ #wget  https://releases.hashicorp.com/consul/1.2.2/consul_1.2.2_linux_amd64.zip #tar zxvf xxxxxx.zip #第一台启动 #nohup ./consul agent -bind=172.16.16.112 -serv