分布式限流系统

限流描述

整个服务集群的资源是有极限的,如果在某一时刻服务集群的访问量超出阈值,系统资源不能支撑超出预期的突发流量时,应当对突发流量进行一些取舍,建立起面对超额流量的自我保护机制,这个机制就是“限流”。
面对限流我们有三个问题:

  1. 依据什么限流?
  2. 具体如何进行限流?
  3. 超额流量如何处理?

流量统计指标

TPS:每秒事务数
HPS:每秒请求数
QPS:每秒查询数
我们对于问题的讨论针对QPS展开

限流方法

流量计数器

这种限流方案就是通过统计任意一秒的QPS,同时保证任意一秒的QPS均低于系统的预设值。假设我们预估系统能够承载的最大流量为100QPS,那么我们在记录时,当计数器的值超过100时,就会进行限流,也就是丢掉超出流量限制的请求。
但是这种统计方式是很不精准的,我们假设从0s开始统计,0-1s时共访问系统80次,当时间来到1时,会将计数器清零,那我们再假设1-2s内仍然有80次的访问,在这两秒内流量控制均不生效。倘若0-1s的流量集中在后半秒而1-2s的流量集中在前半秒,那在1.5-2.5这段时间内,流量高达160QPS却未能出发“限流”。

滑动窗口

滑动窗口是一种改善上述流量统计不准确的方案,通过在时间轴上设置一个长度为1s的窗口大小(从当前时刻向前1s),当检测到这一秒内的流量数超过阈值,就可以触发限流(丢掉)。
滑动窗口可以非常精确的统计QPS,但是它的缺陷在于只能进行否决式限流,对于超出阈值的流量就必须强制失败或降级,很难进行阻塞处理,也就很难对流量曲线进行整形,起不到削峰填谷的作用。
漏桶模式
漏桶算法就是通过一个水池作为缓冲区,当请求来临时,会进入缓冲区,同时,执行者会根据时间戳来判断,是否需要执行下一个请求。
漏桶模式在实现上比较简单,维护一个先进先出的请求队列即可,当队列满时执行拒绝策略。
他的问题在于:如何确定桶的大小和流速。如果设置的不得当,很有可能会杀掉一部分正常请求。
而在实际的应用中,桶的大小和流速往往需要动态的去调整,这对漏桶来说,时难以动态实现的。

令牌桶模式

令牌桶与漏桶极其相似,但思路却恰恰相反,令牌桶时同样需要维护容量为N一个桶,用于保存令牌,同时我们以合适的速度生产令牌。
当有新的请求进入时,倘若桶中拥有令牌,则获取一个,而后进入系统处理数据,倘若没有剩余令牌,执行降级逻辑。
看似需要专门的线程去更新和保存令牌,其实仅需要一个int来说明令牌数,同时在请求到来时,根据时间差和速率计算剩余令牌数即可。
总结
在以上我们介绍了单台机器上的一些限流的思想,接下来我们将讨论针对一个分布式集群的限流方案。

分布式限流方案

误报率

● 引入全局信息会降低误报率

Redis

Redis实现分布式限流方案的主要思路在于,集中存储服务集群中各个服务的状态信息,使这些信息在集群内部共享,在完整掌握整个集群的资源信息后,也就可以利用单机的限流算法进行限流。
但这样的做法缺陷很明显,一个是在限流之前会增加一个Redis的IO操作,同时,如果系统访问量过大,则会导致一个问题,Redis的读写成为了系统瓶颈。
关于Redis读写瓶颈的问题,可以通过服务内部集群做拆分,比如说1、2、3号服务的请求访问Redis1、而4、5、6号服务的请求通过访问Redis2。可以在一定程度上缓解Redis的读写瓶颈。但随之而来的代价是从节点并不能保证时刻都是最新的数据信息。
所有单机算法均可在Redis上进行实现,但是会受限于Redis的单机性能,因此,Redis可用作在低QPS下实现精确的限流操作。

负载均衡器

将业务层需要负责的限流操作让负载均衡器负责,这样业务层可以无感的实现限流操作。同时为了更好的进行动态的限流操作,需要一个元数据管理子系统,用于监听各个服务的状态,动态调整限流配置。
同时,仅需要保证上层负载均衡器是均匀的,就可以在下层实现限流。
限流的效果在一定程度上取决于负载均衡器:
● L4层负载均衡器:仅能在IP层面进行限流,因此不选择该负载均衡器限流
● L7层负载均衡器:可以实现在API层面进行限流
减少误报率的手段:
● 适当扩大阈值,当L4层分配不均时
● 通过规则,自适应调节限流
鲁棒性:
● 控制面采用mysql进行持久化
● 负载均衡服务器保存配置备份
● 设定双TTL缓存机制

分布式token

回头我们考虑令牌桶的限流问题,发现其实是一个生产者消费者问题,生产者通过某种规则分配token到令牌桶中,而消费者在令牌桶中获取token并判断是否命中限流。
单机场景下,生产者可能是一个后台任务也可以是惰性分配策略(基于时间流速的假设)。
分布式场景下,可以是一个中心化的节点zk,redis,mysql,通过计算集群实例个数根据流量分配权重,给不同的节点分配token。
而token是一个抽象化的概念,我们在实践中,将token设置为任务id,当有请求进入服务后,会现在本地检验是否有剩余的任务,如果发现没有任务,服务将执行失败或降级处理。如果请求在服务中获取到相应的任务ID,就可以进行相应的资源请求,获取待标注字段信息。
而对于token的分配,则有一个中心化节点负责,改中心化节点可获取所有机器的状态及配置信息,并根据配置信息向各个服务节点分发任务id。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值