服务限流

背景

限流存在于高可用服务中。
用于高可用的保护手段,主要包括:缓存,降级,限流
限流:只允许指定的事件进入系统,超过的部分将被拒绝服务,排队或者降级处理。
为什么需要限流:
一:服务扛不住压力了
二:因为资源的稀缺或者处于安全防范的目的而采用的自我保护机制,保证有限的资源提供最大的服务能力,按照预期的流量提供服务 ,超过的部分将会拒绝服务,排队或者降级处理

http

http RFC协议中提供了 429的错误码用于服务端返回给客户端,以应答超过资源响应的格式

字段

Retry-After:用于告诉客户端多久后进行访问;
X-Rate-Limit-Limit:同一个时间段所允许的请求的最大数目
X-Rate-Limit-Remaining:当前时间段内剩余的请求数量
X-Rate-Limie-Reset:为了得到最大请求数所等待的秒数??

限流的分类

限流必须是可以被量化,被度量,可以被观察出,可以被统计出来的东西


细分领域

按照粒度

单机 + 分布式
单机限流:通常指的是在分布式节点下的某个服务的限流,各服务节点采用不同的限流保护措施


单机限流

分布式限流:在接入层实现多节点的合并限流,比如利用nginx和redis,分布式网关等(需整理后续要链接)

分布式限流

分布式限流需要中心化存储,常见使用redis实现,引入了中心化存储,需要解决一些问题
以下理论要详细整理
一:数据一致性
理解:理论存在的任意时间,任意组件的数据都是完全一致得,根据cap也不可以实现,只是达到线性一致(理想的模式)
二:时间一致性
各个服务器的时间要达到一致性,如果服务器时间有异常,会对时间窗口敏感的算法造成误差
三:超时
由于网络抖动,或者redis(分布式限流的中间件压力过大响应变慢),超时阈值设置不合理,是否需要放行流量还是拒绝流量
四:性能及可靠性
redis等分布式限流中间件的资源有限,如果是单点限流服务,出现性能上限,分布式限流如何退换成单机限流模式

按照对象分类

基于请求限流+基于资源限流

基于请求限流:实现方式为限制总量+限制QPS
限制总量:如抢红包
限制qps:常用,定义接口的阈值,每秒承担多少的QPS(重点:如何计算接口的QPS

基于资源:需要定位服务的cpu,内存等使用情况 ,比如限制tcp链接数,线程数,内存使用情况。通过限制资源我感觉更能及时反馈服务的状态,提供更快的服务,但是阈值不好判断,需要不停修改

按照限流算法的分类

限流无论是按照什么维度,底层实现一定是相应的算法

1.计数器(固定窗口计数器)

通用及最简单的算法,简单逻辑是维护一个固定时间的计数器,如果检测到单位时间过去则记为0,重新计数

固定窗口

简单讲:计算器超过了限流的阈值,停止服务,等带下一个窗口,计数为0重新提供服务
存在的问题
1.没有应对突发的流量的能力:如100的qps,前100ms来了99个,后900ms只能处理一个
2.不准确,在一个窗口内后半段时间来了100个请求,以及在后一个窗口的前半段时间100个请求,等同于在一个窗口内出现了双倍的限流的流量!

计数器(滑动窗口计数器)

类似于tcp的滑动窗口,
1.将单位时间划分为多个区间,一般均分为多个小时间段
2.每一个区间都有一个计数器,有一个请求则该区间的请求就会就+1
3。每过一段时间,时间窗口向前移动,,抛弃最老的区间,纳入新的一个区间
4.计算阈值的时候,需要判断,整个滑动窗口所有个区间,的数量/时间,超过阈值,进行限流
好处解决了固定窗口的不稳定及突发情况,坏处,如果区间划分很细很小时间段很小,需要较大的内存空间进行数据统计
实现方式:使用redis的zset和循环队列实现,将key作为标志id,value作为uuid唯一值,score作为时间戳,利用zdd,expire,zcount,zremember实现,启用pipeline提高性能重点!!需要代码实现,整理出链接

漏铜算法

没记牢固面试挂过+令牌桶


网图

如何理解,
水:请求
桶:限流阈值大小
漏的水滴:固定速率,服务的处理速度
实现步骤:
1.将每个请求放入固定的大小的队列进行存储
2.以固定的速率向外流出请求,队列为空则停止流出
3.队列满了则拒绝服务
实现代码链接需要整理
缺陷
短时间内有大量的突发请求,及时服务器的负载不高,每个请求也都得在队列中等待一段时间才能得到处理

令牌桶算法

网图

以一个恒定的速率向桶中加令牌,而如果请求需要被处理,则先从桶中获取一个令牌,没有令牌则拒绝服务,(与漏桶区别,一个是请求进桶,一个是那令牌出桶)
令牌桶支持突发流量
因为桶中有多少令牌在等待,就允许有多少突发请求可以执行

实现步骤:
1.以恒定的速率向桶中增加令牌
2.如果令牌满了直接丢弃,如果有请求则获取令牌进行请求
3.如果桶空了,则拒绝执行

四种策略的选择

1.固定窗口:解决燃煤之急
2.滑动窗口:实现简单,少量的突发情况
3.通用性方案,对于流量的均匀有很强的的要求
4令牌:经常性的突发

限流怎么确定阈值

1.设置一个小的阈值慢慢变大:不合理,需要反复修改
2.压测接口,接口的单压不能反馈整个系统的性能,
3.压测+监控数据,但是存在系统性能拐点未知,单纯的预测无法定位真实场景

名言:在具有复杂依赖关系的系统中,对特定服务的进行过载控制可能对整个系统有害或者服务的实现有缺陷。

做限流阈值需要系统关注以下几点:
1.系统运行指标:cpu,内存,线程数,网络连接数
2.资源之间的调用关系,服务之间的强弱依赖
3.控制方法,对限流后的请求,采用何种方式(直接拒绝,快速失败or 排队等待等)

最后java实现的限流类库

作者说用很多种,都没用过
1.concurrency-limits
2.Sentinel
3.Guava
(**需整理,代码及对象的实现逻辑连接)

你可能感兴趣的:(服务限流)