《深入浅出分布式技术原理》 学习笔记 day8

123 阅读7分钟

大家好,我是砸锅。一个摸鱼八年的后端开发。熟悉 Go、Lua。今天和大家一起学习分布式技术😊

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情

限流

限流的背景

限流和熔断都是用来解决服务过载的问题的,有熔断机制还需要限流的原因:

  1. 熔断的处理方式不够优雅。熔断机制是被动感知故障然后再处理的
  2. 熔断机制是最后的底线。虽然它可以解决雪崩问题,但是它是作为系统稳定性保障的最后一道防线
  3. 在快速失败的时候,需要考虑调用方的重要程度。熔断是调用方根据响应结果自适应触发的,在被调用方出现过载的时候,所有调用方都会受到影响。但是很多时候不同的调用方重要程度不同,有些调用方可以优先保障正常使用
  4. 在多租户的情况下,不能让一个租户的问题影响到其他租户。所以需要对每一个租户分配一定的配额,超过了就对谁进行限流,保证租户之间的隔离性

如何实现限流

限流算法

限流算法是限流机制的基础和核心,最常见的四个限流算法:固定窗口、滑动窗口、漏桶和令牌桶算法

固定窗口和滑动窗口

固定窗口就是定义一个“固定”的统计周期,比如 10 秒、30 秒,然后在每个周期里统计当前周期中被接收到的请求数量,经过计数器累加之后如果超过设定的阈值就触发限流,直到进入下一个周期才把计数器清零,流量接收再恢复正常状态

image.png

例如这个图里的是设置了 2 秒内不能超过 100 次请求,但是流量的进入往往是不均匀的,所以固定窗口有以下问题:

  1. 抗抖动性差。由于流量突然增大,导致流量很可能在一个统计周期的前 10 ms 就达到阈值,该统计周期剩下的时间都会触发限流。虽然可以减小统计周期来改善,但是统计周期变小了也会造成一个小的流量抖动就会引起限流,系统的抗抖动能力变差
  2. 每次统计周期里流量的突增都是不固定的,有可能上一次在最后 10ms,这一次在前 10ms,那么这 20ms 就会出现 200 次调用,不符合设定的 2 秒内不超过 100 次请求的阈值

滑动窗口

滑动窗口就是固定窗口的优化,对固定窗口做了进一步切分,将统计周期的粒度切分更细,比如 1 分钟的固定窗口切分为 60 个 1 秒的滑动窗口,然后统计时间范围随着时间推移同步后移

image.png

但是滑动窗口的统计窗口被切分过细,容易造成系统性能和资源损耗的压力增加。同时滑动窗口和固定窗口一样面临抗抖动性差的问题

漏桶和令牌桶

漏桶

漏桶就像一个漏斗,当访问流量过大漏斗就会积水,流量太多就会溢出

image.png

相对于滑动窗口和固定窗口,漏桶改进了两点:

  1. 增加了一个桶来缓存请求。请求突增的时候可以缓存起来,直到超过桶的容量才触发限流
  2. 对出口的流量上限做了限制,使上游流量的抖动不会扩散到下游服务

但是漏桶也有一定的缺点,超过漏桶流出速率的要求就需要在漏桶中排队等待,而且通常流出速率设置的会相对保守,无法完全利用系统的性能,导致请求排队时间的增加

令牌桶

令牌桶算法的核心是固定“进口”速率,限流器在一个一定容量的桶内按照一定的速率放入 Token,然后处理程序去处理请求的时候需要拿到 Token 才可以处理,如果拿不到就进行限流。当大量流量进入时,只要令牌的生成速度大于等于请求被处理的速度,此时的系统处理能力就是极限的

image.png

漏桶和令牌桶各有优点,令牌桶以恒定的速率生产令牌,请求获取令牌的速率是可变的。而漏桶只要桶非空则以恒定的速率处理请求,但是请求进入桶的速率是可变的 令牌桶虽然提高了系统的资源利用率,但是请求流量突然增大时,上游流量的抖动可能会扩散到下游服务

单节点限流

一般来说,熔断机制作用的位置是客户端,限流机制作用的位置更多是服务端。因为熔断更强调的是自适应,让作用点分散在客户端是没问题的。而限流机制更强调控制,它的作用点在服务端的控制能力更强

触发限流之后,如果可以控制流量产生的速率,则使用阻塞式限流,这种方式既可以实现限流又可以不抛弃请求。如果不能控制流量产生的速率,则使用否决式限流,直接抛弃请求。因为使用阻塞等待会导致请求积压,占用大量系统资源,容易引起雪崩

分布式限流

在分布式场景下,需要对多个服务实例统一进行限流。最容易的一个方案是进行集中式限流,例如借助外部限流器,这种方案带来的问题是:

  1. 限流器会成为系统的性能瓶颈。虽然可以增加负载均衡来分配到多个限流器实例,但是同样也增加了系统复杂性
  2. 限流器的故障会影响所有接入限流器的服务。不过我们可以在限流器故障之后进行降级处理
  3. 增加调用的时延。每一次调用都先通过网络访问一次限流器

另一个方案是将分布式限流进行本地化处理,限流器获得一个服务限额的总阈值之后,按照这个阈值的一定策略分配给服务的实例,每一个实例按照分配的阈值进行单节点限流。这种方案的限流策略是根据统计意义来分配的,精确性可能会出现问题

折中的方案是先本地后外部,先本地设置一个令牌桶算法限流,如果令牌数量不足的时候,再通过网络获取令牌,一次只能获取一批令牌。令牌是通过外部限流器生成的,具体限流是本地处理

如何确定限流的阈值

简单的方案是根据经验设置一个比较保守、满足系统负载要求的阈值,然后在后续使用中慢慢调整。这个方案不好之处是可能我们预测的阈值不够准确,过高则限流不起作用,过低则无法发挥服务的性能

另一个方案是通过压力测试来决定限流的阈值,但是压测的环境很难和线上环境保持一致,特别是涉及缓存和存储的情况,并且单个接口的压测不能反映出正常运行情况系统的情况。全链路压测可以通过流量回放,一定程度模拟线上真实流量的比例,但是工作量非常大

限流会引入脆弱性

当整个分布式系统每个服务都有限流功能时,以后服务的扩容、新功能的上线以及调用拓扑结构的变更,都有可能导致局部流量的骤增,从而引发限流使业务受损

最好的方式是在系统的核心链路和核心服务上,默认开启限流机制

此文章为2月Day15学习笔记,内容来源于极客时间《深入浅出分布式技术原理》