业务场景
淘宝双十一
如果你在双十一0点0分之后,购物的时候遇到这个页面,那么亲,你被限流了,必须排到等待
用户洪峰
特点:
- 允许访问的速率
- 爆发量
- 爆发间隔时间
为了提升用户体验,需要支持爆发量,所以采用令牌桶算法
允许最大的访问速率:b+r
爆发持续时间:T=b/(m-2r)
爆发量:L=T*r
回调洪峰
特点:
- 有间隔频率
- 每次调用量大
- 允许有延时
采用漏桶算法
限流框架
分成几个主要模块
-
监控模块
收集数据、实时监控和反馈分析
-
决策模块
什么场景使用什么限流方式;比如,用户洪峰采用令牌桶算法,
系统回调使用漏桶算法
-
规则变更模块
动态调整令牌桶容量和产生令牌的速率
-
限流模块
如何处理被限流的请求,是排队还是丢弃
限流框架的处理流程
小米秒杀
TODO
分层架构
Nginx限流
Nginx限流模块
|
|
参数说明
-
$binary_remote_addr
采用二进制表示访问的IP地址
-
zone=login:10m
表示定义了一个名为login的内存共享区,其占用内存大小为10M。
10M的内存可以存放16W个二进制表示的IP地址。
-
rate=1r/s
就是QPS;对同一个IP地址而言,速率被限制为每秒1次请求
-
burst
如果同一个IP访问的请求超过rate后,没有超过桶上限burst的请求会被放入桶中,等待被处理。
这个例子中桶的容量是5。
-
nodelay
单个IP的在某时间段内平均QPS未超过设定的rate,那么桶中的请求会立即被处理,
此时的瞬间QPS高于设定的rate;如果在某时间段内平均的QPS超过rate,那么超过
rate的请求会直接被拒绝,直接返回503
从示例配置信息中可以看出:
对访问/account/login/的请求根据访问的IP进行了限速,QPS是10;
对于同一个IP地址只允许每秒10个请求访问该URL;
如果请求量大于QPS(10),会立即返回503(因为配置了参数nodelay);
如果没有配置参数nodelay,那么超过QPS访问量的请求会先积压到桶中(可以积压5个),
如果桶满了,就返回503。
nginx限流模块默认使用的是漏桶算法,而当配置了nodelay时采用的是令牌算法,此时允许burst请求
重点说明一下对burst+nodelay的理解
|
|
时间点 | 并发请求量 | 拒绝的请求次数 | 成功的请求次数 |
---|---|---|---|
10:00:01 | 15 | 0 | 15 |
10:00:15 | 15 | 0 | 15 |
10:00:30 | 15 | 0 | 15 |
10:00:45 | 15 | 0 | 15 |
11:00:01 | 15 | 0 | 15 |
11:00:02 | 15 | 14 | 1 |
11:00:03 | 15 | 14 | 1 |
11:00:04 | 15 | 14 | 1 |
针对这个case的理解:
(1)在[10:00:01到10:00:45]期间,每隔15秒会有15个并发请求,虽然在这些时间点上并发
请求大于rate,但在每个15秒内其QPS是1,依旧未超过rate,所以每次的15个并发请求能够
被成功处理
(2)在[11:00:01到11:00:05]期间,每秒15个并发请求,在11:00:01时,请求量未超过burst,
并且由于配置了nodelay,所以当时15个请求立即被执行了;而在其他的时间点上QPS大于
rate,所以超出rate的请求直接被拒绝
Nginx+lua
REDIS
http://redis.io/commands/INCR#pattern-rate-limiter
https://github.com/UsedRarely/spring-rate-limit
https://github.com/colley/spring-ratelimiter
https://github.com/nlap/dropwizard-ratelimit
https://github.com/sudohippie/throttle
https://github.com/coveo/spillway
https://github.com/marcosbarbero/spring-cloud-starter-zuul-ratelimit
ZK
HTTP&DUBBO&MQ
filter+
DB
淘宝双十一秒杀业务
秒杀特点:瞬时并发高、数据一致性高、热点更新频率高
大量更新DB中的同一条记录时,会产生锁等待,导致DB性能急剧下降
当大量的并发更新同一条记录时,使用排队的方式来保证高并发下热点记录更新依然能保持
较好的性能,为threads_running设置一个硬上线,当并发超过此值是,拒绝执行sql,
保护MySQL,我们将这个称之为高水位限流,这样就给数据库加上了一层限流的功能,使得
数据库不被瞬间的高爆发请求打爆。
高水位限流实现:
监控系统status变量threads_running,当满足拒绝条件,拒绝执行sql,返回用户:
MySQL Server is too busy,判断逻辑在dispatch_command中,sql解析之后。
增加的系统variables:
1.threads_running_ctl_mode: 限流的sql类型,有两个取值:[ALL | SELECTS],
默认SELECTS,设置为ALL需谨慎。
2.threads_running_high_watermark: 限流水位值,只有threads_running
超过此值才会触发,默认值为max_connections,当set global
threads_running_high_watermark=0时自动设置为max_connections
拒绝必要条件:
1.threads_running超过threads_running_high_watermark
2.threads_running_ctl_mode与sql类型相符
以下情况不拒绝:
1.用户具有super权限
2.sql所在事务已经开启
3.sql为commit/rollback