限流
微服务为了保证高可用常用的几个手段:限流,降级,缓存和熔断等,这里讲一下几种限流方案。限流可以保证使用有限的资源提供最大化的服务能力,按照预期流量提供服务,超过的部分将会拒绝服务、排队或等待、降级等处理。限流的类库有很多,不同语言的有不同的类库,如大Java的有concurrency-limits、Sentinel、Guava 等
1、计数器
固定窗口计数器
计数限流是最为简单的限流算法,日常开发中,我们说的限流很多都是说固定窗口计数限流算法,比如某一个接口或服务1s最多只能接收1000个请求,那么我们就会设置其限流为1000QPS。该算法的实现思路非常简单,维护一个固定单位时间内的计数器,如果检测到单位时间已经过去就重置计数器为零。
固定窗口计数器实现简单,但是无法应对突发流量,而且无法严格保证某个时间段下限流,因为时间窗口是固定的,
比如固定时间窗口1s限流阈值为100,但是前100ms,已经请求来了99个,那么后续的900ms只能通过一个了,就是一个缺陷,基本上没有应对突发流量的能力。第二个缺陷,在00:00:00这个时间窗口的后500ms,请求通过了100个,在00:00:01这个时间窗口的前500ms还有100个请求通过,对于服务来说相当于1秒内请求量达到了限流阈值的2倍。
滑动窗口计数器
滑动时间窗口算法是对固定时间窗口算法的一种改进,这词被大众所知实在TCP的流量控制中。固定窗口计数器可以说是滑动窗口计数器的一种特例,滑动窗口的操作步骤:
- 将单位时间划分为多个区间,一般都是均分为多个小的时间段;
- 每一个区间内都有一个计数器,有一个请求落在该区间内,则该区间内的计数器就会加一;
- 每过一个时间段,时间窗口就会往右滑动一格,抛弃最老的一个区间,并纳入新的一个区间;
- 计算整个时间窗口内的请求总数时会累加所有的时间片段内的计数器,计数总和超过了限制数量,则本窗口内所有的请求都被丢弃。
时间窗口划分的越细,并且按照时间"滑动",这种算法避免了固定窗口计数器出现的上述两个问题。缺点是时间区间的精度越高,算法所需的空间容量就越大。
常见的实现方式主要有基于redis zset的方式和循环队列实现。基于redis zset可将Key为限流标识ID,Value保持唯一,可以用UUID生成,Score 也记为同一时间戳,最好是纳秒级的。使用redis提供的 ZADD、EXPIRE、ZCOUNT 和 zremrangebyscore 来实现,并同时注意开启 Pipeline 来尽可能提升性能。实现很简单,但是缺点就是zset的数据结构会越来越大。
2、漏桶算法
漏桶算法是水先进入到漏桶里,漏桶再以一定的速率出水,当流入水的数量大于流出水时,多余的水直接溢出。把水换成请求来看,漏桶相当于服务器队列,但请求量大于限流阈值时,多出来的请求就会被拒绝服务。漏桶算法使用队列实现,可以以固定的速率控制流量的访问速度,可以做到流量的“平整化”处理。
大家可以通过网上最流行的一张图来理解。
[图片上传失败...(image-d37d6b-1611819221355)]
漏桶算法原理
漏桶算法实现步骤:
- 将每个请求放入固定大小的队列进行存储;
- 队列以固定速率向外流出请求,如果队列为空则停止流出;
- 如队列满了则多余的请求会被直接拒绝·
漏桶算法有一个明显的缺陷:当短时间内有大量的突发请求时,即使服务器负载不高,每个请求也都得在队列中等待一段时间才能被响应。
3、令牌桶算法
令牌桶算法的原理是系统会以一个恒定的速率往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。从原理上看,令牌桶算法和漏桶算法是相反的,前者为“进”,后者为“出”。
漏桶算法与令牌桶算法除了“方向”上的不同还有一个更加主要的区别:令牌桶算法限制的是平均流入速率(允许突发请求,只要有足够的令牌,支持一次拿多个令牌),并允许一定程度突发流量;
令牌桶算法的实现步骤:
- 令牌以固定速率生成并放入到令牌桶中;
- 如果令牌桶满了则多余的令牌会直接丢弃,当请求到达时,会尝试从令牌桶中取令牌,取到了令牌的请求可以执行;
- 如果桶空了,则拒绝该请求。
四种策略该如何选择?
- 固定窗口:实现简单,但是过于粗暴,除非情况紧急,为了能快速止损眼前的问题可以作为临时应急的方案。
- 滑动窗口:限流算法简单易实现,可以应对有少量突增流量场景。
- 漏桶:对于流量绝对均匀有很强的要求,资源的利用率上不是极致,但其宽进严出模式,保护系统的同时还留有部分余量,是一个通用性方案。
- 令牌桶:系统经常有突增流量,并尽可能的压榨服务的性能
转自 https://www.jianshu.com/p/d62fb7a6fee1
秒杀系统
a、CDN:静态数据缓存
b、缓存:上层抗住流量
c、限流:防止应用挂掉
d、答题验证码:削峰
e、MQ:异步/削峰/解耦
f、风控、接口幂等:防刷
g、分库分表:减轻 DB 压力