互联网网关设计之限流算法

腾讯王卡业务第一代网关设计架构如上图所示,也许有许多人会问,nginx本身就能做网关了,为什么还需要另外开发网关呢?

答案是nginx开发网关,在线现有成员技术背景下,条件不成熟,为了快速构建我们的微服务架构,所以我们选择了基于spring cloud zuul做网关开发,这样技术栈单一,小团队比较合适,运维维护成本较低。

网关能给我们带来的好处如下:

  • 客户端认证
    无论是对内网还是外网的接口都是需要做用户身份认证的,而用户认证在一些规模大点的公司都会有统一的单点登录系统,如果每个微服务系统都是做对接单点登录系统的工作,那么显然比较浪费资源,开发效率低。可以将认证的部分抽取到网关层,然后微服务系统无需关注认证的逻辑只关注自身业务即可。

  • 访问控制
    对一些特定的接口设置白名单,访问次数,访问频率等各类设置。而这些非业务功能的配置以及变更不会影响微服务的实现可以在网关层单独做操作。

  • 负载均衡
    可以灵活的在网关层制定负载均衡策略。

  • 安全
    可以统一在网关层增加一个额外的保护层来防止恶意攻击,如果客户端直连微服务的话,每个暴露的微服务都需要面临安全问题。

       下面我们回到本文的主题“访问控制”

       访问控制中,必谈的就是限流算法了,目前比较流行的算法有“漏桶限流算法”、“令牌桶限流算法”,另外大家很少回去谈及“滑动窗口算法”

       漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:

         可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。

         漏桶本身具有一定容量,生产方的生产速率不受限制,当达到漏桶容量时将拒绝生产,消费方以固定速率消费。例如5r/s

         优点:消费方可以以固定速率消费,因为漏桶消费方限制了速率。
         缺点:缺点也很明显,不能抵抗难于突发流量。

         举例:漏桶允许以200r/s速率消费,如果突发流量为500r/s来袭,导致大量请求堆积或者拒绝。

        令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

        令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

      优点:可以抵抗突发流量。令牌桶中积累一定数量的令牌,消费速率不固定,在一个极小的时间窗口内,可以消费所有的令牌。
      缺点;事物具有两面性,优点极可能就会导致缺点。难于平滑的、以固定的速率消费(比如5r/s),因为消费令牌并没有限速
 
      举例:假如我们的令牌桶容量是500,现有令牌数也是500,我们系统总并发也是500,生产令牌速率是5r/s,假如一次突发的500个请求,他会瞬间消费完所有令牌,后续请求可能是300r/s,200r/s....那么所有请求将被缓存或者拒绝(自己时间策略决定),难于平滑消费。

       通过以上分析,感觉令牌桶算法更合适大家,他可以抵抗突发流量,同时又可以平滑消费(突发流量耗尽后,后面的令牌生产方生产速率是恒定的,这样限制了消费速率也是恒定的)。可是大家有没有发现一个问题,不论是 令牌桶限流 和 漏桶限流都存在一个问题,相连两个时间单位内,流量可能会超过系统承受能力。为什么呢?前一个时间单位的N请求没有完全返回,
后一个时间单位的m个请求又来袭,导致n+m>系统总容量。

       滑动窗口限流

image

在发送方一侧会将要发送的数据组成一个队列,依次发送队列里的数据。队列里面的数据包含几个部分,有已经发送且已经确认的数据、已经发送但未确认的数据、即将发送的数据、现在还不能发送的数据这四个部分,其中的数字标号是数据序列号。上图中提供的窗口即对方通告的窗口大小,可以看出为6个窗口,同时窗口的左边界为3,表明在序列号3及之前的数据已经发送并完成确认,则可以算出窗口的右边界为9。同时我们可以知道有多少已经发送但未收到确认的数据,总共有3个窗口,则发送边界为6,所以最后我们可知可用窗口,即马上能发送的数据序列号范围为7-9。

      随着时间的推移,当我们收到已经发送的数据的ACK时,滑动窗口的左边界就能右移,如果窗口大小未发生改变,那么窗口的右边界也会右移,相当于整个窗口右移。其中在窗口的变化过程中有三个运动状态:

  • 关闭: 窗口左边界右移。发生在收到已发送数据的ACK时。
  • 打开: 窗口右边界右移。发生在接收方已处理接收到的数据,使得接收方缓存变大,会给发送方通告新的变大的窗口值。
  • 收缩: 窗口有边界左移。发生再糊涂窗口中。

      滑动窗口优点:

1:他能抵抗突发流量,

2:他能解决两个相邻时刻瞬时流量超过系统总承载量

 

 作者也玩公众号,欢迎关注《JAVA之庖丁解牛》

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值