限流常用算法以及基于Sentinel的微服务限流及熔断

一、服务限流的作用及实现

在没有任何保护机制的情况下,如果所有的流量都进入服务器,很可能造成服务器宕机导致整个系统不可用,从而造成巨大的损失。为了保证系统在这些场景中仍然能够稳定运行,就需要采取一定的系统保护策略,常见的策略有服务降级、限流和熔断等。

限流的主要目的是通过限制并发访问数或者限制一个时间窗口内允许处理的请求数量来保护系统,一旦达到限制数量则对当前请求进行处理采取对应的拒绝策略,比如跳转到错误页面拒绝请求、进入排队系统、降级等。从本质上来说,限流的主要作用是损失一部分用户的可用性,为大部分用户提供稳定可靠的服务

在实际开发过程中,限流几乎无处不在

  • 在Nginx层添加限流模块限制平均访问速度
  • 通过设置数据库连接池、线程池的大小来限制总的并发数
  • 通过Guava提供的Ratelimiter限制接口的访问速度
  • TCP通信协议中的流量整形要实现限流,最重要的就是限流的算法,下面简单来讲解一下常见的限流实现算法

二 、常见的限流算法

2.1计数器算法

计数器算法是一种比较简单的限流实现算法,在指定周期内累加访问次数,当访问次数达到设定的闻值时触发限流策略,当进入下一个时间周期时进行访问次数的清零

如图7-2所示,限定了每一分钟能够处理的总的请求数为100,在第一个一分钟内,一共请求了60次。接着到第二个一分钟,counter又从0开始计数,在一分半钟时,已经达到了最大限流的闯值,这个时候后续的所有请求都会被拒绝。这种算法可以用在短信发送的频次限制上,比如限制同一个用户一分钟之内触发短信发送的次数

这种算法存在一个临界问题,如图7-3所示,在第一分钟的0:58和第二分钟的1:02这个时间段内,分别出现了100个请求,整体来看就会出现4秒内总的请求量达到200,超出了设置的闻值

2.2 滑动窗口算法

为了解决计数器算法带来的临界问题,所以引入了滑动窗口算法。滑动窗口是一种流量控制技术,在TCP网络通信协议中,就采用了滑动窗口算法来解决网络拥塞的情况。

简单来说,滑动窗口算法的原理是在固定窗口中分割出多个小时间窗口,分别在每个小时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口。最终只需要统计滑动窗口范围内的所有小时间窗口总的计数即可。

如图7-4所示,我们将一分钟拆分为4个小时间窗口,每个小时间窗口最多能够处理25个请求。并且通过虚线框表示滑动窗口的大小(当前窗口的大小是2,也就是在这个窗口内最多能够处理50个请求)。同时滑动窗口会随着时间往前移动,比如前面15s结束之后,窗口会滑动到15s~45s这个范围,然后在新的窗口中重新统计数据。这种方式很好地解决了固定窗口算法的临界值问题。

Sentinel就是采用滑动窗口算法来实现限流的,后续在源码分析部分会再讲到

2.3令牌桶限流算法

令牌桶是网络流量整形(TrafficShaping)和速率限制(Rate Limiting)中最常使用的-种算法。对于每一个请求,都需要从令牌桶中获得一个令牌,如果没有获得令牌,则需要触发限流策略

如图7-5所示,系统会以一个恒定速度(r tokens/sec)往固定容量的令牌桶中放入令牌,如果此时有客户端请求过来,则需要先从令牌桶中拿到令牌以获得访问资格

假设令牌生成速度是每秒10个,也就等同于QPS=10,此时在请求获取令牌的时候,会存在三种情况

  • 请求速度大于令牌生成速度:那么令牌会很快被取完,后续再进来的请求会被限流。
  • 请求速度等于令牌生成速度:此时流量处于平稳状态。
  • 请求速度小于令牌生成速度:说明此时系统的并发数并不高,请求能被正常处理

由于令牌桶有固定的大小,当请求速度小于令牌生成速度时,令牌桶会被填满。所以令牌桶能够处理突发流也就是在短时间内新增的流量系统能够正常处理,这是令牌桶的特性。

2.4 漏桶限流算法

漏桶限流算法的主要作用是控制数据注入网络的速度,平滑网络上的突发流量。

漏桶限流算法的原理如图7-6所示,在漏桶算法内部同样维护一个容器,这个容器会以恒定速度出水,不管上面的水流速度多快,漏桶水滴的流出速度始终保持不变。实际上消息中间件就使用了漏桶限流的思想,不管生产者的请求量有多大,消息的处理能力取决于消费者

在漏桶限流算法中,存在以下几种可能的情况

  • 请求速度大于漏桶流出水滴的速度:也就是请求数超出当前服务所能处理的极限,将会触发限流策
    略。
  • 请求速度小于或者等于漏桶流出水滴的速度,也就是服务端的处理能力正好满足客户端的请求量将正常执行。

漏桶限流算法和令牌桶限流算法的实现原理相差不大,最大的区别是漏桶无法处理短时间内的突发流量
漏桶限流算法是一种恒定速度的限流算法

三、服务熔断与降级

在微服务架构中,由于服务拆分粒度较细,会出现请求链路较长的情况 。如图7-7所示,用户发起一个请求操作,需要调用多个微服务才能完成;

在高并发场景中,这些依赖服务的稳定性对系统的影响非常大,比如某个服务因为网络延迟或者请求超时等原因不可用时,就会导致当前请求阻塞,如图7-8所示,一旦某个链路上被依赖的服务不可用,很可能出现请求堆积从而导致出现雪崩效应

3.1 服务熔断

所以,服务熔断就是用来解决这个问题的方案。服务熔断是指当某个服务提供者无法正常为服务调用者提供服务时,比如请求超时、服务异常等,为了防止整个系统出现雪崩效应,暂时将出现故障的接口隔离出来,断绝与外部接口的联系,当触发熔断之后,后续一段时间内该服务调用者的请求都会直接失败,直到目标服务恢复正常。

3.2服务降级需要有一个参考指标

服务降级需要有一个参考指标,一般来说有以下几种常见方案

  • 平均响应时间:比如1s内持续进入5个请求,对应时刻的平均响应时间均超过闻值,那么接下来在一个固定的时间窗口内,对这个方法的访问都会自动熔断。
  • 异常比例:当某个方法每秒调用所获得的异常总数的比例超过设定的闻值时,该资源会自动进入降级状态,也就是在接下来的一个固定时间窗口中,对这个方法的调用都会自动返回
  • 异常数量:和异常比例类似,当某个方法在指定时间窗口内获得的异常数量超过闯值时会触发熔断。

Sentinel也提供了熔断功能,在后续的章节中我们会演示如何通过Sentinel实现服务熔断

四 分布式限流架Sentinel

Sentinel是面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、服务降级、系统负载保护等多个维度来帮助我们保障微服务的稳定性。

在阿里巴巴内部有一句口号:"稳定压倒一切",稳定性是系统的基础能力,稳定性差的系统会出现服务超时或服务不可用,给用户带来不好的体验,从而对业务造成恶劣影响。所以系统稳定性是一条"红线",任何业务需求或技术架构升级都不应该越过它。

目前,Sentinel在阿里内部被广泛使用,为多年双11、双12、年货节618等大促活动保驾护航,并Sentinel开源以后也被很多互联网企业采用。

4.1 Sentinel的特性

如图7-9所示,Sentinel的特性非常多

  • 丰富的应用场景:几乎涵盖所有的应用场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制等。
  • 实时监控:Sentinel提供了实时监控功能。开发者可以在控制台中看到接入应用的单台机器秒级数据,甚至500台以下规模的集群汇总运行情况。
  • 开源生态支持:Sentinel提供开箱即用的与其他开源框架/库的整合,例如与Spring CloudDubbogRPC的整合。开发者只需要引入相应的依赖并进行简单的配置即可快速接入Sentinel。
  • SPI扩展点支持:Sentine提供了SPI扩展点支持,开发者可以通过扩展点来定制化限流规则,动态数据源适配等需求

4.2 Sentinel的组成

Sentinel分为两个部分:

  • 核心库(Java客户端):不依赖任何框架/库,能够运行于所有Jva运行时环境,同时对Dubbo、SpringCloud等框架也有较好的支持。
  • 控制台(Dashboard):基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

4.3 SentinelDashboard的部署

Sentinel提供一个轻量级的开源控制台,它支持机器发现,以及健康情况管理、监控(单机和集群)、规则管理和推送的功能。

SentinelDashboard的安装步骤如下

  • 在GitHub中Sentinel的源码仓库中:
  1. 直接下载源码通过mvnclean package自己构建
  2. 直接在Release页面下载已经构建好的Jar
  • 通过以下命令启动控制台:
bash 复制代码
java-Dserver.port=7777 -Dcsp,sentinel.dashboard.server=localhost;7777 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

其中,启动参数的含义如下。

-Dserver.port:指定Sentinel控制台的访问端口,默认是8080

-Dcsp.sentineldashboard.server:指定Sentinel Dashboard控制台的IP地址和端口,这里进行设置的目的是把自己的限流数据暴露到监控平台。

-Dprojectname:设置项目名称

4.4Sentinel的基本应用

使用Sentinel的核心库来实现限流,主要分以下几个步骤。

  • 定义资源
  • 定义限流规则。
  • 检验规则是否生效

所谓的资源,就是需要通过限流保护的最基本元素,比如一个方法。有了需要保护的资源之后,就可以针对该资源设置流量控制规则了。

下面先通过一个简单的案例来演示一下Sentinel的基本使用方法,让读者对Sentinel有一个基本的认识。

4.4.1Sentinel实现限流首先,引入Sentinel的核心库:

xml 复制代码
<dependency>
  <groupId>com.alibaba,csp</groupId>
  <artifactId>sentinel-core</artifactId>
  <version>1.7.1</version>
</dependency>

然后,定义一个普通的业务方法

在doSomething方法中,通过使用Sentinel中的SphU.entry("doSomething")定义一个资源来实现流控的逻辑,它表示当请求进入doSomething方法时,需要进行限流判断。如果抛出BlockException异常,则表示触发了限流。接着,针对该保护的资源定义限流规则:

针对资源doSomething,通过initFlowRules设置限流规则,其中参数的含义如下

  • Grade:限流闻值类型,QPS模式(1)或并发线程数模式(0)。
  • count:限流闻值
  • resource:设置需要保护的资源。这个资源的名称必须和SphU.entry中使用的名称保持一致上述代码的意思是,针对doSomething方法,每秒最多允许通过20个请求,也就是QPS为20最后,通过main方法进行测试
Sentinel 限流日志查看

从日志中可以看出,这个程序每秒稳定输出(doSomething)20次,和规则中预先设定的闻值是一样的,而被拒绝的请求每秒最高达50多万次。

4.4.2 资源的定义

Sentinel还可以使用@SentinelResource支持注解的方式来定义资源,具体实现方式如下:

4.4.3Sentinel资源保护规则

Sentinel支持多种保护规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则、热点参数规则。

限流规则在前面的案例中简单使用过,先通过FlowRule来定义限流规则,然后通过FlowRuleManagerloadRules来加载规则列表。完整的限流规则设置代码如下:

其中,FlowRule部分属性的含义说明如下。

  • limitApp:是否需要针对调用来源进行限流,默认是default,即不区分调用来源
  • strategy:调用关系限流策略一一直接、链路、关联
  • controlBehavior:流控行为,包括直接拒绝排队等待、慢启动模式,默认是直接拒绝
  • clusterMode:是否是集群限流,默认为否下面基于这几个参数的含义做一个详细分析。
4.4.3.1基于并发数和QPS的流量控制

Sentinel流量控制统计有两种类型,通过grade属性来控制:

  • 并发线程数(FLOW_GRADE_THREAD)。
  • QPS(FLOW_GRADEQPS)
并发线程数

并发线程数限流用来保护业务线程不被耗尽 。比如,A服务调用B服务,而B服务因为某种原因导致服务不稳定或者响应延迟,那么对于A服务来说,它的吞吐量会下降,也意味着占用更多的线程(线程阻塞之后一直末释放),极端情况下会造成线程池耗尽
针对这种问题,一个常见的解决方案是通过不同业务逻辑使用不同的线程池来隔离业务自身的资源争抢问题,但是这个方案同样会造成线程数量过多带来的上下文切换问题
Sentinel并发线程数限流就是统计当前请求的上下文线程数量,如果超出闻值,新的请求就会被拒绝。

QPs

QPS(Queries PerSecond)表示每秒的查询数,也就是一台服务器每秒能够响应的查询次数当QPS达到限流的闻值时,就会触发限流策略。

4.4.3.2 QPS流量控制行为

当QPS超过闻值时,就会触发流量控制行为,这种行为是通过controlBehavior来设置的,它包含:

  • 直接拒绝(RuleConstant.CONTROL_BEHAVIORDEFAULT);
  • Warm Up( RuleConstant.CONTROL_BEHAVIOR_WARM_UP),冷启动(预热);
  • 匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
  • 冷启动+匀速排队(RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER)。
直接拒绝

直接拒绝是默认的流量控制方式,也就是请求流量超出闻值时,直接抛出一个FowException。

冷启动(预热) Warm Up

Warm Up是一种冷启动(预热)方式。当流量突然增大时,也就意味着系统从空闲状态突然切换到繁忙状态,有可能会瞬间把系统压垮。当我们希望请求处理的数量逐步递增,并在一个预期时间之后达到允许处理请求的最大值时,WarmUp就可以达到这个目的。

如图7-10所示,当前系统所能够处理的最大并发数是480,首先,在最下面标记的位置,系统一直处于空闲状态,接着请求量突然直线升高。这个时候系统并不是直接将QPS拉到最大值,而是在一定时间内逐步增加闻值,而中间这段时间就是一个系统逐步预热的过程

匀速排队

匀速排队的方式会严格控制请求通过的间隔时间,也就是让请求以均匀的速度通过,其实相当于前面讲的漏桶限流算法。

如图7-11所示,当QPS=2时,意味着每隔500ms才允许通过下一个请求。这种方式的好处是可以处理间隔性突发流量。

4.4.3.3调用关系流量策略

调用关系包括调用方和被调用方,一个方法又可能会调用其他方法,形成一个调用链。所谓的调用关系流量策略,就是根据不同的调用维度来发流量控制。

  • 根据调用方限流
  • 根据调用链路入口限流
  • 具有关系的资源流量控制(关联流量控制)。
调用方限流

所谓调用方限流,就是根据请求来源进行流量控制,我们需要设置limitApp属性来设置来源信息,它有三个选项。

  • default:表示不区分调用者,也就是任何访问调用者的请求都会进行限流统计
  • {some_origin_name}:设置特定的调用者,只有来自这个调用者的请求才会进行流量统计和控制。
  • other:表示针对除{some_origin_name)外的其他调用者进行流量控制

由于同一个资源可以配置多条规则,如果多个规则设置的limitApp不一样,那么规则的生效顺序为:{someorigin name}->other->default

根据调用链路入口限流

一个被限流保护的方法,可能来自不同的调用链路。比如针对资源nodeA,入口Entrance1和入口Entrance2都调用了资源nodeA,那么Sentinel允许只根据某个入口来进行流量统计。比如我们针对nodeA资源,设置针对Entrance1入口的调用才会统计请求次数。它在一定程度上有点类似于调用方限流。

关联流量控制

当两个资源之间存在依赖关系或者资源争抢时,我们就说这两个资源存在关联。这两个存在依赖关系的资源在执行时可能会因为某一个资源执行操作过于频繁而影响另外一个资源的执行效率**,所以关联流量控制(流控)就是限制其中一个资源的执行流量。**

4.4.3 Sentinel实现服务熔断

Sentinel实现服务熔断操作的配置和限流类似,不同之处在于限流采用的是FlowRule,而熔断中采用的是DegradeRule,配置代码如下:

其中,有几个属性说明如下。

  • grade:熔断策略,支持秒级RT、秒级异常比例、分钟级异常数。默认是秒级RT
  • timeWindow:熔断降级的时间窗口,单位为s。也就是触发熔断降级之后多长时间内自动熔断.
  • rtSlowRequestAmount:在RT模式下,1内持续多少个请求的平均RT超出闻值后触发熔断,默
    认值是5。
  • minRequestAmount:触发的异常熔断最小请求数,请求数小于该值时即使异常比例超出闻值也不会触发熔断,默认值是5。
Sentinel提供三种熔断策略

Sentinel提供三种熔断策略,对于不同策略,参数的含义也不相同

  • 平均响应时间(RuleConstant.DEGRADEGRADERT):如果1s内持续进入5个请求对应的平均响应时间都超过了闯值(count,单位为ms),那么在接下来的时间窗口(timeWindow,单位为s)内,对这个方法的调用都会自动熔断,抛出DegradeException。

Sentinel默认统计的RT上限是4900ms,如果超出此闻值都会算作4900ms,如果需要修改,则通过启动参数-Dcspsentinelstatisticmaxrt=xxx来配置

  • 异常比例(RuleConstantDEGRADE_GRADEEXCEPTION_RATIO):如果每秒资源数>=minRequestAmount(默认值为5),并且每秒的异常总数占总通过量的比例超过闻值count (count的取值范围是0.0,1.0,代表0%~100%),则资源将进入降级状态。同样,在接下来的timeWindow之内,对这个方法的调用都会自动触发熔断。
  • 异常数(RuleConstant.DEGRADEGRADE EXCEPTION COUNT):当资源最近一分钟的异常数目超过闻值之后,会触发熔断。需要注意的是,如果timeWindow小于60,则结束熔断状态后仍然可能再进入熔断状态。

至此,大家对于Sentinel应该有一个基本的认识了,在接下来的内容中,笔者会围绕Sentinel在SpringCloud生态下的使用进行展开,帮助读者加深对Sentinel的理解。

4.5 Spring Cloud集成Sentinel实践

Spring Cloud Alibaba默认为Sentine整合了Servlet、RestTemplate、 FeignClient和Spring WebFlux。它不仅补全了Hystrix在Servlet和RestTemplate这一块的空白,而且还完全兼容了Hystrix在FeignClient中限流降级的用法,并支持灵活配置和调整流控规则。

下面主要演示Sentinel如何实现Spring Cloud应用的限流操作

4.5.1 Sentinel接入Spring Cloud

  • 创建一个基于Spring Boot的项目,并集成GreenwichSR2版本的Spring Cloud依赖
  • 添加Sentinel依赖包。
xml 复制代码
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
	<version>2.1.1.RELEASE</version>
</dependency>
  • 创建一个REST接口,并通过@SentinelResource配置限流保护资源

    在上述代码中,配置限流资源有几种情况:
    • Sentinel starter在默认情况下会为所有的HTTP服务提供限流埋点,所以如果只想对HTTP服务进行限流,那么只需要添加依赖即可,不需要修改任何代码。
    • 如果想要对特定的方法进行限流或者降级,则需要通过@SentinalResouce注解来实现限流资源的定义。
    • 可以通过SphU.entry()方法来配置资源
  • 手动配置流控规则,可以借助Sentinel的InitFunc SPI扩展接口来实现,只需要实现自己的InitFunc接口,并在init方法中编写规则加载的逻辑即可。

SPI是扩展点机制,如果需要被Sentinel加载,那么还要在resource目录下创建META-INF/services/comalibaba.csp.sentinelinit.InitFunc文件,文件内容就是自定义扩展点的全路径

java 复制代码
com.gupaoedu.book.springcloud.sentinel.springcloudsentinelsample.FlowRuleInitFunc

按照上述配置好之后,在初次访问任意资源的时候,Sentinel就会自动加载hello资源的流控规则。

上述配置过程是基于手动配置来加载流控规则的,还有一种方式就是通过Sentinel Dashboard来进行配置

4.5.2基于SentinelDashboard来实现流控配置

基于Sentinel Dashboard来配置流控规则,可以实现流控规则的动态配置,执行步骤如下

  • 启动Sentinel Dashboard
  • 在applicationyml中增加如下配置

    spring.cloudsentineltransport.dashboard指向的是Sentinel Dashboard的服务器地址,可以实现流控数据的监控和流控规则的分发。
  • 提供一个REST接口,代码如下

    此处不需要添加任何资源埋点,在默认情况下SentinelStarter会对所有HTTP请求进行限流
  • 启动服务后,此时访问http://ocalhost:8080/dash,由于没有配置流控规则,所以不存在限流行为。
    至此,Spring Cloud集成Sentinel就配置完成了,接下来,进入Sentinel Dashboard来实现流控规则的配置,
  • 访问http://192168.216.128:7777/进入Sentinel Dashboard
  • 进入springapplication.name对应的菜单,访问"簇点链路",如图7-12所示,在该列表下可以看到/dash这个REST接口的资源名称。
  • 针对/dash这个资源名称,可以在图7-12中最右边的操作栏单击"流控"按钮设置流控规则,如图7-13所示。

新增规则中的所有配置信息,实际就是FlowRule中对应的属性配置,为了演示效果,把单机闻值设置为1。

bash 复制代码
Blocked by Sentinel(flow limiting)

4.5.3自定义URL限流异常

在默认情况下,URL触发限流后会直接返回

Blocked by Sentinel(flow limiting)

在实际应用中,大都采用JSON格式的数据,所以如果希望修改触发限流之后的返回结果形式,则可以通过自定义限流异常来处理,实现UrlBlockHandler并且重写blocked方法:

还有一种场景是,当触发限流之后,我们希望直接跳转到一个降级页面,可以通过下面这个配置来实现

spring.cloud.sentinel.servlet.block-page=(url)

4.5.4 URL资源清洗

Sentinel中HTTP服务的限流默认由Sentinel-Web-Servet包中的CommonFilter来实现,从代码中可以看到,这个Filter会把每个不同的URL都作为不同的资源来处理。

在下面这段代码中,提供了一个携带id)参数的REST风格API,对于每一个不同的id),URL也都不一样,所以在默认情况下Sentinel会把所有的URL当作资源来进行流控。

这会导致两个问题:

  • 限流统计不准确,实际需求是控制dlean方法总的QPS,结果统计的是每个URL的QPS。
  • 导致Sentinel中资源数量过多,默认资源数量的闻值是6000,对于多出的资源规则将不会生效。

针对这个问题可以通过UrlCleaner接口来实现资源清洗,也就是对于/dean/{id};这个URL,我们可以统一归集到/clean/*资源下,具体配置代码如下,实现UrCleaner接口,并重写clean方法即可。

4.6 Sentinel集成Nacos实现动态流控规则

通过前面的案例可以发现,Sentinel的理念是只需要开发者关注资源的定义,它默认会对资源进行流控。当然,我们还需要对定义的资源设置流控规则,前面演示了两种方式:

  • 通过FlowRuleManagerloadRules(List rules)手动加载流控规则
  • 在Sentinel Dashboard上针对资源动态创建流控规则。

针对第一种设置方式,如果接入Sentinel Dashboard,那么同样支持动态修改流控规则。但是,这里会存在一个问题,基于Sentinel Dashboard所配置的流控规则,都是保存在内存中的,一目应用重启,这些规则都会被清除。为了解决这个问题,Sentinel提供了动态数据源支持。

目前,Sentine支持Consul、ZooKeeper、Redis、Nacos、Apolloetcd等数据源的扩展。下面通过一个案例演示SpringCloud Sentinel集成Nacos实现动态流控规则,配置步骤如下

添加Nacos数据源的依赖包。

xml 复制代码
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
	<version>1.7.0</version>
</dependency>
  • 创建一个REST接口,用于测试

  • 在application.yml中添加数据源配置

    部分配置说明如下。

    • datasource:目前支持redis、apollokflenacos,选择什么类型的数据源就配置相应的key即可。
    • data-id:可以设置成$springapplicationname),方便区分不同应用的配置。
    • rule-type:表示数据源中规则属于哪种类型,如flow、degrade、param-flow、gw-flow等.
    • data-type:指配置项的内容格式,Spring CloudAlibaba Sentinel提供了JSON和XML两种格式。如果需要自定义,则可以将值配置为custom,并配置converter-class指向converter类
  • 登录Nacos控制台,创建流控配置规则,配置信息如图7-14所示。

  • 最后,登录Sentinel Dashboard,找到执行项目名称菜单下的"流控规则",就可以看到在Nacos上所配置的流控规则已经被加载了,如图7-15所示。
  • 当我们在Nacos的控制台上修改流控规则后,可以同步在Sentinel Dashboard上看到流控规则的变;

通过上述配置整合之后,接口流控规则的动态修改就存在于以下两个地方

  • Sentinel Dashboard.
  • Nacos控制台。

那么问题就来了,在Nacos控制台上修改流控规则,虽然可以同步到Sentinel Dashboard,但是Nacos此时应该作为一个流控规则的持久化平台,所以正常的操作过程应该是开发者在Sentinel Dashboard上修改流控规则后同步到Nacos上,遗憾的是,目前Sentinel Dashboard不支持该功能。

所以,Nacos名义上是"Datasource",但实际上充当的仍然是配置中心的角色,开发者可以在Nacos控制台上动态修改流控规则并实现规则同步。在实际开发中,很难避免在不清楚情况的前提下,部分开发者通过Sentinel Dashboard来管理流控规则,部分开发者通过Nacos来管理流控规则,这将会导致非常严重的问题

如图7-16所示,Nacos在此处扮演的角色应该是一个"Datasource",所以笔者强烈建议大家不要在Nacos上修改流控规则,因为这种修改的危险系数很高,毕竟Nacos的UI并不是专门负责流控规则维护的。

这也就意味着流控规则的管理应该集中在Sentinel Dashboard上,接下来的问题就很简单了,我们需要实现Sentinel Dashboard来动态维护流控规则并同步到Nacos上,目前官方还没有提供支持,但是大家可以自己来实现。

4.7 SentinelDashboard集成Nacos实现规则同步

Sentinel Dashboard的"流控规则"下的所有操作,都会调用Sentinel-Dashboard源码中的FlowControllerV1类,这个类中包含流控规则本地化的CRUD操作。

另外,在comalibabacspsentineldashboard.controllerv2包下存在一个FlowControllerV2类这个类样提供流控规则的CRUD,和V1版本不同的是,它可以实现指定数据源的规则拉取和发布,部分代码如下:

4.7.1SentinelDashboard源码修改

修改SentinelDashboard的源码,具体的实现步骤如下

在GitHub中下载Sentinel Dashboard 171的源码

  • 使用IDEA工具打开SSentinel homel/sentinel-dashboard工程
  • 在pomxml中把sentinel-datasource-nacos依赖的注释掉

4.7.2 SentinelDashboard规则数据同步

对于应用程序来说,需要改动的地方比较少,只要注意配置文件中data-id的命名要以-sentinel-flow结尾即可,因为在Sentinel Dashboard中我们写了一个固定的后缀

4.8Dubbo集成Sentinel实现限流

Sentinel提供了与Dubbo整合的模块Sentinel Apache Dubbo Adapter,可以针对服务提供方和服务消费方进行流控,在使用的时候,只需要添加以下依赖。

spring-coud-starter-alibaba-sentinel目前无法支持Dubbo服务的限流,所以针对Dubbo服务的限流只能使用sentinel-apache-dubbo-adapter。这个适配组件并没有自动接入Sentinel Dashboard,需要通过以下步骤来进行接入。

入sentinel-transport-simple-http依赖,这个依赖可以上报应用相关信息到控制台。

bash 复制代码
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.7</version></dependency>

·添加启动参数

bash 复制代码
-Djava.net.preferIPv4Stack=true
-Dcsp.sentinel.api.port=8720Dcsp.sentinel.dashboard.server=192.168216128:7777
-Dproject.name=spring-cloud.sentinel-dubbo.provider

参数配置说明如下

  • Djava.net.preferIPv4Stack:表示只支持IPv4。
  • Dcspsentinelapi.port:客户端的port,用于上报应用的信息
  • Dcspsentinel.dashboardserver : Sentinel Dashboard地
  • Dprojectname:应用名称,会在Sentinel Dashboard右侧展示

登录SentinelDashboard之后,进入"簇点链路",就可以看到如图7-18所示的资源信息

需要注意的是,限流可以通过服务接口或服务方法设置

  • 服务接口:resourceName为接口的全限定名,在图7-18中的体现为comgupaoedu.sentineldubbo.IHelloService。
  • 服务方法:resourceName为接口全限定名:法名,如com.gupaoedusentinel.dubboIHelloService : sayHello ( )

4.8.2 Dubbo服务限流规则配置

Dubbo限流规则同样可以通过以下集中方式来实现

  • Sentinel Dashboard
  • FlowRuleManager.loadRules(List rules)

前面我们讲过基于Sentinel Dashboard来实现流控规则配置,最终持久化到Nacos中,然而规则的持久化机制在Spring Cloud Sentinel中是自动实现的,在Sentinel Apache Dubbo Adapter组件中并没有实现该功能。下面演示一下在Dubbo服务中如何实现规则的持久化。

  • 添加sentinel-datasource-nacos的依赖

4.9 Sentinel热点限流

热点数据表示经常访问的数据,在有些场景中我们希望针对这些访问频次非常高的数据进行限流,比如针对一段时间内频繁访问的用户IP地址进行限流,或者针对频繁访问的某个用户ID进行限流。

Sentinel提供了热点参数限流的策略,它是一种特殊的限流,在普通限流的基础上对同一个受保护的资源区根据请求中的参数分别处理,该策略只对包含热点参数的资源调用生效。热点限流在以下场景中使用较多。

  • 服务网关层:例如防止网络爬虫和恶意攻击,一种常用方法就是限制爬虫的IP地址,客户端IP地址就是一种热点参数
  • 写数据的服务:例如业务系统提供写数据的服务,数据会写入数据库之类的存储系统。存储系统的底层会加锁写磁盘上的文件,部分存储系统会将某一类数据写入同一个文件。如果底层写同一文件,会出现抢占锁的情况,导致出现大量超时和失败。出现这种情况时一股有两种解决办法:修改存储设计、对热点参数限流

Sentinel通过LRU策略结合滑动窗口机制来实现热点参数的统计,其中,LRU策略可以统计单位时间内最常访问的热点数据,滑动窗口机制可以协助统计每个参数的QPS

如图7-19所示,Sentinel会根据请求的参数来判哪些是热点参数,然后通过热点参数限流规则,将QSP超过设定闯值的请求阻塞。

4.9.1热点参数限流的使用

针对不同的热点参数,需要通过SphU.entry(resourceName,EntryTypeIN,id)方法设置,其最后一个参数是一个数组,有多个热点参数时就按照次序依次传入,该配置表示后续会针对该参数进行热点限流

下面针对上述资源sayHelo设置热点参数限流规则,通过ParamFlowRuleManagerloadRules方法加载热点

4.9.2@SentinelResource热点参数限流

4.10 Sentinel的工作原理

Sentinel的核心分为三部分:工作流程、数据结构和限流算法,工作原理(整体架构)如图7-21所示

可以看出,调用链路是Sentinel的工作主流程,由各个Slot插槽组成,将不同的Slot按照顺序串在一起(责任链模式),从而将不同的功能(限流、降级、系统保护)组合在一起Sentinel中各个slot承担了不同的职责,例如LogSlot负责记录日志StatisticSlot负责统计指标数据、FowSlot负责限流等。这是一种职责分离的设计,每个模块更聚焦于实现某个功能。

在Sentinel中,所有的资源都对应一个资源名称(resourceName),每次访问该资源都会创建一个Entry对象,在创建Entry的同时,会创建一系列功能槽(Slot Chain),这些槽会组成一个责任链,每个槽负责不同的职责

  • NodeSelectorSlot:负责收集资源的调用路径,以树状结构存储调用栈,用于根据调用路径来限流降级。
  • ClusterBuilderSlot:负责创建以资源名维度统计的ClusterNode,以及创建每个CusterNode下按调用来源origin划分的StatisticNode。
  • LogSlot:在出现限流、熔断、系统保护时负责记录日志
  • AuthoritySlot:权限控制,支持黑名单和白名单两种策略
  • SystemSlot:控制总的入口流量,限制条件依次是总QPS、总线程数、RT闻值、操作系统当前load1、操作系统当前CPU利用率
  • FlowSlot:根据限流规则和各个Node中的统计数据进行限流判断。
  • DegradeSlot:根据熔断规则和各个Node中的统计数据进行服务降级。
  • StatisticSlot:统计不同维度的请求数、通过数、限流数、线程数等runtime信息,这些数据存储在DefaultNode OriginNode和ClusterNode中。

7.11Spring Cloud Sentinel工作原理分析

在Spring Cloud中使用Sentinel实现限流的场景中,我们并不需要任何配置,Sentinel会自动保护所有的HTTP服务,本节重点讲解该实现机制。

在Spring-Cloud-Starter-Alibaba-Sentinel包中,我们知道Starter组件会用到自动装配,所以直接找到META-INF/spring.factories文件。

这里EnableAutoConfiguration自动装配了5个配置类

  • SentinelWebAutoConfiguration是对Web Servlet环境的支持
  • SentinelWebFluxAutoConfiguration是对Spring WebFlux的支持
  • SentinelEndpointAutoConfiguration暴露Endpoint信息
  • SentinelFeignAutoConfiguration用于适配Feign组件
  • SentinelAutoConfiguration支持对RestTemplate的服务调用使用Sentinel进行保护。

在SentinelWebAutoConfiguration配置类中,自动装配了一个FilterRegistrationBean,主要作用是注册个CommonFilter,并且默认情况下通过"/*"规则拦截所有的请求;

4.12Sentinel核心源码分析

在本节中,主要针对Sentinel中的一些核心源码进行分析,帮助读者更好地理解Sentinel的实现原理Sentinel源码的版本为1.71,读者可以自行从GitHub上下载,源码模块如下。

  • sentinel-adapter:负责针对主流开源框架进行限流适配,比如DubbogRPCZuul等。
  • sentinel-core:Sentinel核心库,提供限流、降级等实现。
  • sentinel-dashboard:控制台模块,提供可视化监控和管理。
  • sentinel-demo:官方案例
    ·sentinel-extension:实现不同组件的数据源扩展,比如Nacos、ZooKeeper、Apollo等·sentinel-transport:通信协议处理模块。

限流及熔断的核心逻辑都是在sentinel-core中实现的,所以我们主要针对sentinel-core模块进行分析。

4.12.1限流的源码实现

限流的判断逻辑是在Sphu.entry方法中实现的,这个方法往下执行最终会进入Sphentry(),Sph的默认实现是CtsPh。限流方法的主要逻辑是:

  • 校验全局上下文Context。
  • 通过lookProcessChain方法获得一个ProcessorSlot链。
  • 执行chainentry,如果没有被限流,则返回entry对象,否则抛出BlockException。

4.12.2实时指标数据统计

限流的核心是限流算法的实现,Sentinel默认采用滑动窗口算法来实现限流,具体的指标数据统计由StatisticSlot实现。

4.12.3服务降级的实现原理

服务降级是通过DegradeSlot来实现的,它会根据用户配置的降级规则和系统运行时各个Node中的统计数据进行降级判断。

4.13本章小结

本章花了较长的篇幅讲解Sentinel的使用和原理,其中包括:

  • 限流的产生背景和常见的限流算法。
  • Sentinel的基本应用。
  • 如何将Sentinel集成到Spring Cloud及Dubbo中
  • Sentinel Dashboard的使用及流控规则的持久化。
  • Sentinel的工作原理和核心代码分析

整体来看,Sentinel就两个部分,核心库和Sentinel Dashboard,核心库主要提供基础的限流及熔断的支持,而Sentinel Dashboard提供可视化监控及流控规则的管理。

同时,Sentinel核心库提供了非常丰富的应用场景,如秒杀场景中的突发流量控制、消息的削峰填谷、集群流量控制、熔断降级等。并且对主流的框架提供了很好的适配,使得开发者可以更容易地集成Sentinel。

相关推荐
蝎子莱莱爱打怪2 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking3 天前
Java微服务练习方式
java·后端·微服务
米丘6 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质9 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
霸道流氓气质9 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
地瓜伯伯9 天前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
Devin~Y9 天前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
递归尽头是星辰9 天前
AI 访问数据仓库:从直连到微服务化
数据仓库·人工智能·微服务·dataagent·ai数据治理
就改了10 天前
Windows 环境 SkyWalking 完整实操教程
windows·微服务·skywalking
至乐活着10 天前
Docker Compose多服务编排实战:从零搭建Node.js+MySQL+Redis全栈应用
docker·微服务·devops·容器编排·compose