zoukankan      html  css  js  c++  java
  • Ocelot(五)- 流量限制、服务质量

    Ocelot(五)- 流量限制、服务质量

    作者:markjiang7m2
    原文地址:https://www.cnblogs.com/markjiang7m2/p/10965300.html
    源码地址:https://gitee.com/Sevenm2/OcelotDemo

    本文是我关于Ocelot系列文章的第五篇,流量限制、服务质量。Ocelot允许针对具体的服务接口进行流量限制,以便下游服务不会过载而影响响应速度。服务质量则是Ocelot根据下游服务响应的结果做出判断,当超过一定次数的响应失败时,Ocelot认为该服务不可用,自动产生熔断,在一定的时间范围内不再向该服务转发请求,同时Ocelot也支持自定义的请求超时时间,当下游响应超过设定的时间,会认为该服务响应失败。

    关于更多的Ocelot功能介绍,可以查看我的系列文章

    本文中涉及案例的完整代码都可以从我的代码仓库进行下载。

    案例六 流量限制

    Ocelot支持流量限制,只要在路由中添加RateLimitOptions配置即可

    "RateLimitOptions": {
        "ClientWhiteList": [
            "markadmin"
        ],
        "EnableRateLimiting": true,
        "Period": "1m",
        "PeriodTimespan": 30,
        "Limit": 5
    }
    
    • ClientWhiteList:数组,在请求头中包含ClientId=xxx的请求不受限流控制,其中ClientId这个key可以修改,xxx表示配置的白名单。
    • EnableRateLimiting:是否启用限流
    • Period:限流控制的时间周期,输入单位支持s(秒), m(分), h(时), d(天)
    • PeriodTimespan:恢复等待时间,当访问超过限流限制的次数后,需要等待的时间,单位为s,如当一分钟内访问超过5次,就需要等待30秒后,访问才会重新有效
    • Limit:一个时间周期内允许访问的最大次数。

    下面来看案例,在ReRoutes中添加一组路由

    {
        "DownstreamPathTemplate": "/api/ocelot/{postId}",
        "DownstreamScheme": "http",
        "DownstreamHostAndPorts": [
        {
            "Host": "localhost",
            "Port": 8001
        }
        ],
        "UpstreamPathTemplate": "/ocelot/ratelimit/{postId}",
        "UpstreamHttpMethod": [ "Get" ],
        "Priority": 2,
        "RateLimitOptions": {
        "ClientWhiteList": [
            "markadmin"
        ],
        "EnableRateLimiting": true,
        "Period": "1m",
        "PeriodTimespan": 30,
        "Limit": 5
        }
    }
    

    在这里我只是添加多了一组路由,但下游服务接口是重用了之前使用过的接口,流量限制部分配置上面已经介绍过了。下面运行来看结果。

    当我第一次访问http://localhost:4727/ocelot/ratelimit/5的时候,得到了正常的返回结果

    Ocelot_043_ratelimit_request1

    而且,在请求头可以看到流量限制的相关信息

    Ocelot_047_ratelimit_request1header

    然后,我又很快地继续发出请求,可以看到,当我第六次发出请求的时候,得到了429 To Many Requests的状态

    Ocelot_044_ratelimit_request6

    而此时的请求头信息也会不一样,这里可以看到Retry-After →28,意思是在28秒后可以恢复请求

    Ocelot_048_ratelimit_request6header

    这证明,我们的Ocelot网关流量限制的作用起效了,而且与我们的配置一致。
    在等待30秒之后,我重新发出请求,又得到了正常的返回结果

    Ocelot_045_ratelimit_request7

    当我在请求头中加上[ClientId]=markadmin后,清空Postman的请求记录,重新开始发出请求,无论请求多少次,Ocelot也不会对我的访问进行限流

    Ocelot_046_ratelimit_nolimit

    这里对于PeriodTimespan(恢复等待时间)的算法,我倒是有点疑问的。我一开始的理解是,基于上面案例的配置,当一分钟内访问超过5次时,就需要等待Period + PeriodTimespan,也就是从第一个有效请求开始算起,一分半钟之后Ocelot才会重新正常转发请求,但是我做了几次重复实验,得到的结果都是:当一分钟内访问到第1次时,Ocelot开始进入PeriodTimespan时间内的倒计时,也就是实际的重置时间为PeriodTimespan

    为了更加明确地验证这个问题,我使用OcelotConsole项目进行测试。
    首先,修改路由配置如下:

    {
        "DownstreamPathTemplate": "/api/ocelot/{postId}",
        "DownstreamScheme": "http",
        "DownstreamHostAndPorts": [
        {
            "Host": "localhost",
            "Port": 8001
        }
        ],
        "UpstreamPathTemplate": "/ocelot/ratelimit/{postId}",
        "UpstreamHttpMethod": [ "Get" ],
        "Priority": 2,
        "RateLimitOptions": {
        "ClientWhiteList": [
            "markadmin"
        ],
        "EnableRateLimiting": true,
        "Period": "1m",
        "PeriodTimespan": 10,
        "Limit": 5
        }
    }
    

    然后,在OcelotConsole项目中添加代码如下:

    public static async Task Main(string[] args)
    {
        using (var client = new HttpClient())
        {
            for (var i = 0; i < 100; i++)
            {
                Console.WriteLine(DateTime.Now);
    
                var result = await client.GetAsync("http://localhost:4727/ocelot/ratelimit/5");
                Console.WriteLine($"{result.StatusCode}, {result.Content.ReadAsStringAsync().Result}");
                System.Threading.Thread.Sleep(1000);
            }
            Console.Read();
        }
    }
    

    每隔1s就发出一次请求,运行,在命令窗口得到以下输出:

    2019/6/3 13:33:31
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:32
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:33
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:34
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:35
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:36
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:37
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:38
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:39
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:40
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:41
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:43
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:44
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:45
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:46
    OK, This is from localhost:8001, path: /api/ocelot/5
    2019/6/3 13:33:47
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:48
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:49
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:50
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    2019/6/3 13:33:51
    TooManyRequests, API calls quota exceeded! maximum admitted 5 per 1m.
    

    然后,我又通过修改参数,得出如下结果:

    • PeriodTimespan=10, Limit=5:5个成功,5个失败
    • PeriodTimespan=10, Limit=6:6个成功,4个失败
    • PeriodTimespan=20, Limit=5:5个成功,15个失败
    • PeriodTimespan=30, Limit=5:5个成功,25个失败

    似乎都是与我前面得到的结论相同,与官方文档不一致。
    我在GitHub上提了一个issue:https://github.com/ThreeMammals/Ocelot/issues/910,期待能得到答复。

    流量限制的全局配置

    "RateLimitOptions": {
        "DisableRateLimitHeaders": true,
        "QuotaExceededMessage": "Customize Tips!",
        "HttpStatusCode": 999,
        "ClientIdHeader": "Test"
    }
    
    • DisableRateLimitHeaders:当设为true时,请求头中就不会输出流量限制的相关信息,默认值:"false"
    • QuotaExceededMessage:当请求数量超出流量限制时,输出的信息,默认值:"API calls quota exceeded! maximum admitted {Limit} per {Period}."
    • HttpStatusCode:当请求数量超出流量限制时,输出的状态码,默认值:"429"
    • ClientIdHeader:标识为白名单中的客户端的请求头key,默认值:"ClientId"

    Ocelot_049_ratelimit_request1noheader

    Ocelot_050_ratelimit_request6status

    Ocelot_051_ratelimit_whitelist

    案例七 服务质量

    Ocelot支持服务质量与熔断,意味着当下游服务不可用时,Ocelot会进行自动熔断,不再将请求转发给该下游服务。来看看配置

    "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking":3,
        "DurationOfBreak":3000,
        "TimeoutValue":5000
    }
    
    • ExceptionsAllowedBeforeBreaking:允许异常次数,当Ocelot转发给该下游服务连续出现异常次数达到该数字时,Ocelot会进行自动熔断,一段时间内不再向该下游服务转发请求
    • DurationOfBreak:熔断时间,单位为ms(毫秒),持续多长时间不向该下游服务转发请求
    • TimeoutValue:服务质量配置项,超时时间,单位为ms(毫秒),当Ocelot向下游服务转发请求多长时间后,自动认为该请求超时

    ExceptionsAllowedBeforeBreaking 必须跟 DurationOfBreak一起使用,TimeoutValue可以单独使用。

    首先需要安装Polly支持程序,通过Nuget搜索Ocelot.Provider.Polly或者通过以下命令安装

    Install-Package Ocelot.Provider.Polly
    

    然后在Startup.cs中的ConfigureServices方法注册该中间件

    using Ocelot.Provider.Polly;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ……
        services.AddOcelot()
            .AddPolly();
        ……
    }
    

    ReRoutes中添加一组路由

    {
        "DownstreamPathTemplate": "/api/ocelot/{postId}",
        "DownstreamScheme": "http",
        "DownstreamHostAndPorts": [
        {
            "Host": "localhost",
            "Port": 8001
        }
        ],
        "UpstreamPathTemplate": "/ocelot/qos/{postId}",
        "UpstreamHttpMethod": [ "Get" ],
        "Priority": 2,
        "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 3000,
        "TimeoutValue": 5000
        }
    }
    

    为了看出熔断效果,我将8001端口的下游服务停止了,然后运行OcelotDemo项目

    当第一次向网关发出请求时,得到500的状态码

    Ocelot_052_qos_500

    连续3次请求过后,就会得到503的状态码,证明Ocelot已经产生熔断

    Ocelot_053_qos_503

    总结

    在这篇文章中就跟大家介绍了Ocelot的两个基础功能,在路由中进行配置即可使用,不需要依赖于第三方的服务。当然在我实践的过程中产生的一个疑问暂时还没得到答案,如果有知道原因的朋友也可以给我留言,感激不尽。
    结合前面的几篇文章,大家在设计项目API网关的时候就可以综合地考虑到底哪些功能应该配置使用,如何适当地建立路由表。例外,我在这几个案例中为了突出要介绍的功能,基本上都是一组路由单独配置一个功能,而在实际项目中通常都是需要在一组路由当中同时配置多个功能的,希望大家在实际项目中能够灵活运用。今天就先跟大家介绍到这里,希望大家能持续关注我们。

  • 相关阅读:
    Azure PowerShell (2) 修改Azure订阅名称
    Windows Azure Platform Introduction (11) 了解Org ID、Windows Azure订阅、账户
    Azure PowerShell (3) 上传证书
    Azure PowerShell (1) PowerShell入门
    Windows Azure Service Bus (2) 队列(Queue)入门
    Windows Azure Service Bus (1) 基础
    Windows Azure Cloud Service (10) Role的生命周期
    Windows Azure Cloud Service (36) 在Azure Cloud Service配置SSL证书
    Android studio 使用心得(一)—android studio快速掌握快捷键
    android 签名、混淆打包
  • 原文地址:https://www.cnblogs.com/markjiang7m2/p/10965300.html
Copyright © 2011-2022 走看看