作者:人月神话、新浪同名博客简介:多年SOA规划建设,私有云PaaS平台架构设计经验,长期经验一线项目实践,今天要讲的是微服务架构和API网关中的限流熔断器。目前可以看到Hystrix也是为SpringCloud框架本身提供的。像Kong网关这样的主流开源API网关产品,也都带有限流熔断器。当然,也有完全独立的限流熔断源实现。比如阿里的Sentinel就是我们经常使用的一款限流熔源产品,它可以和Dubbo、SpringCloud等各种微服务框架无缝集成。由于网上可以搜索到很多关于限流熔断器功能和使用的各种开源产品的文章,本文不打算介绍这些开源产品,而是想下一个限流熔断器从业务场景在功能实现上的一些想法。当然,我们常说的资源定义,线程池隔离,滑动时间窗计算还是一样。问题及背景说明首先我们来看一下下限流保险丝的出现背景。比如上图中的微服务之间的调用关系,我们就以此图为参考来进行一些常见的场景和问题。某个API接口服务调用导致整体资源耗尽。这是一个典型的场景,就是某个API接口服务的并发量大,大量的数据调用导致服务器线程和内存资源耗尽。对于API接口服务调用,我们往往不怕大并发调用,就怕耗时长、数据量大的调用。这种接口调用导致连接一直被占用,但是在数据量大的情况下内存资源总是被占用。服务是否。在这种场景下,线程池往往是满的,或者场景中的JVM内存溢出问题,会直接导致整个JVM内存溢出崩溃。也就是我们常说的单个API服务问题导致所有资源被抢占,影响所有API接口调用。人们常说服务调用会导致雪崩。在微服务架构下,微服务的API接口相互依赖,形成服务链调用关系,如上图所示。在这种情况下,如果依赖它的API接口服务出现问题,就会导致上层所有消费者调用异常,导致整个服务链的调用雪崩。比如上图中C1出现性能问题,会直接导致B1和B2都出现性能问题,而B层的性能问题会很快传导到A层,导致所有API接口出现问题与A层相关的服务……从上面的初步分析也可以看出,服务限流熔断简单的说就是不因为单个API接口服务出现异常或者性能问题而影响到整个API网关或者微服务架构的运行,牺牲或者拒绝访问一个service经常保证更多的服务可以正常消费和调用。梳理完以上概念,我们再回到业务限流和断路器本身的概念上。限流断路器的基本概念对于限流断路器,我给出了一个概念。简单的说,限流就是服务请求调用必须排队。你只会得到线程池的总数。如果你超过了,你就会等待,即使你的瞬时请求是并发的。也需要慢慢输入。对于断路器,我们常说整个服务处于不可用状态。今天我们重新解释一下这个概念。如下图所示:一个API接口有多个消费者,限流更多的是针对消费者+API的粒度,断路器是针对整个APIProvider服务。限流策略既可以对消费者的服务请求进行排队,也可以在触发规则后直接拒绝特定的消费者调用。比如上图只拒绝了Consumer2的调用,而对于其他消费者Party的调用还是允许的。对于熔断策略,必须拒绝整个服务的访问。注意,这种熔断不一定是服务下线或者状态改变,也可以直接在限流熔断拦截器上拒绝所有入口请求。总体实施思路的描述在谈具体实施方案时,首先要谈一下总体实施思路。从前面的分析我们也可以看出,其实限流和熔断的资源单元和控制粒度是有更多区别的,因为我们想要的是建立一套算法来满足所有问题场景的需求。由于服务限流断路器更需要拦截服务,我们也看到限流断路器一般是和API网关、微服务网关等配合使用,而不是独立存在。01-资源粒度的考虑阿里的Sentinel实现中有几个重要的概念,一个是resource,一个是slot,一个是slidingtimewindow在实现机制上,但是一开始好像不能配置成单一的消费者+服务水平。对于资源粒度,初步分析应该包括多个层次,从最粗的资源到最细的资源。在传统的资源粒度考虑中,我们往往不会考虑微服务或者业务系统的粒度,但是如果API网关的限流被拉断,这对于API网关本身的性能保护还是很有必要的。比如用户中心的微服务,实际上提供了29个API服务接口。当用户中心微服务模块本身出现问题时,这29个微服务可能会出现性能访问变慢的情况,所以需要的是对整个用户中心连接的所有API服务进行限制和融合。即我们进一步细化资源本身的粒度,从最细粒度到最粗粒度可以分为:最细粒度:API消费者+API服务+API提供者熔断层:API服务+API提供者熔断范围:APIprovider(融合API服务提供者的所有服务)以上三个粒度是我们在实际控制资源时需要考虑的。为什么我们会想到这个问题?我们搞清楚了资源管控的粒度。一方面,我们在配置规则时需要支持多级配置。另一方面,我们在实际计算实时数据时需要考虑粒度。02-规则重点讲解要实现限流熔断,简单来说就是三个方面,一是资源,一是规则,三是通过计算总结的过程。最后的计算过程是判断当前某个时间点的实际数据是否满足规则触发的要求,满足则触发规则进行限流熔断。对于规则,首先要考虑维度定义,维度本身就是API接口服务运行实例的汇总统计。那么这些场景的维度包括:API服务运行时间,API服务单位时间运行次数,API服务运行数据量,这三个基本维度本身会进一步产生其他的扩展维度,比如我们常说的最大数据量,评估数据量,操作失败次数,操作成功率,操作最大耗时等。具体的规则,我们希望用最简单的方式来处理,即如果某个指标大于或小于预定阈值,则满足规则。第二个是定义复合规则的能力。复合规则也简单的看做规则的AND或处理,即同时满足规则1和规则2,即使满足了整体规则,规则本身的作用范围,我前面也提到过,是资源本身的不同粒度。规则可以应用于特定消费者在最细粒度级别调用的特定服务,或者应用于服务的所有消费者。简单来说:规则+资源在最终计算完成后触发限流熔断行为。03-计算逻辑的重点讲解上一节我们理清了规则和资源之后,我们来看一下具体的计算逻辑思路。对于计算逻辑,我们可以将计算过程分解为多个独立的计算单元,再由多个计算单元组合,最终形成一个完整的计算处理逻辑。可以看到,Sentinel限流熔断器产品中的Slot概念可以理解为我们前面讲的计算单元。Sentinel最终结合各个Slot的能力,完成一个完整的限流熔断逻辑处理。对于计算逻辑,我们还是要回到具体的规则配置上。例如,我们配置的规则的呈现方式可能是这样的:对于用户查询API接口,如果5分钟内调用次数超过10000次,则整体熔断。对于CRM系统消费商品查询接口,如果10分钟内平均时长大于30秒,则拒绝CRM访问对于订单更新API接口,如果失败率超过1%,则全部熔断从上面的描述,我们有看到了单位时间的概念,就是当我们触发限流熔断行为的时候,我们不希望它是一个意外的调用并发或者异常会立即被触发,但是我们希望它是一个单位时间段的我们observe,只有当某些异常行为持续发生时才会被触发。这个单位时间可以是5分钟,也可以是10分钟,甚至1小时。也就是说,我们最终统计的是单位时间内最终的汇总统计量。也就是说,我们需要采集实时的服务运行实例数据,采集完成后,根据资源粒度进行分类汇总,形成汇总数据。那么如何总结呢?如果我们要统计一个小时,是不是要一直在内存中存储一??个小时的实例数据,等到单位时间一小时后再进行汇总处理呢?这显然是不合适的。Hystrix的滑动窗口计算逻辑就是这个原因,我们给出一个最小统计时间间隔的概念,比如我们可以设置为10秒,我们先汇总最小时间间隔为10秒的实例数据,然后第一次将聚合后的数据放入我们的滑动窗口数组中。然后根据规则配置,提取滑动窗口中的数据进行二次汇总处理,最后判断配置的规则是否触发限流熔断操作。限流熔断器的整体实现逻辑在前面的内容中进行了说明。我们来看一下限流熔断器的整体实现逻辑。您可以将本文的逻辑看成是对当前主流限流熔断器产品的逻辑简化实现。当然,一方面是简化。另一方面,本文的方法在资源控制粒度上会更加细化。对于整个限流断路器的处理逻辑流程,我们可以简化为下图:对于这张图,我们其实可以看出,如果按照Slot计算来划分逻辑单元的话,可以分为:根据配置规则,服务运行实例被划分为资源颗粒度匹配要求存储在实例数据暂存区进行第一次汇总计算,汇总数据推入滑动时间窗口数组进行二次汇总计算根据规则配置判断并处理限流熔断器是否触发。下面我们就应用上面的思路做一个简单的描述。比如我们目前在限流和熔断规则的配置中配置了三个独立的规则,不同的资源粒度。规则一:限制CRM消费getCustomer接口的流量,10分钟内调用>10000则拒绝。规则二:对于getProductinfo接口的流控,如果5分钟内错误>1%,则整体熔断规则三:对于ERP系统提供所有服务,1分钟如果平均时长>30秒,则整体熔断保险丝会被打破。如果使用以上三个独立的限流熔断规则,那么我们需要配置三个不同的数据暂存区和三个独立的滑动时间窗区。将临时数据推送到10秒临时数据存储区时可能会造成冗余,但在限流规则本身不带配置的情况下,该方案是最优方案。毕竟在实际应用场景中,我们往往只有在发现详细的性能异常或问题时才配置限流和熔断规则。例如CRM系统调用getCustomerAPI接口。当获取到实例数据后,我们会将其推送到第一个缓存集合中。如果接口本身也是ERP系统提供的接口,那么我们会同时推送一份数据到ERP系统缓存集合中。对于缓存数据集,我们每10秒执行一次聚合过程。并将聚合后的结果数据形成一条记录,推送到对应的滑动时间窗口区域。推送完成后,数据集中的所有数据被清除或资源被释放。基于滑动窗口数据的二次数据处理对于滑动窗口中的二次数据处理,我们可以在每次数据推送完成后计算一次滑动窗口数据,比如5分钟规则,我们最后一次获取窗口中的数据5分钟进行二次聚合,判断二次聚合后的数据是否满足相应的触发条件。如果满足条件,则执行限流熔断过程。限流断路器实现逻辑与API网关能力的解耦最后说一下限流断路器实现与整个API网关能力的解耦。简单来说,限流熔断器本身也是一个独立的拦截器,拦截服务请求,判断当前的限流熔断器规则是否生效。如果生效,则会触发限流熔断操作,比如拒绝访问请求。.如果状态无效,则释放服务请求。那么,我们需要重新梳理一下限流熔断器和API网关的集成关系,如下:当然,服务本身断线后,我们也可以设置一个释放时间间隔,比如5分钟或者10分钟,我们还需要设置一个定时任务进行计算,当满足释放条件时刷新全局状态缓存中的服务状态,从而释放服务限流。以上是业务限流和断路器逻辑实现的以下重点考虑,供参考。
