在微服务高并发的一些场景下,微服务之间的调用量不断增加,大流量因素很可能会引起服务雪崩,微服务的稳定性对业务系统的影响也比较大。一般微服务容错组件都提供了限流的方式来保护我们的系统,本文主要介绍微服务限流的几种主流方案与适应的场景。
1.1 限流的目的是什么
珍稀之物如星辰般散落,在广袤的大地上熠熠生辉。稀缺的资源总是珍贵的,对于计算机系统来说,在业务的高峰期时也往往会存在资源挤占的情况,甚至导致业务的宕机。例如我们腾讯的游戏类业务有时候会举行一些运营活动,比如卡券领用等,往往会导致用户大流量的产生。还有视频类业务,在遇到热点事件的时候,也会导致突发的大流量冲击问题。而限流则是一种服务很好的保护机制,可以保障服务平稳的运行。服务提供者和服务消费者均可按照一定规则进行限流保护,例如请求的频率达到阈值后做限流处理,防止服务因为流量过大而崩溃。限流主要有两个目的:
1.2 限流机制应该考虑什么
好的限流机制需要综合考虑多个关键因素以确保限流系统的有效性和公平性。
1.3 针对什么来限流
从限流的对象来看,可以分为单机限流、集群限流、针对业务对象的限流。
2.1 主流的限流方式对比
常见的限流方案有固定窗口计数器、滑动窗口计数器、漏斗(漏桶)、令牌桶等,下面我们来看看几种方式的对比情况。
2.1.1 固定窗口计数器
基本概念:
固定窗口计数器算法是一种基本的限流方法,它通过在固定时间窗口内跟踪请求的数量来实现限流。
实现原理:
固定窗口计数器算法通过设置一个固定的时间窗口(例如每分钟)和一个在这个窗口内允许的请求数量限制(例如10个请求)。在每个时间窗口开始时,计数器重置为零,随着请求的到来,计数器递增。当计数器达到限制时,后续的请求将被拒绝,直到窗口重置。
优点:
缺点:
适用场景:
适用于请求分布相对均匀的场景,例如统计 PV/UV 请求等。但请求在短时间内集中到达的场景下,可能需要考虑更复杂的限流算法。
2.1.2 滑动窗口计数器
基本概念:
这个算法是固定窗口计数器算法的一个改进,它通过覆盖多个时间段来平滑请求流量,避免瞬时高峰。这种算法通常需要使用更高级的数据结构,如时间轮(Timing Wheel),来实现。
实现原理:
滑动窗口算法通过将时间分为多个小的时间段,每个时间段内维护一个独立的计数器。当一个请求到达时,它会被分配到当前时间所在的小时间段,并检查该时间段的计数器是否已达到限制。如果未达到,则允许请求并增加计数;如果已达到,则拒绝请求。随着时间的推移,旧的时间段会淡出窗口,新的时间段会加入。
优点:
缺点:
适用场景:
适用于需要平滑流量控制的场景,尤其是在面对突发流量时,能够提供比固定窗口计数器更优的流量控制效果。
2.1.3 漏斗/漏桶
基本概念:
漏斗算法,又名漏桶算法,是一种经典的流量控制方法,特别适合于平滑突发流量,确保数据以均匀的速率被处理。
实现原理:
通过一个固定容量的队列来模拟桶,以恒定速率从桶中取出请求进行处理,无论请求到达的频率如何,都保证请求以均匀的速度被处理,从而平滑流量并防止流量突增。
优点:
缺点:
适用场景:
漏斗适用于需要流量整形(强制固定速率等)场景,如网络流量控制、API 请求限制、DB 保护等。通过控制令牌的添加速率,漏桶算法能够有效地避免系统因瞬时流量高峰而过载。
2.1.4 令牌桶
基本概念:
令牌桶算法是一种流行的限流算法,它允许一定程度的突发流量,同时保持长期的平均速率。
实现原理:
令牌桶算法使用一个令牌桶来调节数据流的速率,允许一定程度的流量突发。桶初始时为空,并以固定速率填充令牌,直至达到预设的容量上限。与漏桶算法不同,令牌桶算法在桶未满时,可以在每个时间间隔内向桶中添加多个令牌,从而积累处理突发请求的能力。当请求到达时,如果桶中存在令牌,算法会从桶中移除相应数量的令牌来处理请求。如果桶中的令牌不足,请求将被延迟处理或根据策略拒绝服务。如果桶已满,额外的令牌将不会被添加,确保了令牌数量不会超过桶的容量限制。
优点:
缺点:
适用场景:
适用于需要处理突发流量的场景,如网络通信、秒杀、热点新闻等。通过控制令牌的填充速率和桶的容量,令牌桶算法能够有效地平衡流量,防止系统过载,同时允许在短期内处理更多的请求。
2.2 限流后采取什么动作
在一个正常的请求被限流之后,我们也可以采取一些方案来进行后续的处理。常见的后续动作有如下几种:
3.1 TSF 限流功能
TSF(Tencent Service Framework)微服务平台是一个围绕着应用和微服务的 PaaS 平台,提供应用全生命周期管理、数据化运营、立体化监控和服务治理等功能。TSF 拥抱 Spring Cloud 、Service Mesh 微服务框架,帮助企业客户解决传统集中式架构转型的困难,打造大规模高可用的分布式系统架构,实现业务、产品的快速落地。
TSF 限流的原理是监控服务流量的 QPS 指标,当达到指定的阈值时进行流量控制,避免被瞬时高峰流量冲垮,从而确保服务的高可用。TSF 目前支持在被调服务上设置限流规则,服务的限流对象(下文称为限流资源)可以通过标签表达式灵活配置,常见的限流对象如当前服务,当前服务的特定 API 等,并且可以通过标签表达式区分不同的调用来源,针对不同的调用关系进行限流。一条限流规则主要包括以下几个元素:
TSF 限流采用了动态配额分配制,限流中控根据实例的历史流量记录,动态计算预测下一时刻该实例的流量,若所有实例的流量预测值都小于额定平均值(总配额/在线实例数),则以该平均值作为所有实例分配的配额;否则按预测流量的比例分配,且保证一个最小值。
TSF 支持全局限流和基于标签限流两种模式:
TSF 支持对服务提供者的角度设置限流规则。一条限流规则包括规则名、作用域、限流阈值(单位时间内的请求数)。作用域可以是某一个微服务来源或是所有请求;一个服务可以有多个同时生效的限流规则,当一个请求被多个限流规则约束时,则仅当所有作用规则都判通时才会放行,这是对每个作用规则的通行请求数+1,若被一个规则拦截,则在该规则的限流请求数+1,请求被拦截。
3.2 TSF 限流原理
3.2.1 TSF 限流逻辑
通过 TSF 页面配置限流规则→调用 yunapi 接口→tsf-dispatch→tsf-ratelimit组件。tsf-ratelimit 组件同步数据库以及注册配置模块中的配置。tsf-ratelimit-master 组件作为流量中控,从各个实例中获取到历史流量,动态计算出下一时刻实例的流量,根据限流规则决定下发配额(超出流量阈值则缩小配额),返回给各个实例。SDK 通过这个配额,进行限流,这里使用的是令牌桶算法,能够限制数据的平均传输速率,还要允许某种程度的突发传输。
一般在下游服务配置限流规则,例如:服务 A 访问服务 B,由于服务 B 所在的服务器核数较低,一次承载不了太多请求,因此在服务 B 做服务限流,上游服务为服务 A,规则为 1s 内只允许一条请求。改规则下发后,通过 tsf-ratelimit 组件更新到注册配置模块以及数据库 DB 中,而 tsf-ratelimit-master 组件作为流控中心,会拉取 DB 中的限流规则。此时如果服务 A 在 1s 内请求了服务 B 两次,那么服务 B 就会上报这个流量记录到流控中心,而流控中心通过与限流规则对比,发现流量超标,则返回1个配额给服务 B,服务 B 的 SDK 通过令牌桶算法,限制服务 A 的请求。
3.2.2 TSF 令牌桶细节
TSF 使用的令牌桶限流,具体来说原理如下:
3.3 限流使用场景
TSF 通常适用于根据调用方进行限流和针对不同资源限流等场景,具体如下:
场景 | 应用场景描述 | 应用示例 |
---|---|---|
根据调用方进行限流 | 调用关系中包括调用方和被调用方,一个被调服务可能同时被多个服务调用。在限流规则中,限流粒度字段可以用于根据调用来源进行流量控制。区分调用方除了使用上游服务名等系统标签外,还可以使用自定义标签来区分带有不同业务信息的调用。例如针对特定用户 foo 的调用进行限流,可以在代码中设置 user 参数,然后在限流规则中配置业务标签为 user,逻辑关系为等于,值为 foo。 | 不区分调用者:限流粒度选择全局限流时,来自任何调用者的请求都将进行限流统计。如果限流资源的调用总和超过了这条规则定义的阈值,则触发限流。针对特定的调用者:限流粒度选择基于标签限流,设置系统标签为上游服务名,逻辑关系为等于,值为特定的调用服务。针对除特定调用者之外的调用方:限流粒度选择基于标签限流,设置系统标签为上游服务名,逻辑关系为不等于,值为特定的调用服务。 |
针对不同资源限流 | 一个服务包含一个或多个 API,TSF 支持针对服务或者 API 进行限流。在限流规则中,限流粒度字段可以用于区分不同的限流资源。 | 针对当前服务:无须额外设置。针对特定的 API: 限流粒度选择基于标签限流,设置系统标签为当前服务的 API Path,逻辑关系为等于,值为特定的 API Path。如果需要指定 HTTP Method,则需要再增加一条 HTTP Method 的系统标签来约束。针对特定 API 之外的 API:限流粒度选择基于标签限流,设置系统标签为当前服务的 API Path,逻辑关系为不等于,值为特定的 API Path。如果需要指定 HTTP Method,则需要再增加一条 HTTP Method 的系统标签来约束。 |
针对不同资源限流一个服务包含一个或多个 API,TSF 支持针对服务或者 API 进行限流。在限流规则中,限流粒度字段可以用于区分不同的限流资源。
3.4 其他治理方式补充
最后,我想说的是在微服务治理方面,限流也肯定并非银弹。在应对大流量的时候,限流固然是个办法之一,但是微服务架构中通常存在多个服务之间的相互调用,这些外部服务可能是 RPC 接口、数据库、第三方 API 接口等。而当我们依赖的外部服务出现不稳定的情况时,可能会导致服务自身调用外部服务的响应时间也变长,甚者形成级联效应。这样一来,服务自身的线程可能会积压,最终耗尽业务自身的线程池,导致服务本身变得不可用。为了保证整体系统的可用性和用户体验,除了限流我们一般还需要结合服务熔断与降级等治理手段来进行综合防控。
TSF 基于腾讯成熟的分布式核心基础组件,提供丰富的微服务治理与可观测等产品能力。TSF 还可以与 TCS/TCE 专有云底座、TDMQ 消息中间件等产品无缝对接,帮助企业轻松构建专属的云原生分布式系统,支撑企业业务的稳定运行。
-End-
原创作者|侯诗军