Spring Cloud Alibaba 微服务框架 Sentinel:微服务限流和熔断框架
2022-05-21 12:10:45 1 举报
AI智能生成
Spring Cloud Alibaba 微服务框架 Sentinel 微服务限流和熔断框架
作者其他创作
大纲/内容
限流熔断概述
为什么要限流?
保护服务不被突发流量压垮
怎么限流?
限流算法
计数器算法
滑动时间窗口算法
令牌桶算法
漏桶算法
降级指标(熔断策略)
平均响应时间
根据异常数量
根据异常比例
限流规则
流量统计规则
并发线程(线程池、信号量)
QPS
调用来源规则
调用关系规则
热点参数规则
流控行为
直接拒绝
匀速排队
冷启动(预热)
冷启动+匀速排队
服务限流的作用及实现
限流的主要目的
通过限制并发访问数或者限制一个时间窗口内允许处理的请求数量来保护系统
一旦达到限制数量则对当前请求进行处理采取对应的拒绝策略
跳转到错误页面拒绝请求
进入排队系统
降级
实际开发过程中的限流
在Nginx层添加限流模块限制平均访问速度。
通过设置数据库连接池、线程池的大小来限制总的并发数。
通过Guava提供的Ratelimiter限制接口的访问速度。
TCP通信协议中的流量整形。
常见的限流实现算法
计数器算法
原理:在指定周期内累加访问次数,当访问次数达到设定的阈值时,触发限流策略,当进入下一个时间周期时进行访问次数的清零。
缺点:存在一个临界问题
滑动窗口算法
原理:在固定窗口中分割出多个小时间窗口,分别在每个小时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口。 最终只需要统计滑动窗口范围内的所有小时间窗口总的计数即可。
优点:解决计数器算法的临界问题
Sentinel就是采用滑动窗口算法来实现限流的
令牌桶限流算法
原理:系统会以一个恒定速度往固定容量的令牌桶中放入令牌,如果此时有客户端请求过来,则需要先从令牌桶中拿到令牌以获得访问资格
使用场景
网络流量整形(Traffic Shaping)
速率限制(Rate Limiting)
请求获取令牌的3种情况
1.请求速度大于令牌生成速度:那么令牌会很快被取完,后续再进来的请求会被限流
2.请求速度等于令牌生成速度:此时流量处于平稳状态
3.请求速度小于令牌生成速度:说明此时系统的并发数并不高,请求能被正常处理
特点:能够处理突发流量,也就是在短时间内新增的流量系统能够正常处理
漏桶限流算法
原理:在漏桶算法内部维护一个容器,这个容器会以恒定速度出水,不管上面的水流速度多快,漏桶水滴的流出速度始终保持不变
使用情景:控制数据注入网络的速度,平滑网络上的突发流量
请求进入漏桶的2种情况
1.请求速度大于漏桶流出水滴的速度:也就是请求数超出当前服务所能处理的极限,将会触发限流策略
2.请求速度小于或者等于漏桶流出水滴的速度,也就是服务端的处理能力正好满足客户端的请求量,将正常执行
与令牌桶限流算法的区别:无法处理短时间内的突发流量,漏桶限流算法是一种恒定速度的限流算法
服务熔断与降级
服务熔断:指当某个服务提供者无法正常为服务调用者提供服务时,比如请求超时、服务异常等,为了防止整个系统出现雪崩效应, 暂时将出现故障的接口隔离出来,断绝与外部接口的联系,当触发熔断之后,后续一段时间内该服务调用者的请求都会直接失败,直到目标服务恢复正常。
服务降级常见参考指标方案
平均响应时间:比如1s内持续进入5个请求,对应时刻的平均响应时间均超过阈值,那么接下来在一个固定的时间窗口内,对这个方法的访问都会自动熔断。
异常比例:当某个方法每秒调用所获得的异常总数的比例超过设定的阈值时,该资源会自动进入降级状态,也就是在接下来的一个固定时间窗口中,对这个方法的调用都会自动返回。
异常数量:和异常比例类似,当某个方法在指定时间窗口内获得的异常数量超过阈值时会触发熔断。
分布式限流框架Sentinel
作用:面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、服务降级、系统负载保护等多个维度来帮助我们保障微服务的稳定性
特性
丰富的应用场景:几乎涵盖所有的应用场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制等。
实时监控:Sentinel提供了实时监控功能。开发者可以在控制台中看到接入应用的单台机器秒级数据,甚至500台以下规模的集群汇总运行情况。
开源生态支持:Sentinel提供开箱即用的与其他开源框架/库的整合,例如与Spring Cloud、Dubbo、gRPC的整合。
SPI扩展点支持:Sentinel提供了SPI扩展点支持,开发者可以通过扩展点来定制化限流规则,动态数据源适配等需求。
Sentinel Dashboard 功能点
机器发现
健康情况管理
监控(单机和集群)
规则管理
推送规则
Sentinel的基本应用
基本使用步骤
1.定义资源
2.定义限流规则
3.检验规则是否生效
资源定义方式
Sph0方式
@SentinelResource方式
还有其他方式
资源保护规则
流量控制规则
熔断降级规则
系统保护规则
来源访问控制规则
热点参数规则
定义限流规则
FlowRule 参数说明
grade:流量控制统计,包含2种类型
FLOW_GRADE_THREAD:并发线程数
作用:并发线程数限流用来保护业务线程不被耗尽
方案
方案1
不同业务逻辑使用不同的线程池来隔离业务自身的资源争抢问题
问题:会造成线程数量过多带来的上下文切换问题,过多的线程池会非常影响性能
方案2
统计当前请求的上下文线程数量(并发线程数-信号量隔离),如果超出阈值,新的请求就会被拒绝(Sentinel使用)
问题:隔离没有使用线程池隔离强度高,不支持异步调用,线程处理业务时间长阻塞后面请求(sentinel有超时机制)
思考:sentinel认为服务之间请求在内网,大部分能快速处理完成,结合基于响应时间的熔断降级模式,
可以在不稳定资源的平均响应时间比较高的时候自动降级,防止过多的慢调用占满并发数,影响整个系统
而Hystrix的信号量隔离比较简单,无法对慢调用自动进行降级,只能等待客户端自己超时,因此仍然可能会出现级联阻塞的情况
FLOW_GRADE_QPS:QPS(每秒查询数)
作用:当QPS达到限流的阈值时,就会触发限流策略
limitApp:是否需要针对调用来源进行限流,3种方式
default:表示不区分调用者,也就是任何访问调用者的请求都会进行限流统计(默认)
{some_origin_name}:设置特定的调用者,只有来自这个调用者的请求才会进行流量统计和控制
other:表示针对除{some_origin_name}外的其他调用者进行流量控制
strategy:调用关系限流策略,3种策略
根据调用方限流:根据请求来源进行流量控制,我们需要设置limitApp属性来设置来源信息
根据调用链路入口限流
一个被限流保护的方法,可能来自不同的调用链路。比如针对资源nodeA,入口Entrance1和入口Entrance2都调用了资源nodeA,
那么Sentinel允许只根据某个入口来进行流量统计。
比如我们针对nodeA资源,设置针对Entrance1入口的调用才会统计请求次数。它在一定程度上有点类似于 调用方限流 。
具有关系的资源流量控制(关联流量控制)
当两个资源之间存在依赖关系或者资源争抢时,我们就说这两个资源存在关联。
这两个存在依赖关系的资源在执行时可能会因为某一个资源执行操作过于频繁而影响另外一个资源的执行效率,
所以关联流量控制(流控)就是限制其中一个资源的执行流量。
controlBehavior:流控行为,包含4种模式
直接拒绝:RuleConstant.CONTROL_BEHAVIOR_DEFAULT(默认)
请求流量超出阈值时,直接抛出一个FlowException
匀速排队:RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
定义:匀速排队的方式会严格控制请求通过的间隔时间,也就是让请求以均匀的速度通过,其实相当于前面讲的漏桶限流算法
优点:可以处理间隔性突发流量
冷启动(预热):RuleConstant.CONTROL_BEHAVIOR_WARM_UP
场景:当流量突然增大时,也就意味着系统从空闲状态突然切换到繁忙状态,有可能会瞬间把系统压垮
作用:请求处理的数量逐步递增,并在一个预期时间之后达到允许处理请求的最大值时
说明:当前系统所能够处理的最大并发数是480,首先,在最下面标记的位置,系统一直处于空闲状态,接着请求量突然直线升高。 这个时候系统并不是直接将QPS拉到最大值,而是在一定时间内逐步增加阈值,而中间这段时间就是一个系统逐步预热的过程。
冷启动+匀速排队:RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER
clusterMode:是否是集群限流,默认为否
FlowRuleManager.loadRules 加载规则
实现服务熔断
DegradeRule 参数说明
grade:熔断策略,3种策略
平均响应时间(RuleConstant.DEGRADE_GRADE_RT)(默认)
异常比例(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
异常数(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
timeWindow:熔断降级的时间窗口,单位为s。也就是触发熔断降级之后多长时间内自动熔断。
rtSlowRequestAmount:在RT模式下,1s内持续多少个请求的平均RT超出阈值后触发熔断,默认值是5。
minRequestAmount:触发的异常熔断最小请求数,请求数小于该值时即使异常比例超出阈值也不会触发熔断,默认值是5。
Spring Cloud集成Sentinel实践
Sentinel优点
默认为Sentinel整合了Servlet、RestTemplate、FeignClient和Spring WebFlux
不仅补全了Hystrix在Servlet和RestTemplate这一块的空白,而且还完全兼容了Hystrix在FeignClient中限流降级的用法
并支持灵活配置和调整流控规则
Sentinel接入Spring Cloud
创建一个基于Spring Boot的项目,并集成Greenwich.SR2版本的Spring Cloud依赖
添加Sentinel依赖包
创建一个REST接口,并通过@SentinelResource配置限流保护资源
Sentinel Starter在默认情况下会为所有的HTTP服务提供限流埋点, 所以如果只想对HTTP服务进行限流,那么只需要添加依赖即可,不需要修改任何代码
如果想要对特定的方法进行限流或者降级,则需要通过@SentinalResouce注解来实现限流资源的定义
可以通过SphU.entry()方法来配置资源
手动配置流控规则,可以借助Sentinel的InitFunc SPI扩展接口来实现,
只需要实现自己的InitFunc接口,并在init方法中编写规则加载的逻辑即可
SPI是扩展点机制,如果需要被Sentinel加载,那么还要在resource目录下创建 META-INF/services/com.alibaba.csp.sentinel.init.InitFunc文件,文件内容就是自定义扩展点的全路径。
启动服务后,访问http://localhost:8080/say方法,当访问频率超过设定阈值时,就会触发限流
基于Sentinel Dashboard来实现流控配置
启动Sentinel Dashboard
在业务服务中的application.yml中增加连接sentinel dashboard配置
提供一个REST接口,不需要添加任何资源埋点,在默认情况下Sentinel Starter会对所有HTTP请求进行限流
启动服务后,此时访问http://localhost:8080/dash,由于没有配置流控规则,所以不存在限流行为
进入Sentinel Dashboard
进入spring.application.name对应的菜单,访问“簇点链路”,在该列表下可以看到/dash这个REST接口的资源名称
针对/dash这个资源名称,可以在最右边的操作栏单击“流控”按钮设置流控规则
新增完成之后,再次访问http://localhost:8080/dash接口,当QPS超过1时,就可以看到限流的效果
自定义URL限流异常
在默认情况下,URL触发限流后会直接返回:Blocked by Sentinel (flow limiting)
在实际应用中,大都采用JSON格式的数据,所以如果希望修改触发限流之后的返回结果形式, 则可以通过自定义限流异常来处理,实现UrlBlockHandler并且重写blocked方法
另一种方式 ,当触发限流之后,我们希望直接跳转到一个降级页面,可以通过配置来实现: spring.cloud. sentinel.servlet.block-page={ur1}
URL资源清洗
场景:sentinel默认会把每个不同的URL都作为不同的资源来处理,比如 :提供了一个携带{id}参数的REST风格API, 对于每一个不同的{id},URL也都不一样,所以在默认情况下Sentinel会把所有的URL当作资源来进行流控
问题
限流统计不准确,实际需求是控制clean方法总的QPS,结果统计的是每个URL的QPS
导致Sentinel中资源数量过多,默认资源数量的阈值是6000,对于多出的资源规则将不会生效
解决方案:通过UrlCleaner接口来实现资源清洗
也就是对于/clean/{id}这个URL,我们可以统一归集到/clean/*资源下
代码示例
不足:需要手写大量不同接口的清洗代码
Sentinel集成Nacos实现动态流控规则
场景:基于Sentinel Dashboard所配置的流控规则,都是保存在内存中的,一旦应用重启,这些规则都会被清除。
为了解决这个问题,Sentinel提供了动态数据源支持
动态数据源支持:Consul、ZooKeeper、Redis、Nacos、Apollo、etcd等数据源
服务集成Nacos实现动态流控规则步骤
添加Nacos数据源的依赖包
创建一个REST接口,用于测试
在application.yml中添加数据源配置
登录Nacos控制台,创建流控配置规则,配置信息如图
最后,登录Sentinel Dashboard,找到执行项目名称菜单下的“流控规则”, 就可以看到在Nacos上所配置的流控规则已经被加载了,如图
当我们在Nacos的控制台上修改流控规则后,可以同步在Sentinel Dashboard上看到流控规则的变化
整合之后,接口流控规则的动态修改存在于以下两个地方
Sentinel Dashboard
Nacos控制台
集成Nacos实现动态流控规则存在的问题
在Nacos控制台上修改流控规则,虽然可以同步到Sentinel Dashboard,
但是开发者在Sentinel Dashboard上修改流控规则后不能同步到Nacos上
流控规则同步流程图
建议:不要在Nacos上修改流控规则,因为这种修改的危险系数很高,毕竟Nacos的UI并不是专门负责流控规则维护的
注意:实现Sentinel Dashboard来动态维护流控规则并同步到Nacos上,目前官方还没有提供支持,需要大家可以自己来实现
Sentinel Dashboard集成Nacos实现规则同步
方案实现分析
Sentinel Dashboard的“流控规则”下的所有操作,都会调用Sentinel-Dashboard源码中的FlowControllerV1类, 这个类中包含流控规则本地化的CRUD操作
在com.alibaba.csp.sentinel.dashboard.controller.v2包下存在一个FlowControllerV2类, 这个类同样提供流控规则的CRUD,和V1版本不同的是,它可以实现指定数据源的规则拉取和发布
FlowControllerV2依赖以下两个非常重要的接口
DynamicRuleProvider:动态规则的拉取,从指定数据源中获取流控规则后在Sentinel Dashboard中展示(后面实现基于Nacos的实现类)
DynamicRulePublisher:动态规则的发布,将在Sentinel Dashboard中修改的规则同步到指定数据源中(后面实现基于Nacos的实现类)
我们扩展这两个类,然后集成Nacos来实现Sentinel Dashboard规则的同步
方案实现步骤(Sentinel Dashboard源码修改)
在GitHub中下载Sentinel Dashboard 1.7.1的源码
使用IDEA工具打开${Sentinel_home}/sentinel-dashboard工程
在pom.xml中把sentinel-datasource-nacos依赖的<scope>注释掉
修改resources/app/scripts/directives/sidebar/sidebar.html文件中的下面这段代码, 将dashboard.flowV1改成dashboard.flow,也就是去掉V1,修改之后,会调用FlowControllerV2中的接口
在com.alibaba.csp.sentinel.dashboard.rule包中创建一个nacos包,并创建一个类用来加载外部化配置
创建一个Nacos配置类NacosConfiguration
注入Converter转换器,将FlowRuleEntity转化成FlowRule,以及反向转化
注入Nacos配置服务ConfigService
创建一个常量类NacosConstants,分别表示默认的GROUP_ID和DATA_ID的后缀
实现动态从Nacos配置中心获取流控规则
创建一个流控规则发布类,在Sentinel Dashboard上修改完配置之后,需要调用该发布方法将数据持久化到Nacos中
修改FlowControllerV2类,将上面配置的两个类注入进来,表示规则的拉取和规则的发布统一用我们前面自定义的两个实例
在application.properties文件中添加Nacos服务端的配置信息
使用以下命令将代码打包成一个fat jar,根据前面介绍的操作方法启动服务
服务针对改造后的Sentinel Dashboard配置
配置文件中data-id的命名要以-sentinel-flow结尾即可,因为在Sentinel Dashboard中我们写了一个固定的后缀
示例
Dubbo集成Sentinel实现限流?
Sentinel热点限流
热点数据:表示经常访问的数据,在有些场景中我们希望针对这些访问频次非常高的数据进行限流
比如针对一段时间内频繁访问的用户IP地址进行限流
或者针对频繁访问的某个用户ID进行限流
热点参数限流的策略
它是一种特殊的限流,在普通限流的基础上对同一个受保护的资源区根据请求中的参数分别处理
该策略只对包含热点参数的资源调用生效
热点限流使用场景
服务网关层:例如防止网络爬虫和恶意攻击,一种常用方法就是限制爬虫的IP地址,客户端IP地址就是一种热点参数
写数据服务:例如业务系统提供写数据的服务,数据会写入数据库之类的存储系统
热点参数限流的原理
Sentinel通过LRU策略结合滑动窗口机制来实现热点参数的统计
LRU策略可以统计单位时间内最常访问的热点数据,滑动窗口机制可以协助统计每个参数的QPS
Sentinel会根据请求的参数来判断哪些是热点参数,然后通过热点参数限流规则,将QPS超过设定阈值的请求阻塞
热点参数限流的使用
引入热点参数限流依赖包sentinel-parameter-flow-control
创建一个REST接口,并定义限流埋点,此处针对参数id配置热点限流规则
SphU.entry代码方式
@SentinelResource注解方式
当注解所配置的方法上有参数时,Sentinel会把这些参数传入Sphu.entry(res,args)
通过ParamFlowRuleManager.loadRules方法加载热点参数限流规则(不能通过Dashboard设置规则吗?)
通过测试工具或者快速刷新浏览器来测试热点参数限流
访问Sentinel Dashboard,进入“实时监控”来查看限流的效果
热点参数规则说明
durationInSec:统计窗口时间长度,单位为秒。
maxQueueingTimeMS:最长排队等待时长,只有当流控行为controlBehavior设置为匀速排队模式时生效。
paramIdx:热点参数的索引,属于必填项,它对应的是SphU.entry(xxx,args)中的参数索引位置。
paramFlowItemList:针对指定参数值单独设置限流阈值,不受count阈值的限制。
Sentinel的工作原理
核心部分
工作流程
数据结构
限流算法
工作原理
架构图
图片
逻辑分析
调用链路是Sentinel的工作主流程,由各个Slot插槽组成
将不同的Slot按照顺序串在一起(责任链模式),从而将不同的功能(限流、降级、系统保护)组合在一起
各个Slot承担了不同的职责,例如LogSlot负责记录日志、StatisticSlot负责统计指标数据、FlowSlot负责限流等。 这是一种职责分离的设计,每个模块更聚焦于实现某个功能
在Sentinel中,所有的资源都对应一个资源名称(resourceName),每次访问该资源都会创建一个Entry对象, 在创建Entry的同时,会创建一系列功能槽(Slot Chain),这些槽会组成一个责任链,每个槽负责不同的职责
Sentinel中的槽
NodeSelectorSlot :负责收集资源的调用路径,以树状结构存储调用栈,用于根据调用路径来限流降级。
ClusterBuilderSlot :负责创建以资源名维度统计的ClusterNode,以及创建每个ClusterNode下按调用来源origin划分的StatisticNode。
LogSlot :在出现限流、熔断、系统保护时负责记录日志。
AuthoritySlot :权限控制,支持黑名单和白名单两种策略。
SystemSlot :控制总的入口流量,限制条件依次是总QPS、总线程数、RT阈值、操作系统当前load1、操作系统当前CPU利用率。
FlowSlot :根据限流规则和各个Node中的统计数据进行限流判断。
DegradeSlot :根据熔断规则和各个Node中的统计数据进行服务降级。
StatisticSlot :统计不同维度的请求数、通过数、限流数、线程数等runtime信息,这些数据存储在DefaultNode、OriginNode和ClusterNode中。
Spring Cloud Sentinel的工作原理
作用:在Spring Cloud中使用Sentinel实现限流的场景中,我们并不需要任何配置,Sentinel会自动保护所有的HTTP服务
实现机制
在Spring-Cloud-Starter-Alibaba-Sentinel包中,我们知道Starter组件会用到自动装配,所以直接找到META-INF/spring.factories文件
spring.factories文件自动装配了5个类
SentinelWebAutoConfiguration是对Web Servlet环境的支持
SentinelWebFluxAutoConfiguration是对Spring WebFlux的支持
SentinelEndpointAutoConfiguration暴露Endpoint信息
SentinelFeignAutoConfiguration用于适配Feign组件
SentinelAutoConfiguration支持对RestTemplate的服务调用使用Sentinel进行保护
分析SentinelWebAutoConfiguration
代码实现
自动装配了一个FilterRegistrationBean,主要作用是注册一个CommonFilter,并且默认情况下通过“/*”规则拦截所有的请求
CommonFilter过滤器的定义
从请求中获取目标URL
获取Urlcleaner,如果存在,则说明配置过URL清洗策略,调用UrlCleaner.clean替换target
使用SphU.entry对当前URL添加限流埋点
只是通过Filter的方式将所有请求自动设置为Sentinel的资源,从而达到限流的目的
Sentinel对Feign的支持原理
核心类
SentinelFeignAutoConfiguration
启用属性:feign.sentinel.enabled
SentinelFeign
build方法中重新实现了super.invocationHandlerFactory方法,也就是动态代理工厂,构建的是InvocationHandler对象。
build中会获取Feign Client中的信息,比如fallback,fallbackFactory等,然后创建一个SentinelInvocationHandler(动态代理)
SentinelInvocationHandler继承了InvocationHandler,invoke方法里面进行熔断限流的处理
总结
Hystrix要对Feign的调用进行熔断处理,那么肯定是将Feign的请求包装了HystrixCommand。
同样的道理,我们只要找到Hystrix是如何包装的,无非就是将Hystrix的代码换成Sentinel的代码而已。
InvocationHandlerFactory是用于创建动态代理的工厂,有默认的实现,也有Hystrix的实现feign.hystrix.HystrixFeign。
Sentinel构造的是SentinelInvocationHandler ,Hystrix构造的是HystrixInvocationHandle。在HystrixInvocationHandler的invoke方法中进行HystrixCommand的包装。
Sentinel核心源码分析?
源码模块
sentinel-core:核心库,提供限流、降级等实现
sentinel-transport:通信协议处理模块
sentinel-adapter:负责针对主流开源框架进行限流适配,比如Dubbo、gRPC、Zuul等
sentinel-extension:实现不同组件的数据源扩展,比如Nacos、ZooKeeper、Apollo等
sentinel-dashboard:控制台模块,提供可视化监控和管理
sentinel-demo:官方案例
限流的源码实现
实时指标数据统计
服务降级的实现原理
参考资料
https://www.cnblogs.com/fswhq/p/13690320.html
如果导图对您有用,请在右上角给点个赞吧
0 条评论
下一页
为你推荐
查看更多