查看原文
其他

天弘基金首席架构师李鑫:微服务接口限流的算法及架构实现

李鑫 中生代架构 2021-09-05

李鑫(码码的土狼)

读完需要

9分钟

速读仅需 3 分钟


李鑫,著有《微服务治理:体系、架构及实践》一书,公众号“码码的土狼”分享技术干货及心得。

目前是天弘基金移动直销平台的技术总监兼首席架构师,负责基金直销平台的整体技术架构和技术团队管理;
曾在华为中间件技术团队任六级技术专家,主导了多款华为软件的云计算产品的规划、设计、构建及落地工作,包括 APaaS、ASPaaS、服务治理平台、分布式服务调测框架等几款产品;
在此之前,在当当网的运作产品中心任技术负责人,主要负责电商中后台的仓储、物流、客服等系统的重构优化及技术管理工作。

其从业十多年,在并行计算、大规模分布式服务及治理、中间件云化及服务化(PaaS)、APM 监控、基础开发平台、数据集成及治理等领域都有技术积累,如果大家在这些领域有疑问或好的建议,欢迎共同探讨。

线上系统遇到的一大风险就是流量的暴涨暴跌,尤其是在这个全民上网的时代,一条明星出轨的新闻带来的访问流量暴涨可以把微博给压趴。

企业会优先通过扩容来尽量容纳所有的流量,以保障业务不受损失。但通过资源扩容来提升系统容量也不是无限的,不仅技术实现上不现实,从成本投入角度看也不划算。

相对而言,更经济可行的方式是限流或者降级这就像一些城市在上班高峰期车流量增大时,临时增调对行车道以增加通行容量;如果车流量再继续增大,就只能限行,控制进入车道的车辆数。


1


   

服务限流的概念

所谓限流,是根据某个应用或基础部件的某些核心指标,如总并发数、QPS 或并发线程数,甚至是白名单,来决定是否将后续的请求进行拦截。比如我们设定 1 秒的 QPS 阈值为 1000,如果某一秒的 QPS 为 1100,那超出的 100 个请求就会被拦截掉,直接返回约定的错误码或提示页面。

服务限流是在高流量下保证服务集群整体稳定,并提供一定可用性的有效办法。比起系统整体被“压趴”,所有用户都无法获得服务的状况,拒绝一部分用户,对另一部分用户提供正常服务总是要好一些。

限流操作一定要前置,对于已经明确要被拒绝处理的流量,尽量不要放到后续环节。一方面可以避免不必要的资源浪费,另一方面也可以减少调用方无谓的等待。如图 1 所示,如果在服务调用方限流,则在接口调用发起时就可以进行限流控制;如果在服务提供方限流,则在请求接入后、解码前就可以进行限流控制。

图1 服务流控架构

流控的模式也不仅仅局限于一种,可以采用多种流控模式的组合来应对复杂业务场景下的限流需求。

比如,当发生热点事件时,可以先基于 IP 白名单,只允许联通用户的请求接入,在此基础上再基于 QPS 进行限流。对服务集群而言,单个服务节点的限流是基础,它是实现集群整体限流的前提,下面,我们首先介绍单服务节点的限流实现。

2


   

单服务节点限流

限流的目的不仅是要控制访问的总并发量,还要尽量让访问的流量来的更均衡,才不会让系统的负载大起大落,因此又称之为“流量整形”。在单点模式下有多种手段能达到“流量整形”式限流,也有很多组件可供选择,例如 Java 自带的信号量组件 semaphore,Google Guava 的 RateLimiter 组件等。那么,这些组件的限流模式有什么不同呢?

2.1


   

漏桶算法

很多受欢迎的餐厅在就餐高峰期都需要排队,餐厅为客满后再来的顾客发放排队号,当有顾客用餐完毕离开,就按排号顺序让最早的顾客进入餐厅就餐。这实际上就是一种限流措施,严格控制客流量稳定在餐厅的招待能力范围内。这种限流方式保证在餐厅内就餐的顾客总数(并发数)是一致的,只有出去一个顾客,才能放进来一个顾客。新来的顾客能不能吃上饭,完全取决于已就餐顾客是否“翻牌”。

图2 漏桶算法&令牌桶算法

餐厅排号就餐的方式非常像一个漏桶,桶的容量是固定的,桶底的水不断的流出,桶顶的水不断流入,如果流入的水量(请求量)超出了流出的水量(最大并发量),桶满后新流入的水会直接溢出,这就是限流应用中常用的漏桶算法,如图 2-1 所示。漏桶算法可以很好的控制流量的访问速度,一旦超过该速度就拒绝服务。Java 中自带的信号量组件 Semaphore 就是典型的基于漏桶算法的组件,它可以有效控制服务的最大并发总数,防止服务过载。以下是 Semaphore 的典型用法:

1private Semaphore smp = new Semaphore(30);     //非公平策略
2...
3if(smp.getQueueLength()>0){   //如果有排队现象,则立刻拒绝服务
4    return;
5}
6try{
7    smp.acquire();   //获取一个信号量
8    //处理具体的业务逻辑
9}catch(InterruptedException ex){
10     ex.printStackTrace();
11}finally{
12    smp.release();      //释放信号量
13}

研究漏桶算法可以发现,它主要关注当前的并发总量(信号总量),只有某个资源被释放的信号发出(release 操作),等待进入的请求才能获得通行证,有“出”才有“进”,通过这种方式,来保证系统负载可控。

2.2


   

令牌桶算法

限流的另一种常用算法是令牌桶算法,它的原理如图 2-2 所示,系统以恒定的速率往桶里放令牌,请求需要从桶里获得令牌才能被处理,一旦桶里无令牌可取,则拒绝服务。Google Guava 的 RateLimiter 组件就是采用的令牌桶算法。下面是基于 RateLimiter 实现的简单限流示例:

1RateLimiter limiter = RateLimiter.create(5);
2System.out.println(limiter.acquire());
3System.out.println(limiter.acquire());
4System.out.println(limiter.acquire());
5System.out.println(limiter.acquire());
6System.out.println(limiter.acquire());

代码运行后,可以获得如下结果

0.0
0.199013
0.195662
0.199781
0.200103

上面的代码中,01 行代码创建了一个容量为 5 的“桶”,并且每秒投入 5 个令牌。第一次申请一个令牌时(02 行),当前桶中有足够的令牌,因此可以马上获取到,此时打印出来的等待时间是 0。后面再请求令牌时,由于要达到“流量整形”的目标,RateLimiter 会以固定周期,间歇性的往“桶”里投入令牌,平均时间间隔是 1000ms/5=200ms 左右,因此 03~07 行的代码运行就被阻塞了,从运行结果上看,基本符合理论计算的预期。可见,RateLimiter 通过这种策略将突发请求速率平均为(整形成)固定请求速率。在实际应用中,对无法获取令牌,注定要被拒绝的请求可以快速抛弃,减少请求的等待时间,降低阻塞带来的无谓资源损耗。因此,实际使用中会更多使用无阻塞的 tryAcquire 方法,尽量少用阻塞的 acquire 方法。如下代码是常用的基于 RateLimiter 令牌桶的限流模式:

1RateLimiter rateLimiter = RateLimiter.create(100);    //控制每秒只能有100个请求进来
2if(!rateLimiter.tryAcquire()){   //判断是否能马上获取令牌,如不能则直接给客户端返回错误信息
3//给客户端返回异常或者拒绝信息
4    return;
5}
6//下面是正常业务逻辑
7...;

比较 RateLimiter 和 Semaphore 的限流,可以发现,RateLimiter 并没有一个后置的、类似 Semaphore 的 release 这样显式的信号释放动作,其通过 acquire 和 tryAcquire 动作是否能够获取到令牌完全取决于时间,限流控制是在请求流入端进行。

3


   

服务集群限流

单机限流下,各个服务节点负责各自机器的限流,不关注其它节点,更不关注服务集群总调用量。

因为后台总资源是有限的,有时虽然各个单节点的流量都没有超,但总流量会超过后台资源的总承受量,所以必须控制服务在所有节点上的总流量,这就是集群限流。

总流量控制可以在前台通过网关来实施。但 P2P 直连模式的服务集群没有网关一说。

所以要控制总流量,就必须先汇总集群各个服务节点的流量,并将这个总流量与预先设定的 SLA 阈值相比较,如果超了就要进行限流。比如 SLA 设置 1000,总流量算出来是 1200,那就超了 200,这时就必须将总流量降到(1-(200/1200)),大概 0.85 左右。

每个服务节点都要将当前流量降低到这个比例。由于流量的倾斜,每台机器的流量都不一样,需要将 0.85 这个限流比例推到各个服务节点,让每个节点基于自己之前统计的流量结合 0.85 限流比率算出各自的限流阈值。再根据各自的限流阈值去调用 semaphore 或者 RateLimiter 做单机限流。

因此集群环境下的限流也要以单点的限流为基础,但流量判定上有所不同,集群环境下需要采集所有服务节点的流量信息进行统一判定,图 3 是典型的集群限流架构图。

图3 集群限流架构图

服务集群限流基本遵循如下步骤:

1. 将时间分片,可以 1 分钟,也可以 30 秒钟、10 秒钟,具体时间长度根据业务实际需求,也与线上日志的采集及处理能力相关。每个服务节点记录本节点的每次实际调用及调用延时,并统计本时间片内的总调用量及平均调用延时。

2. 一个时间片结束后,这个时间片内的调用计数会以日志的形式被采集并汇总到日志中心(如图 3 的步骤 1),对日志的流式分析中会有专门的统计分析器对这些调用计数日志进行分析。当统计分析器确定所有的日志都已到位,会进行集群调用量的汇总,并基于时间片算出这个时间片对应的此服务集群的 QPS(步骤 2)。

3. 分析器集合中的集群限流分析器根据统计分析器的结果,并结合服务注册中心中定义的限流配置来判断是否需要进行限流控制。对于一些自动化程度高的系统,可能还要综合平均调用延时及服务等级协议(SLA)来做综合评判,如果实际流量超过了限流阈值(或者综合评判满足限流条件),则计算出一个限流比例(步骤 3)。不考虑其他因素的限流比例的计算公式如下:
限流比例=1-(实际 QPS-限流 QPS)/实际 QPS

4. 集群限流分析器将“限流比例”指标写入服务注册中心(步骤 4),并通过服务注册中心的事件推送机制将此配置下发到各服务节点。服务节点基于获取到的限流比例,根据对应时间片的调用量换算出限流调用量,再采用“单点限流”的限流策略进行限流控制。

从上述步骤可见,服务集群的限流机制比较复杂,需要依赖监控、计数、分析、配置下发、节点流控等各个能力的协同配合,缺一不可。为了实现高效的集群限流控制,必须实现各个环节的高效处理,要注意以下几个方面:

1. 时间片太长,会导致限流操作滞后,可能限流指令还未下发,服务集群就被压垮了,因此要尽量缩短时间片的长度。但时间片也不是越小越好,由于流量的波动,太小的时间片计算出来的 QPS 可能会有较大偏差。所以,需要根据线上流量特点来评估时间片的长度设置。

2. 日志采集一定要及时,时间片一结束,要尽快将计数日志发出,可以让计数日志采用单独的日志文件,并配置独立的采集器,优先保障其信息采集。如果采用消息队列对日志数据进行缓冲,可以给访问计数日志设置独立的 Topic,以提高其处理优先级。

3. 对计数日志的分析一定要采用实时分析,不能是离线分析,否则不具有时效性。

4


   

限流的难点及注意事项

如果只是单纯的单点限流其实并不难,有很多现成的组件可以选择。但如果要构建系统的限流体系又是一件极“难”的事情。

它的难度在于,由于涉及服务节点的调用监控、日志采集发送、日志接收聚合、计算分析、限流决策判断、指令下发、节点限流等许多环节,要实现各环节的高效衔接和紧密协作配合,需要整个技术栈的统一及协同调度。

所以说,要构建一套行之有效的限流体系,必须统一微服务框架、日志采集规范、日志分析规范、SLA 的定义及节点限流的技术策略,这些都要有很明确的要求。

如果某些环节使用的框架不同,那么这套统一的技术体系就无法推广落地。试想,如果企业内部同时存在基于 Java 和 Go 两种语言构建的微服务框架,那么针对它们的节点限流就必须要创建两套不同语言的节点限流及对应计数、日志采集的能力,相应的开发及维护成本也会升高。

技术栈的统一,依赖于技术体系的标准化建设。如果在 IT 建设的初期就注重技术选型及构建的标准化,后续在构建新能力时,就可以有效减少业务代码的改变和调整。

不仅仅是限流体系,还有治理工作甚至运维自动化遇到的大部分困难往往都是标准化缺失导致的。“没有规矩,不成方圆”,这里的规矩就是我们从各式各样的 IT 运维对象及流程中提取出来的标准和规范,也是构建自动化及智能化运维能力的前提。

所以,一定要重视标准化的建设,具体到限流体系的构建上也是如此,要“标准先行”。限流体系的标准涉及如下几点:

1. 节点限流策略的选择及集成;
2. 节点调用度量时间片的设定策略;
3. 计数日志采集规范及度量规范;
4. 限流配置规范;
5. 限流指令规范。


5


   

本文节选自《微服务治理:体系、架构及实践》一书



精彩文章推荐:


一文讲清K8s如何改变美团的云基础设施2020-08-21
蚂蚁科技 Service Mesh 落地实践与挑战 | GIAC 实录2020-08-18
托管式服务网格:多种类型计算服务统一管理的基础设施2020-07-30
亿级流量请求,多级缓存解救2020-07-27
已火 2 年,Service Mesh究竟给微服务带来了什么?2020-07-22
为什么我不推荐你盲目追求微服务?迟早要吃亏!2020-06-30
阿里高级技术专家邱小侠:微服务架构的理论基础 - 康威定律2020-05-09
导致微服务失败的 11 个原因2020-05-08
停!你不需要微服务2020-04-30
缓存穿透、缓存击穿和缓存雪崩实践附源码2020-04-24
可能是全网最通俗易懂的微服务架构改造解读2020-04-21



   END     

#接力技术,链接价值#

点分享点点赞点在看
: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存