使用Ocelot搭建网关Gateway

发布时间 2023-10-28 21:20:38作者: 江渔湖

一、Ocelot官网和学习地址

  官网:https://threemammals.com/ocelot

  Git:https://github.com/ThreeMammals/Ocelot

  文档:https://ocelot.readthedocs.io/en/latest/index.html

二、搭建网关Gateway

  1 .新建一个WebAPI服务进程,独立进程完成网关请求转发,承上启下。

    2.nuget-Ocelot 安装Ocelot类库  

                 

    3. Startup配置中间件和IOC注册

      builder.Configuration.AddJsonFile("configuration.json", false, true);//表示要读取这个配置文件

      builder.Services.AddOcelot();

      app.UseOcelot();//使用Ocelot的中间件来完成http响应

    4. 增加配置文件+指定地址     

 1 ////*****************************单地址多实例负载均衡********************************
 2 {
 3   "Routes": [
 4    {
 5      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
 6       "DownstreamScheme": "http",
 7       "DownstreamHostAndPorts": [
 8        {
 9           "Host": "127.0.0.1",
10           "Port": 5726
11         },
12         {
13           "Host": "127.0.0.1",
14           "Port": 5727
15         },
16         {
17           "Host": "127.0.0.1",
18           "Port": 5728
19         }//能负载均衡,但是不能动态伸缩---写到数据库动态?服务挂掉,人不一定知道----Consul可以,结合起来
20       ],
21       "UpstreamPathTemplate": "/T/{url}", //网关地址--url变量   //冲突的还可以加权重Priority
22       "UpstreamHttpMethod": [ "Get", "Post" ],
23       "LoadBalancerOptions": {
24         "Type": "RoundRobin" //轮询 //"LeastConnection" //最少连接数的服务器  "NoLoadBalance" //不负载均衡  //"CookieStickySessions" //会话粘滞  //
25       }
26      31     }
32   ]
33 }

三、Ocelot+Consul

  Ocelot也是写死的配置文件---无法做到服务动态伸缩,可以使用Ocelot+Consul来实现服务的动态伸缩

  1. Nuget Ocelot.Provider.Consul

  2. ConfigureServices AddConsul    

builder.Services.AddOcelot().AddConsul()

 

  3. 更新配置文件   

{
  "Routes": [
    {
      "UpstreamPathTemplate": "/T/{url}", //网关地址--url变量
      "UpstreamHttpMethod": [ "Get", "Post" ],

      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
      "DownstreamScheme": "http",

      "UseServiceDiscovery": true,
      "ServiceName": "TestService", //consul服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
     }
    }
  ],
  "GlobalConfiguration": {
    //"BaseUrl": "http://127.0.0.1:6299", //网关对外地址
    "ServiceDiscoveryProvider": {
      "Host": "127.0.0.1",
      "Port": 8500,
     "Type": "Consul" //由Consul提供服务发现, 每次请求去consul
    } 

  }
}

四、服务治理:缓存

  1. Nuget Ocelot.Cache.CacheManager

  2. ConfigureServices AddCacheManager   

builder.Services.AddOcelot()
    .AddConsul()
    .AddCacheManager(x =>
    {
        x.WithDictionaryHandle();//默认字典存储---默认---换成分布式的--换个存储的介质
    })

 

  3. 配置文件

     "FileCacheOptions": {
       "TtlSeconds": 15, //Second
       "Region": "UserCache" //可以调用Api缓存清理
      }

 

  4. 缓存扩展CustomCache+IOC替换

//来个扩展--非常常见的基于IOC的扩展---IOC控制反转,用来生成对象---会先注册映射关系,然后反射生成---那就可以去覆盖映射关系,换成自定义对象,就可以做到扩展

builder.Services.AddSingleton<IOcelotCache<CachedResponse>, CustomCache>();//IOC替换
public class CustomCache : IOcelotCache<CachedResponse>
{
    private class CacheDataModel
    {
        public CachedResponse CachedResponse { get; set; }
        public DateTime Timeout { get; set; }
        public string Region { get; set; }
    }

    private static Dictionary<string, CacheDataModel> CustomCacheDictionary = new
         Dictionary<string, CacheDataModel>();

    /// <summary>
    /// 没做过期清理  所以需要
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="ttl"></param>
    /// <param name="region"></param>
    public void Add(string key, CachedResponse value, TimeSpan ttl, string region)
    {
        Console.WriteLine($"This is {nameof(CustomCache)}.{nameof(Add)}");
        //CustomCacheDictionary.Add(key, new CacheDataModel()
        //{
        //    CachedResponse = value,
        //    Region = region,
        //    Timeout = DateTime.Now.Add(ttl)
        //});
        CustomCacheDictionary[key] = new CacheDataModel()
        {
            CachedResponse = value,
            Region = region,
            Timeout = DateTime.Now.Add(ttl)
        };
    }

    public void AddAndDelete(string key, CachedResponse value, TimeSpan ttl, string region)
    {
        Console.WriteLine($"This is {nameof(CustomCache)}.{nameof(AddAndDelete)}");
        CustomCacheDictionary[key] = new CacheDataModel()
        {
            CachedResponse = value,
            Region = region,
            Timeout = DateTime.Now.Add(ttl)
        };
    }

    public void ClearRegion(string region)
    {
        Console.WriteLine($"This is {nameof(CustomCache)}.{nameof(ClearRegion)}");
        var keyList = CustomCacheDictionary.Where(kv => kv.Value.Region.Equals(region)).Select(kv => kv.Key);
        foreach (var key in keyList)
        {
            CustomCacheDictionary.Remove(key);
        }
    }

    public CachedResponse Get(string key, string region)
    {
        Console.WriteLine($"This is {nameof(CustomCache)}.{nameof(Get)}");
        if (CustomCacheDictionary.ContainsKey(key) && CustomCacheDictionary[key] != null
            && CustomCacheDictionary[key].Timeout > DateTime.Now
            && CustomCacheDictionary[key].Region.Equals(region))
        {
            return CustomCacheDictionary[key].CachedResponse;
        }
        else
            return null;
    }
}

五、超时机制

  调用服务的操作可以配置为执行超时,如果服务未能在这个时间内响应,将回复一个失败消息。

  1. Nuget Polly

  2. AddPolly()

  3. 配置文件 QOS  

   "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3, //允许多少个异常请求
        "DurationOfBreak": 10000, // 熔断的时间,单位为ms
        "TimeoutValue": 2000 //单位ms 如果下游请求的处理时间超过多少则自如将请求设置为超时 默认90秒
      }

 

 超时可能放弃正确结果,为的是保证服务的可用---尽早报错的方案

六、熔断机制,限流机制,熔断机制

  添加配置

//*****************************超时+限流+熔断+降级+Consul+Polly********************************
{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/T/{url}", //网关地址--url变量
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "UseServiceDiscovery": true,
      "ServiceName": "ZhaoxiService", //consul服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //轮询      LeastConnection-最少连接数的服务器   NoLoadBalance不负载均衡
      },
      "RateLimitOptions": {
        "ClientWhitelist": [ "eleven", "seven" ], //白名单 ClientId 区分大小写
        "EnableRateLimiting": true,
        "Period": "5m", //1s, 5m, 1h, 1d
        "PeriodTimespan": 30, //多少秒之后客户端可以重试
        "Limit": 5 //统计时间段内允许的最大请求数量---张队贡献的代码
      },
      //"AuthenticationOptions": {
      //  "AuthenticationProviderKey": "UserGatewayKey",
      //  "AllowedScopes": []
      //},
      //"QoSOptions": {
      //  "ExceptionsAllowedBeforeBreaking": 3, //允许多少个异常请求
      //  "DurationOfBreak": 10000, // 熔断的时间,单位为ms
      //  "TimeoutValue": 2000 //单位ms 如果下游请求的处理时间超过多少则自如将请求设置为超时 默认90秒
      //}
      //"FileCacheOptions": {
      //  "TtlSeconds": 15,
      //  "Region": "UserCache" //可以调用Api清理
      //}
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://127.0.0.1:6299", //网关对外地址
    "ServiceDiscoveryProvider": {
      "Host": "127.0.0.1",
      "Port": 8500,
      "Type": "Consul" //由Consul提供服务发现
    },
    "RateLimitOptions": {
      "QuotaExceededMessage": "Too many requests, maybe later? 11", // 当请求过载被截断时返回的消息
      "HttpStatusCode": 666, // 当请求过载被截断时返回的http status
      //"ClientIdHeader": "client_id" // 用来识别客户端的请求头,默认是 ClientId
    }
  }
}