为什么要限流日常生活中,哪些地方需要限流?比如我旁边有个国家级风景名胜区。平时去的人可能不多,一到五一或者春节,就人满为患了。此时,景区管理人员将实施一系列限制人流的政策。为什么要限流?如果景区能容纳10000人,现在进了30000人,人山人海,搞不好会出事故。结果就是大家的体验都会不好。如果发生意外,景区可能不得不关闭,导致无法对外开放,而这样的后果就是大家觉得体验很糟糕。限流的思路是在保证可用性的情况下,尽可能增加进入的人数,剩下的人在外面排队等候,保证里面的一万人可以正常玩。回到互联网,也是如此。比如某明星公布恋情后,访问量从平时的50万增加到500万。系统最多可以支持200万次访问,所以一定要实现限流规则,保证是可用状态,以免服务器崩溃,所有请求都不可用。限流的思路对系统服务进行限流,一般有以下几种方式:熔断系统在设计之初就考虑了熔断措施。当系统出现问题时,如果短时间内无法修复,系统必须自动做出判断,打开熔断开关,拒绝流量访问,避免大流量请求导致后台过载。系统还应该能够动态监控后端程序的修复状态。当程序恢复稳定后,可以关闭熔断器开关,恢复正常服务。常见的熔断器组件有Hystrix和阿里的Sentinel,两者各有优缺点,可根据业务实际情况选择。服务降级对系统的所有功能服务进行分类。当系统出现问题,需要紧急限流时,可以将不太重要的功能降级,停止服务,为核心功能释放更多资源。.比如在电商平台,如果流量突然暴增,可以暂时降级商品评论、积分等非核心功能,停止这些服务,释放机器、CPU等资源确保用户可以正常下单。这些降级后的功能服务可以等待整个系统恢复正常,然后启动它进行补货/补偿处理。除了功能降级之外,还可以采用不直接操作数据库,而是全部读取缓存和写入缓存的方式作为临时降级方案。延迟处理的模式需要在系统前端建立一个流量缓冲池,将所有请求缓冲到这个池中,而不是立即处理。然后后端真正的业务处理程序从这个池中获取请求并顺序处理。通常,可以使用队列模式来实现它们。这相当于使用了异步的方式来减轻后端的处理压力,但是当流量较大时,后端的处理能力是有限的,缓冲池中的请求可能无法及时处理,就会出现得到一定程度的延迟。下面具体的漏桶算法和令牌桶算法就是这个思路。这种权限处理方式需要对用户进行分类。通过预设的分类,让系统优先处理对安全性要求高的用户群,其他用户群的请求将被延迟或直接不处理。缓存、降级、限流的区别缓存用于提高系统吞吐量,提高访问速度,提供高并发。降级是指当系统部分服务组件不可用、流量激增、资源枯竭等情况下,暂时屏蔽掉掉问题的服务,继续提供降级后的服务,尽可能给予用户友好提醒,并返回自下而上的数据。它将影响整个业务流程。问题解决后,服务将重新启动。限流是指使用缓存和降级无效的场景。例如,当达到阈值时,限制接口调用频率、访问次数、库存数量等,在服务不可用之前提前降级服务。只服务好部分用户。限流算法限流算法有很多,常见的有三种,分别是计数器算法、漏桶算法和令牌桶算法,下面会一一说明。计数器算法简单粗暴,比如指定线程池大小,指定数据库连接池大小,Nginx连接数等,都属于计数器算法。计数器算法是限流算法中最简单易行的算法。举个例子,比如我们规定对于A接口,一分钟的访问次数不能超过100次。那么我们可以这样做:一开始我们可以设置一个counter计数器,每有一个请求过来,计数器会加1,如果计数器的值大于100且请求与第一次请求的间隔还在1分钟以内,说明请求过多,拒绝访问;如果请求和第一次请求的间隔大于1分钟,并且计数器的值还在限流范围内,那么重新设置计数器,就这样简单粗暴。漏桶算法漏桶算法的思想很简单。水(请求)先进入漏桶,漏桶以一定的速度放水。当进水速度过大,超过水桶所能容纳的容量时,直接溢出。可以看出,漏桶算法可以对数据传输速率施加限制。这样做的好处是:调峰:当大量流量进入时,会发生溢出,这样限流保护服务可以使用缓冲:不会直接向服务器请求,缓冲压力令牌桶算法与令牌桶类似toleakybucket,但不同的是一些token放在tokenbucket中。服务请求到达后,只有获取token后才会获取服务。比如我们平时去食堂吃饭的时候,一般都是在食堂的窗前排队。这就像是一个漏桶算法。大量人群聚集在食堂窗外,以一定的速度享受服务。如果进来的人太多,食堂装不下,可能会有人站在食堂外面。享受食堂的服务就叫溢出,溢出可以继续请求,也就是继续排队,那这有什么问题呢?如果这个时候有特殊情况,比如有些志愿比较匆忙,或者高三高考,这种情况属于紧急情况。如果我们也使用漏桶算法,我们就得慢慢排队,这并不能解决我们的问题。需求,对于很多应用场景,除了限制平均数据传输速率外,还需要允许一定程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更合适。如图所示,令牌桶算法的原理是系统会以恒定的速度往桶中放入令牌,如果需要处理请求,需要先从桶中取出一个令牌,当有桶中没有令牌当卡可用时,服务被拒绝。令牌桶的好处是,如果访问量激增或者某个时刻出现紧急情况,可以通过改变桶中令牌的数量来改变连接数,就像排队等候的问题在食堂吃饭。如果现在不直接去窗口排队,而是先到楼外拿饭票再去排队,所以有高三的时候可以增加饭票的数量或者先给高中生代币,比漏桶算法灵活多了。并发限流简单来说就是设置系统的QPS阈值总数。这些很常见。以Tomcat为例,很多参数都是基于这个考虑。比如配置的acceptCount设置响应连接数,maxConnections设置瞬时最大连接数,maxThreads设置最大线程数,在各个框架或者组件中,并发限制在以下几个方面:限制总线程数并发数(如数据库连接池、线程池)限制瞬时并发数(Nginx的limit_conn模块,用于限制瞬时并发连接数)限制时间窗口内的平均速率(如Guava的RateLimiter、Nginx的limit_req模块,限制每秒平均速率)其他包括限制远程接口调用速率和限制MQ的消费速率。此外,还可以根据网络连接数、网络流量、CPU或内存负载等限制流量。有了并发限流,就意味着在处理高并发的时候多了一个保护机制,不用担心瞬时流量导致系统挂掉或者雪崩,最终损坏服务而不是没有服务;但是限流需要评估好,不能乱用,否则在一些正常的流量中会出现一些奇怪的问题,导致用户体验不好,造成用户流失。接口限流接口限流分为两部分,一是限制一段时间内的接口调用次数,参考前面限流算法的计数器算法,二是设置滑动时间窗算法.接口总数控制一定时间内调用的接口总数。可以参考前面的计数器算法,这里不再赘述。接口timewindow固定时间窗算法(也就是上面说的counter算法)的问题是统计区间太大,限流不够准确,和之前统计区间的关系和影响不大在第二个统计区间考虑(第一个区间后半段+第二个区间前半段也是一分钟)。为了解决我们上面提到的关键问题,我们尝试将每个统计区间划分为更小的统计区间和更准确的统计计数。上面的例子,假设QPS可以接受100个查询/秒,第一分钟前40秒访问量很低,后面20秒突然增加,持续一段时间,并没有直到第二分钟第40秒开始下降,按照之前的统计方式,前一秒的QPS是94,下一秒的QPS是92,所以没有超过设定的参数,但是!但是在中间区域,QPS达到了142,明显超过了我们允许的服务请求数,所以固定窗口计数器不可靠,需要滑动窗口计数器。计数器算法其实是固定窗口算法,只是没有进一步划分时间窗口,所以只有一个格子;可以看出,当滑动窗口的网格划分得越多,即秒级精确到毫秒或纳秒,那么滑动窗口的滚动越平滑,限流统计就越准确。需要注意的是,占用的空间越大。这部分限流实现是限流的具体实现。简单的说,毕竟没人愿意看长代码。Guava实现导入包:
