某些场景不能用缓存或者降级来解决,比如稀缺资源(秒杀,抢购),写服务(如评论,下单),频繁的复杂查询,需要限流。
常见限流有:限制总并发数,限制瞬时并发数,限制时间窗口内的平均速率,以及限制远程接口调用速率,限制MQ的消费速率等。还可以根据网络连接数,网络流量,CPU或内存负载等来限流。
4.1 限流算法
4.1.1 令牌桶算法
假设限制2r/s,按照500ms固定速率往桶中添加令牌。
桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃或拒绝。
当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上。
如果桶中的令牌不足n个,则不会删除令牌,且该数据包将被限流(要么丢弃,要么在缓冲区等待)
4.1.2 漏桶算法
一个固定容量的漏桶,按照常量固定速率流出水滴。
如果桶是空的,则不需流出水滴。
可以以任意速率流入水滴到漏桶。
如果流入水滴超出了桶的容量,则流入的水滴溢出了(被丢弃),而漏桶容量是不变的。
另外还用计数器来进行限流,主要用来限制总并发数。
4.2 应用级限流
4.2.1 限流总并发/连接/请求数
极限并发/请求数,总有一个TPS/QPS阀值。
Tomcat,Connector其中有如下几个参数:
acceptCount:如果Tomcat线程都忙于响应,新来的请求进入排队,如果超出排队大小,则拒绝连接。
maxConnections:瞬时最大连接数,超出的会排队等待。
maxThreads:用来处理请求的最大线程数,如果请求处理量一直远远大于最大线程数,则会引起响应变慢甚至会僵死。
4.2.2 限流总资源数
使用池化技术来限制总资源数。
4.2.3 限流某个接口的总并发/请求数
如抢购业务,超出限额,要么排队,要么告诉没货了。
4.2.4 限流某个接口的时间窗请求数
时间窗口内(某个接口/每秒,每分钟,每天)请求数。
4.2.5 平滑限流某个接口的请求数
之前的限流不能很好的应对突发请求,令牌桶和漏桶算法可以满足,Guava框架提供令牌桶算法实现。
RateLimiter
4.3 分布式限流
限流服务做成原子化,解决方案使用Redis+Lua或者Nginx+Lua,通过这两种技术实现高并发和高性能。
4.4 接入层限流
接入层目的是负载均衡,非法请求过滤,请求聚合,缓存,降级,限流,A/B测试,服务质量监控等。
Nginx自带两个模块:ngx_http_limit_req_module,ngx_http_limit_conn_module。
4.4.1 ngx_http_limit_conn_module
1.配置示例
limit_conn:最大连接数
limit_conn_zone:共享内存区域大小
limit_conn_status:被限流后返回的状态码
limit_conn_log_level:日志级别,默认error级别
4.4.2 ngx_http_limit_req_module
limit_req:配置限流区域,桶容量,是否延迟模式
limit_req_zone:共享区域大小,固定请求速率。
limit_conn_status:被限流后返回状态码。
limit_conn_log_level:日志级别,默认error级别。
可使用AB测试工具进行测试。
4.5 节流
特定时间窗口内对重复的相同事件最多只处理一次。
4.5.1 throttleFirst/throttleLast
如果有重复的多个相同事件要处理,则只处理第一个或者最后一个。
对于前端开发,可以使用jquery-throttle-debounce-plugin,android开发可以使用RxAndroid实现。
4.5.2 throttleWithTimeout
去抖,连续两个事件先后执行时间不得小于某个时间窗口。
例如搜索关键词自动补全,可以减少频繁的网络请求,避免每输入一个字就导致一次请求。
领取专属 10元无门槛券
私享最新 技术干货