学习目标
理解Sentinel系统可用性解决方案
掌握基于Sentinel的服务限流实现方法
目录
Sentinel核心概念和工作流程
Sentinel基本限流机制
Sentinel热点参数限流
Sentinel核心概念和工作流程 alibaba开源的高可用流量管理框架 提供面相分布式服务架构的高可用流量防护组件,主要以流量为切入点,多维度保障微服务稳定性
Sentinel的解决方案
Sentinel功能特性
Setinel开源生态
Setinel模块结构
核心概念 资源 Java应用程序中的任何内容,如一个方法、一段代码-个服务等,一般指一个具体的接口
指标数据 Sentinel以资源为维度统计指标数据,这些指标包括每秒请求数、请求平均耗时、每秒异常总数等,
规则 围绕资源的实时指标数据设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则等
ProcessorSlot 处理器插槽是Sentinel提供的插件,负责执行具体的资源指标数据的统计、限流、熔断降级、系统自适应保护等工作。 一组处理器插槽表现为有序的处理器插槽链表(ProcessorSlotChain),Sentinel在执行方法之前根据ProcessorSlotChain调度处理器插槽完成资源指标数据的统计、限流、熔断降级等
ProcessorSlot定义
1 2 3 4 5 6 7 8 interface ProcessorSlot<T>{ //执行entry 方法来启动各个节点对该资源本次访问的数据度量的开始和结束 void entry(...); void exit(...); //表示该Slot的entry或exit方法已经执行完毕,可以将entry对象传递给下一个Slot void fireEntry(...); void fireExit(...); }
内置ProcessorSlot
Processorslot名称
Processorslot作用
NodeSelectorSlot
用于构建调用树中的Node
ClusterBuilderSlot
创建CluserNode,具有相同名称的资源共享一个ClusterNode
LogSlot
用于打印异常日志
StatisticSlot
用于统计实时的调用数据
SystemSlot
用于根据Statisticslot所统计的全局入口流量进行限流
AuthoritySlot
用于对资源的黑白名单做检查,只要有一条不通过就抛异常
FlowSlot
用于根据预设资源的统计信息,按照固定的次序执行限流规则
Degradeslot
用于基于统计信息和设置的降级规则进行匹配校验以决定是否降级
ProcessorSlotChain 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public abstract class ProcessorSlotChain extends AbstractLinkedProcessorSlot<Object>{ public abstract void addFirst(AbstractLinkedProcessorSlot<?>protocolProcessor); public abstract void addLast(AbstractLinkedProcessorSlot<?>protocolProcessor); } public class DefaultProcessorSlotChain extends ProcessorSlotChain { public void addFirst(AbstractLinkedProcessorSlot<?>protocolProcessor){ protocolProcessor.setNext(this.first.getNext());this.first.setNext(protocolProcessor); if(this.end == this.first){ this.end = protocolProcessor; } } public void addLast(AbstractLinkedProcessorslot<?>protocolProcessor){ this.end.setNext(protocolProcessor); this.end = protocolProcessor; } }
指标数据统计 ResourceWrapper 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class ResourceWrapper { protected final String name; //资源名称 protected final EntryType entryType; //流量类型 protected final int resourceType; //资源类型 } public enum EntryType { IN, //流入流量 OUT;//流出流量 } public final class ResourceTypeConstants { public static final int COMMON=0;//默认,可以是接口、一个方法、一段代码。 public static final int COMMON_WEB = 1; //Web应用的接口 public static final int COMMON_RPC =2; //使用Dubbo框架实现的RPC接口 public static final int COMMONAPI_GATEWAY = 3;//网关接口 public static final int COMMON_DB_SOL= 4;//数据库SQL操作 }
Node Node定义统计资源实时指标数据的方法,不同实现类被用在不同维度为资源统计实时指标数据
StatisticNode extends Node 封装实现实时指标数据统计 DefaultNode extends StatisticNode 统计同一资源、不同调用链入口的实时指标数据 ClusterNode extends StatisticNode 统计每个资源的全局指标数据 EntranctNode extends ClusterNode 调用链入口节点(入口,不代表资源)
统计实现通过滑动窗口
Entry 在调用链上,一个资源对应一个Entry实例
Context Sentinel工作流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class sentinelDemo { public static void main(String[] args){ initRules(); //配置规则 String resourceName:="resource"; Entry entry = null; try { //注册资源 entry = SphU.entry(resourceName); //执行业务逻辑 doBusinessLogic(); } catch (BlockException e){ //处理限流 handleBlockException(); } finally { if(entry != null){ //退出数据度量 entry.exit(); } } } }
流程名
释义
定义规则
根据业务需求定义规则,包括限流规则、熔断规则和降级规则等
注册资源
将需要限流或熔断的资源(如接口、方法等)注册到Sentinel中
调用链路拦截
在业务代码中调用需要进行限流或熔断的资源时Sentinel会拦截请求进行规则匹配和统计
执行处理
根据规则匹配的结果Sentinel可以进行限流、熔断和降级等处理,保障系统的稳定性和可用性
Sentinel基本限流机制 开发步骤
定义资源 通过代码嵌入和注解集成
设置限流规则 指定流量统计类型和控制行为
验证限流效果 通过测试工具执行验证
定义资源 工具类
SphU包含try-catch风格的API1 2 3 4 5 6 7 try(Entry entry= SphU.entry("resourceName")){ //被保护的业务逻辑 // do something here... }catch(BlockException ex){ //资源访问阻止,被限流或被降级 //在此处进行相应的处理操作 }
SphO提供if-else风格的API1 2 3 4 5 6 7 8 9 10 11 if(Spho.entry("resourceName")){ //务必保证finally会被执行 try { //被保护的业务逻辑 // do something here... } finally { Spho.exit(); } } else{ //资源访问阻止,被限流或被降级在此处进行相应的处理操作 }
注解 1 public @interface SentinelResource{ ... }
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class TestService { //对应的 handleException`函数需要位于 ExceptionUtil类中并且必须为 static 函数 @SentinelResource(value ="test", blockHandler = "handleException",blockHandlerClass = {ExceptionUtil.class}) public void test(){ System.out.println("Test"); } @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "hellofallback") public String hello(long s){ return String.format("Hello at %d',s); } //Fallback函数,函数签名与原函数一致或加一个Throwable 类型的参数 public String helloFallback(long s){ return String.format("Hello fall back %d"S); } //Block异常处理函数,参数最后多一个其余与原函数一致BlockException public String exceptionHandler(long s, BlockException ex){ ex.printStackTrace(); return "Error occurred at" + s; } }
限流规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class FlowRule extends AbstractRule { //限流阈值类型 private int grade = RuleConstant.FLOW_GRADE_OPS; private double count; //基于调用关系的限流策略 private int strategy = RuleConstant.STRATEGY_DIRECT; private String refResource; //流量控制效果 private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT: //冷启动时长 private int warmUpPeriodsec =10; private int maxQueueingTimeMs =500; private boolean clusterMode: private ClusterFlowConfig clusterConfig; //流量整形控制器 private TrafficShapingController controller; ... }
Grade
FLOW_GRADE_THREAD (资源的最大)并发线程数:相当于线程隔离机制
FLOW_GRADE_QPS 每秒查询数QPS
Strategy
STRATEGY_DIRECT 直接流控:当前资源访问量达到某个阈值时后续请求将被直接拦截
STRATEGY_RELATE 关联流控:关联资源的访问量达到某个阈值时对当前资源进行限流
STRATEGY_CHAIN 链路流控:指定链路的访问量大于某个阈值时对当前资源进行限流
ControlBehavior
ControlBehavior
TrafficShapingController
效果
CONTROL_BEHAVIOR_DEFAULT
DefaultController
快速失败:直接拒绝超过阈值的请求
CONTROL_BEHAVIOR_WARM_UP
WarmUpController
冷启动限流:基于令牌桶算法并通过预热机制到达稳定的性能状态
Sentinel的冷启动限流确保系统在流量突增时平稳过渡,防止资源瞬间被打满。所谓冷启动,或预热是指,系统长时间处理低水平请求状态,大量请求突然到来时,并非所有请求都放行,而是慢慢增加请求,目的时防止大量请求冲垮应用,达到保护应用的目的。拿到令牌的会处理,放行一部分请求。预热可随时间增加令牌投放量。
CONTROL_BEHAVIOR_RATE_LIMITER
RateLimiterController
匀速限流:基于漏桶算法并结合虚拟队列等待机制
入队,慢慢处理
CONTROL_BEHAVIOR_WARM_UPRATE_LIMITER
WarmUpRateLimiterController
冷启动集成匀速限流
设置限流规则 FlowRuleManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private static void initFlowRules(){ List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); // 资源名 rule.setResource("myResource"); //限流类型 rule.setGrade(RuleConstant.FLOW GRADE OPS); //限流阈值 rule.setCount(20); //限流策略 rule.setStrategy(RuleConstant.STRATEGY CHAIN); //流量控制效果 rule.setControlBehavior(RuleConstant,CONTROL_BEHAVIOR_DEFAULT); rule.setClusterMode(false) //添加FlowRule到执行流程中 rules.add(rule); FlowRuleManager.loadRules(rules); }
Sentinel热点参数限流 参数限流是指根据方法调用传递的参数实现限流,或者根据接口的请求参数限流,而热点参数限流是指对访问频繁的参数进行限流,例如对频繁访问的IP地址进行限流等,热点参数限流会统计传入参数中的热点参数,并根据配置的限流值与模式,对包含热点参数的资源调用进行限流。 热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。 例如:
1 2 3 http://localhost:8080/test?a=10 访问100次 http://localhost:8080/test?b=10 访问10次 http://localhost:8080/test?c=10 访问3次
与围绕资源实现限流不同,热点参数限流是围绕资源的参数的不同取值来限流的,它不需要统计资源指标数据,而需要统计不同参数取值的指标数据。Sentinel利用LRU策略统计最近最常访问的热点参数结合令牌桶算法来进行参数级别的流控。
限流规则
属性
说明
默认值
resource
资源名,非空
count
限流阈值,非空
grade
限流模式
QPS 模式
durationInSec
统计窗口时间长度(单位为秒)
1s
controlBehavior
流控效果
快速失败
paramldx
热点参数的索引,非空,对应 SphU.entry(xxx,args)方法中的参数索引位置
paramFlowltemList
参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面count阈值的限制
clusterMode
是否是集群参数流控规则
false
clusterConfig
集群流控相关配置
定义热点参数资源 原生API方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @RestController public class ParamController { final String resourceName ="test"; @GetMapping("/param") public String test(@PathParam("id") String id, @PathParam("name") String name)Entry entry = null; try { //使用entry带参数的重载方法定义资源 //id 处理不同的热点数据,最后一个参数是一个可变入参 entry = Sphu.entry(resourceName,EntryType.IN,1,id); return"success"; } catch(BlockException e){ e.printStackTrace(); return "block exception"; } finally { if(entry != null){ entry.exit(); } } }
注解方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static void initRule(){ ParamFlowRule paramFlowRule = new ParamFlowRule(); paramFlowRule.setResource("test"); paramFlowRule.setGrade(RuleConstant.FLOW_GRADE_OPS); paramFlowRule.setCount(3): //允许的最大突发请求 paramFlowRule.setBurstCount(10); paramFlowRule.setControlBehavior(RuleConstant.CONTROL _BEHAVIOR_DEFAULT); paramFlowRule.setDurationInSec(1); 热点参数索引 paramFlowRule.setParamIdx(0); List<ParamFlowRule> paramFlowRules = new ArrayList<>(); paramFlowRules.add(paramFlowRule); //通过ParamFlowRuleManager加载规则 ParamFlowRuleManager.loadRules(paramFlowRules); } @SentinelResource(value ="test') @GetMapping("/hello") public String test(@PathParam("id")Integer id){ return "success"; }
集成
核心库 不依赖其他任何框架或者库,能够在任何ava环境上运行,并且能与Spring Cloud.Dubbo等开源框架进行整合
控制台 基于Spring Boot开发,独立可以运行Jar包,不需要额外的Tomcat等容器
Spring Cloud Alibaba集成Sentinel 集成控制台
1 2 3 4 5 spring: cloud: sentinel: transport: dashboard:127.0.0.1:8088
集成Feign(链路流量控制)
1 2 3 feign: sentinel: enabled:true
思考题 如果想要实现对某一个微服务访问链路进行流量控制,开发上需要哪些主要步骤?