限流设计-Throttle
限流设计-Throttle
含义:
进行流量控制,以保护系统不会在过载的情况下出现问题。
场景:
数据库访问的连接池;线程池;Nginx 并发连接限制 limit_conn 模块,每秒平均速率限制 limit_req 模块;MQ 的生产速
策略:
限流的目的是通过对并发访问进行限速。
相关的策略一般是,一旦达到限制的速率,那么就会触发相应的限流行为。
触发条件:
拒绝服务:拒绝恶意、高并发请求
服务降级:后端服务、功能做降级
特权请求:在多租户内将有限资源分配给重要租户
延迟处理:使用队列缓冲、削峰
弹性伸缩:自动伸缩无状态服务 实现方式:
计数器: 维护一个计数器 Counter,当一个请求来时,就做加一操作,当一个请求处理完后就做减一操作。如果这个 Counter 大于某个数了(我们设定的限流阈值),那么就开始拒绝请求以保护系统的负载了。
队列: 普通队列:流速波动,处理速度固定,类似FIFO

优先队列: 先处理高优先级,再处理低优先级。缺点:低优先级可能会饿死

带时间片的权重队列:分配不同的处理时间到不同的队列。即优先队列加上时间片概念。

队列算法的缺点:队列长度难以控制。长度需要跟系统的吞吐挂钩。一旦队列过长,整个服务可能提前挂掉。这类模型建议使用pull方式,而不是push。
漏斗: 漏斗算法其实就是在队列请求中加上一个限流器,来让 Processor 以一个均匀的速度处理请求。
当请求过多时,队列就会开始积压请求,如果队列满了,就会开拒绝请求。e.g TCP滑动窗口

令牌桶: 有一个中间人。在一个桶内按照一定的速率放入一些 token。处理程序要处理请求时,需要拿到 token,才能处理;如果拿不到,则不处理。
在processor处理能力不受限制的情况下,漏斗算法会以一个稳定的速度转发;而令牌桶算法平时流量不大时在“攒钱”,流量大时,可以一次发出队列里有的请求,而后就受到令牌桶的流控限制。

基于响应时间的动态限流 上述算法都需要做相应的性能测试,找到系统最大的性能值。
现状:各依赖的处理能力不同;各api的性能差异较大;各集群性能不一样。所以限流阈值无法做成固定值。
实现: 通过P90或P99动态指标来限流。当P90 或 P99 超过我们设定的阈值,那么我们就自动限流。
e.g. TCP 协议的拥塞控制的算法。TCP 使用 RTT - Round Trip Time 来探测网络的延时和性能,设定“滑动窗口”的大小,从而使发送的速率和网络的性能相匹配。https://coolshell.cn/articles/11609.html
实现难点:
样本量太大。1.采样 2. 蓄水池近似算法
模拟阻尼运动,控制流速。将整个限流的流量会在一个值上下做小幅振动。这么做的目的是,如果后端扩容伸缩后性能变好,系统会自动适应后端的最大性能。
限流设计目的:
向用户承诺SLA
阻止多租户的某个用户将资源耗尽
应对突发流量
节约成本,将异常的峰值进行限流,而不是扩容。 限流设计要点:
限流设计要早。当架构形成后,限流不是很容易加入。
限流模块性能要好。而且对流量的变化也是非常灵敏的,否则太过迟钝的限流,系统早因为过载而挂掉了。
限流可通过开关手动操作,这样在应急的时候,可以手动操作。
限流时要可感知,协调各个系统: 通过监控事件通知责任人。让我们知道有限流事件发生,这样,运维人员可以及时跟进。而且还可以自动化触发扩容或降级,以缓解系统压力。
通过特定的限流错误码通知客户端,当前限流,请求被拒。以区分其他错误。客户端触发本地买入机制,可以调整发送速度,或是走重试机制。
通过协议头中加标识的方式通知后端服务。e.g. HTTP Header 中,放入一个限流的级别,告诉后端服务目前正在限流中。这样,后端服务可以根据这个标识决定是否做降级。