zoukankan      html  css  js  c++  java
  • 服务限流原理及算法

    限流是啥?
    维基百科是这样解释的:
    在计算机网络中,频率限制被应用在控制网络接口收到或发送的请求频次,它可以被用来阻止dos攻击或者是网络爬虫。
    直白点说,就是限制服务收到或发出的请求频次,保证整体服务可以正常健康的使用。
    谈到这里有人会想,只要我服务处理的速度足够快,那么频次高点也没问题,而且我们做的系统不就应该接受各种峰值考验么?
    这么想没问题,提高服务的吞吐量确实是没问题,但是有时出于安全角度考虑,比如爬虫,就不应该让他过快的获取到抓取的数据,还可能涉及到洗钱网络安全什么的。
    另外一方面,需求的开发是有成本的,不应该想当然,在超出系统本来承受打范围后,还有数量级差异的请求进来,这种需求改进的成本无论是人工还是费用都是巨大的。
    因此限流是肯定有存在必要的。下面我们来谈谈经典的限流都有哪些:
    假设我们要实现1分钟,100次的限流:
    1、计数器限流(固定窗口限流)
    这个算法简单实用,基本可以满足很多业务场景的需要
    大致原理是这样的,有一个全局的计数器,初始值为0,每次请求进来,计数器+1,然后再处理,如果计数器超过100,则不再处理请求,直接返回。
    同时我们启动一个定时的线程,每过1分钟,就重置计数器为0;
    流程大概是下边这个样子:

    但是这种计数器限流有一个临界的问题,我们初衷其实上是,任意的一分钟范围内,处理的请求不超过100。
    但是假若第一分钟最后10s处理100个请求,第二分钟最初10s处理100个请求,也就是说20s内,我们共处理了200请求,这显然是不满足最初我们的诉求的。
    2、滑动窗口
    为了解决传统计数器限流的弊端,有人提出了滑动窗口的概念。所谓的滑动窗口,是指不存在固定的起止、结束的时间点。而是当前的时间点向前推动单位周期,判定流量是否超限:(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
    举个例子,比如1min,100次的限流
    我们将时间划分成10s每个单位
    请求如下图,在窗口1期间,请求已经到达60次,因此后两个时间单位内就进入限流状态。

    但是随着时间推移,窗口2期间的请求次数再次小于了100,又可以处理请求。
    继续推移,窗口3的请求次数再次到达100,因此又被限流。

    滑动窗口如何实现呢?
    我们可以使用一个HashMap或者干脆使用一个数组,然后统计每个时间单位内的请求,当判断是否限流时,只要统计时间窗内的请求次数是否满足即可。
    同时map或者是数组我们并不需要无限大,我们可以反复利用其中已经过期的位置。另外滑动窗口的单位时间越小,整体的限流也就会越精准。

    3、漏桶算法
    滑动窗口的结尾我们有说时间单位越小,那么就越精准平滑,可是我们并不能把时间单位搞到无限小,或者说尽可能小的时候就出现偏差,比如1ns,但是可能你刚计算完限流后,已经到下一个时间单位了
    为了解决这种问题,有人提出了漏桶算法。
    如图,这个模型和消息队列有点像:


    请求进来后,会先放置在漏桶中,漏桶最多保存的请求是有限的。当漏桶满了以后,会丢弃请求,否则会添加到漏桶的队尾。
    同时任务处理会恒定的处理漏桶队列中的请求。以此达到平衡。漏桶算法也并不一定需要一个列队,我们也可以使用一个计数器,当请求进来后,计数器+1。计数器满了以后会请求丢弃。同时任务处理完毕后会回调计数器-1;(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )

    4、令牌桶算法
    漏桶算法会让请求更加平滑,但是当有突发请求冲击时,并且我们的下游处理速度又比较快(或者是使用固定频率)来处理,这样我们没有办法很好的控制请求的处理速率。
    如果你设置固定频率,当某个时段请求冲击比较大,而我们也应该满足时,显然无法满足。当放开请求频率,又可能因为下游处理速度太快,对机器的整体性能造成冲击,而且我们又无法控制。
    针对这种情况,有人提供了令牌桶算法:
    如图

    1、有线程会按照固定频率向令牌桶中添加令牌,当令牌桶满了之后,就不会继续添加。
    2、请求来了之后,向令牌桶中请求令牌,成功拿到令牌可以继续处理请求
    3、未请求到令牌,则丢弃该请求

    不知道大家有没有是否记得有一款腾讯的小游戏叫开心消消乐。其中的防沉迷策略就是通过令牌桶的算法处理的。玩家每次玩游戏会消耗一份闪电(令牌),可以连续玩,直到所有闪电都消耗完毕。
    同时随着时间的推移,闪电又会慢慢变满,但是最多不会超过上限(令牌桶满)。在这个增加的过程中,我们也可以同时去玩消消乐消耗令牌

    如果你觉得写的不错,欢迎转载和点赞。 转载时请保留作者署名jilodream/王若伊_恩赐解脱(博客链接:http://www.cnblogs.com/jilodream/

  • 相关阅读:
    js对象数组(JSON) 根据某个共同字段 分组
    一个 函数 用来转化esSearch 的range 条件
    关于 vuex 报错 Do not mutate vuex store state outside mutation handlers.
    android listview 重用view导致的选择混乱问题
    android SDK和ADT的更新
    Android中adb push和adb install的使用区别
    pycharm中添加扩展工具pylint
    su Authentication failure解决
    Putty以及adb网络调试
    有关android源码编译的几个问题
  • 原文地址:https://www.cnblogs.com/jilodream/p/15183193.html
Copyright © 2011-2022 走看看