服务稳定性建设之限流机制 学习笔记

前言

通过前文,我们了解了当下游服务过载时,借助熔断和降级机制,能够有效提升服务的稳定性。但反过来,倘若我们自身作为其他服务的下游,在面对可能出现的突发流量时,怎样才能有效避免自身服务陷入过载状态呢?

许多热门旅游景点会通过限制门票销售数量来控制景区的人数,当门票售罄后,后续的游客需要等待或改日再来。这种限流措施可以有效避免景区内过度拥挤,确保游客的安全和体验。

与之相似,在秒杀、大促抢购这类高并发场景中,为避免超出预期的流量冲击,导致服务出现过载、性能下降乃至崩溃的状况,我们通常会给服务添加限流机制限制服务在单位时间内处理的请求数量,当请求量超过预先设定的阈值时,就直接拒绝超出部分的请求。一旦触发限流,前端便会显示 "活动太火爆啦,请稍后重试" 之类的提示文案。

常见的限流算法

一、固定窗口算法

也称为计数器算法,需要设定一个固定的时间窗口,在这个时间窗口里,每收到一个请求,计数器就加 1 。当计数器的值达到设定的限流阈值时,这个时间窗口内后续收到的请求就会被限流,直接被拒绝或者排队等待,直到进入下一个周期后,计数器重置为 0,重新开始计数。

优点:简单易懂,在流量较为均匀且对限流精度要求不高的情况下,能够发挥重要作用。例如,在一些日常访问量相对稳定、无需精细控制请求频率的系统中,固定窗口算法可以简单有效地控制请求量。

缺点:在请求流量分布不均的情况下,存在下面两个问题

  1. 抗抖动能力较弱 :当请求流量分布不均时,即便在设定的固定时间窗口内,整体流量没有突破限流阈值,但可能在局部较短时段内出现流量尖峰,导致服务负载突然升高。例如,设定限流阈值为 1000 QPS,在 1 秒的时间窗口内,可能前 10 毫秒就涌来了 999 次请求,而随后的 990 毫秒仅有 1 次请求,这就导致前 10 毫秒内服务负载压力极大。
  2. 时间窗口边界限流不准:在时间窗口交替的地方,可能会出现高达两倍阈值的请求量。例如,设定限流阈值为 1000 QPS,在前 1秒时间窗口的最后 10 毫秒,请求量达到 900 次,紧接着后 1 秒时间窗口的前 10 毫秒,请求量又达到 900 次。这样一来,在这短短 20 毫秒内,请求量就达到 1800 次,远远超过 1000 QPS 的限制。
二、滑动窗口算法

对计数器算法做了一定的改进,将时间窗口划分为多个更小的子窗口,每个子窗口都有独立的计数器。随着时间的推移,窗口移动,统计滑动窗口内的请求总数进行限流。比方说,将 1 分钟的时间窗口划分为 60 个 1 秒的子窗口,每个子窗口记录该秒内的请求数量。当窗口滑动时,就会移除最旧的子窗口的计数,再把新的子窗口计数纳入统计。

优点:相较于计数器算法,滑动窗口算法的确能在一定程度上避开临界问题,让限流的精准度有所提升

缺点:实现过程较为复杂,需要对多个子窗口的计数器进行维护。特别是当时间窗口划分得过细时,会过度消耗内存空间 。并且,滑动窗口算法在应对流量波动时,抗抖动能力差的问题依然存在

三、漏桶算法

可以把请求想象成水,漏桶则是一个固定容量的容器,底部有一个固定大小的孔用于漏水(处理请求)。水(请求)以任意速率流入漏桶,但漏桶始终以固定的速率将水(请求)漏出(处理)。如果漏桶已满,新流入的水(请求)将溢出(被限流)。

优点:最大的优势在于它的流量整形功能,不管请求流量如何波动,都能以固定的速率处理请求,保障服务不会因为突发流量而导致过载。特别适用于对接第三方 API 的场景。当第三方 API 对调用频率有明确限制时,为了防止因超出频率限制而导致调用失败,我们需要在客户端进行精准限流。此时,漏桶算法无疑是最佳选择。

例如,在电商购物的支付环节,支付系统需要与众多上游银行系统对接,我们必须根据各银行的服务等级协议(SLA)来严格限制请求速率。在这样的场景下,漏桶算法不仅能够确保请求的平滑处理,还能有效避免因请求过载而导致的支付失败,保障支付流程稳定可靠。

缺点:漏桶算法也有局限,它在应对短时突发流量时,难以充分挖掘系统资源的潜力 。因为它始终保持固定的请求处理速率,一旦遭遇短时突发流量,极有可能导致大量请求因漏桶满而被限流。事实上,对于多数服务而言,短时间内处理压力的增大,并不至于引发整个系统的崩溃。所以,当服务负载水平较低,却面临短时突发流量时,我们期望服务能够适度提升处理速度,从而尽量减少不必要的限流,影响用户体验

四、令牌桶算法

在这种算法机制下,系统会以固定的速率生成令牌,并将这些令牌放入桶中。每个请求在被处理前,都必须从桶中获取一个令牌。要是桶里有令牌,这个请求就能顺利进入处理流程;要是桶内没有令牌,这个请求就会被限流。值得注意的是,令牌桶设有容量上限,一旦桶被令牌填满,新生成的令牌就会被丢弃。

采用令牌桶算法,当服务处于低负载状态,令牌桶内会积累大量令牌。这时,如果遭遇短暂的突发流量,凭借充足的令牌储备,这些突发请求能够得到快速处理。因此,令牌桶算法能够出色地应对短时突发流量,有效保障服务稳定、流畅

在微服务架构实践中,针对上游服务限流,为了实现流量的平滑处理,同时又能允许一定程度的突发流量出现,我们往往会选用令牌桶算法。

限流对象/粒度

应该针对哪个关键标识(key)进行限流?在服务端限流的实际应用场景中,我们通常会将下面的关键元素组合,构建出具有针对性的限流 key。

  1. 服务维度:通常情况下,一个服务可能会对接多个上游服务。如果某个上游服务的流量突然大幅增加,引发限流,很可能会波及其他服务的正常访问。因此,为了防止这种情况发生,我们需要以上游服务为维度进行限流,针对每个上游服务构建唯一标识。
  2. 接口维度:由于一个上游服务可能会调用我们服务的多个接口,如果某一个接口的调用量超出限制,就可能影响其他接口的正常访问。所以,为了保障各接口的稳定访问,我们有必要针对接口名称实施限流。
  3. 集群维度:由于不同的服务集群,机器数量存在差异,处理能力也不尽相同。因此,为了适配不同集群的实际情况,我们需要针对不同的集群制定差异化的限流配置,限流对象是本服务集群名称。
  4. 业务场景维度:在实际业务中,上游往往会依据不同的业务场景划分集群,而不同集群的重要程度各有不同。若采用统一的限流策略,可能会出现例如上游一些非关键业务场景的突发调用,导致像下单这类核心集群被限流的情况。所以,为了避免此类情况,我们同样会针对负责不同业务场景的上游服务集群名称进行限流。

关于限流对象的选择也很关键。为了防止出现误限流的情况,我们会综合考虑多个因素,将上游服务标识、本服务接口名称、本服务集群名称以及上游服务的集群名称进行组合,形成限流的关键标识(key),以此来实现精准的限流控制。通过这种方式,可以更加细致地对不同来源、不同接口以及不同集群的流量进行管理,避免因单一维度的限流导致不必要的业务影响。

限流方式

常见的限流方式主要有集中式限流与单机本地限流这两种。

  • 集中式限流:在系统架构中借助一个中心化的组件(如 Redis)来集中统一地管理和执行限流逻辑。多个应用实例或服务节点都向这个中心组件请求限流许可,由它来决定每个请求是否被允许通过。集中式限流能够精确控制整个服务的流量,确保整体流量不超过设定的阈值。然而,由于请求需经由中心化组件处理,这在一定程度上增加了请求延迟。特别是在高并发的复杂场景下,中心化组件承受的巨大压力,会显著提升服务稳定性受损的风险。
  • 本地限流:在单个服务器或服务实例上进行限流,通过限制单台服务器在单位时间内处理的请求数量,防止服务器过载。得益于限流操作在本地内存中的高效执行,本地限流的延迟极低,且无需依赖任何外部组件,这保障了更高的稳定性。然而,本地限流的应用场景相对受限,它更适用于那些服务节点流量分布相对均衡的环境。一旦面临流量分布不均的情况,想要合理设定各个单机的限流阈值就会变得特别困难。

在微服务架构体系下,服务调用通常会借助负载均衡 机制来实现。基于此,我们可以合理假设各个单机所承担的流量大致相当。因此,在进行服务限流时,本地限流便成为了首选方案

具体操作中,我们会将整体的限流阈值均匀分配到每台机器上,以此作为单机本地限流的精准阈值,从而确保整个服务在高并发场景下的稳定运行与高效处理。

总结

参考

《go服务开发高手课》

相关推荐
浪九天3 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
uhakadotcom4 小时前
Apache CXF 中的拒绝服务漏洞 CVE-2025-23184 详解
后端·面试·github
uhakadotcom4 小时前
CVE-2025-25012:Kibana 原型污染漏洞解析与防护
后端·面试·github
uhakadotcom4 小时前
揭秘ESP32芯片的隐藏命令:潜在安全风险
后端·面试·github
uhakadotcom4 小时前
Apache Camel 漏洞 CVE-2025-27636 详解与修复
后端·面试·github
uhakadotcom4 小时前
OpenSSH CVE-2025-26466 漏洞解析与防御
后端·面试·github
uhakadotcom4 小时前
PostgreSQL的CVE-2025-1094漏洞解析:SQL注入与元命令执行
后端·面试·github
zhuyasen5 小时前
Go语言开发实战:app库实现多服务启动与关闭的优雅方案
后端·go
ITlinuxP5 小时前
2025最新Postman、Apipost和Apifox API 协议与工具选择方案解析
后端·测试工具·postman·开发工具·apipost·apifox·api协议
浪遏5 小时前
面试官😏 :文本太长,超出部分用省略号 ,怎么搞?我:🤡
前端·面试