- 官方中文文档:https://sentinelguard.io/zh-cn/docs/introduction.html
- github网址:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
官方文档介绍挺详细的,这里摘要一部分信息。
1、Sentinel是什么随着微服务的流行,服务和服务之间的稳定性变得越来越重要。
Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件。
Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。简单来说,Sentinel是一个分布式系统的流量防卫兵。
Sentinel具有以下特征:
- 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、 gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
2.2 规则围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
二、Sentinel快速使用Sentinel 的使用可以分为两个部分:
- 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。
官方-如何使用:https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
下面通过 Java 客户端的方式来快速使用 Sentinel。
创建一个 SprintBoot项目,引入 sentinel‐core依赖:
<dependency> <groupId>com.alibaba.csp @Autowired private OrderService orderService; public static final String RESOURCE_NAME_JAVA_GET_BY_ID = "JAVA_GET_BY_ID"; /**
* 对请求资源进行 sentinel流控
* http://127.0.0.1:18081/orderJava/getById/100
*/ @GetMapping(value = "/getById/{id}") public R getById(@PathVariable("id") Long id) { Entry entry = null; try { // 1. 定义流控资源。sentinel针对资源进行流控限制的 entry = SphU.entry(RESOURCE_NAME_JAVA_GET_BY_ID); // 被保护的业务逻辑 Order order = orderService.getById(id); if (id == 5) { int res = 1 / 0; } return R.ok().put("order", order); } catch (BlockException blockEx) { // 3.资源访问阻止,被限流或被降级 // 进行相应的处理操作 log.info("BlockException。id={}, blockEx = {}", id, blockEx.getMessage()); return R.error(" getById 方法被流控了。id=" + id); } catch (Exception ex) { // 3.若需要配置降级规则,需要通过这种方式记录业务异常 log.info("业务出异常了。ex = {}", ex.getMessage()); Tracer.traceEntry(ex, entry); } finally { if (entry != null) { entry.exit(); } } return R.error(); } }
1.2 定义规则
使用 Spring的@PostConstruct注解:创建规则的初始化方法,Spring会提前将规则加载到 Spring容器中。
@PostConstruct private static void initFlowRules() { List<FlowRule> rules = new ArrayList<>(); /**
* 流控规则 QPS
*/ FlowRule rule1 = new FlowRule(); // 设置受保护的资源 rule1.setResource(OrderJavaController.RESOURCE_NAME_JAVA_GET_BY_ID); // 设置流控规则 QPS rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置受保护的资源阈值 // Set limit QPS to 20. rule1.setCount(3); rules.add(rule1); // 加载配置好的规则 FlowRuleManager.loadRules(rules); }
这里指定的是 QPS流控规则。更多规则查看官方文档。
1.3 测试启动项目,访问请求:http://127.0.0.1:18081/orderJava/getById/100
根据规则,请求被 Sentinel流控管理OK。
Sentinel 支持通过@SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。使用步骤同上。
官方 @SentinelResource 注解使用:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
所以,还需要引入它的依赖:
<dependency> <groupId>com.alibaba.csp // 业务逻辑 Order order = orderService.getById(id); if (id == 5) { int res = 1 / 0; } return R.ok().put("order", order); }
创建 blockHandler 和 fallback 函数的处理逻辑。
注意:如果 blockHandler 和 fallback同时指定了,则 blockHandler优先级更高。
/**
* 被限流或被降级的异常处理
* 注意:
* 1. 一定要public
* 2. 返回值一定要和源方法保证一致,包含源方法的参数。
* 3. 可以在参数最后添加BlockException,可以区分是什么规则的处理方法
*/ public R blockHandlerForGetById(Long id, BlockException blockEx) { log.info("BlockException。id={}, blockEx = {}", id, blockEx.getMessage()); return R.error(" getById 方法被流控了。id=" + id); } /**
* 业务异常处理
*/ public R fallbackForGetById(Long id, Throwable e) { log.info("业务出异常了。ex = {}", e.getMessage()); return R.error(" 业务出异常了。ex = " + e); }
2.2 定义规则
@PostConstruct private static void initFlowRules() { List<FlowRule> rules = new ArrayList<>(); FlowRule rule2 = new FlowRule(); // 设置受保护的资源 rule2.setResource(OrderAnnotationController.RESOURCE_NAME_ANNOTATION_GET_BY_ID); // 设置流控规则 QPS rule2.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置受保护的资源阈值 // Set limit QPS to 20. rule2.setCount(2); rules.add(rule2); FlowRule rule3 = new FlowRule(); // 设置受保护的资源 rule3.setResource(OrderAnnotationController.RESOURCE_NAME_ANNOTATION_GET_BY_ID2); // 设置流控规则 QPS rule3.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置受保护的资源阈值 // Set limit QPS to 20. rule3.setCount(2); rules.add(rule3); // 加载配置好的规则 FlowRuleManager.loadRules(rules); }
2.3 测试
启动项目,根据规则,访问请求被 Sentinel流控管理OK。
通过@SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数时。我们可以把它们定义到一个公共的类中,通过指定类即可。更过属性查看官方文档。
@SentinelResource(value = RESOURCE_NAME_ANNOTATION_GET_BY_ID, blockHandler = "blockHandler", blockHandlerClass = SentinelExceptionUtil.class, fallback = "fallback", fallbackClass = SentinelExceptionUtil.class) @GetMapping(value = "/getById2/{id}") public R getById2(@PathVariable("id") Long id) { // 业务逻辑 Order order = orderService.getById(id); if (id == 5) { int res = 1 / 0; } return R.ok().put("order", order); }
blockHandler 和 fallback 函数的公共处理逻辑。
public class SentinelExceptionUtil { /**
* @SentinelResource注解,如果指定了class,方法必须是 static方法。
*/ public static R blockHandler(Long id, BlockException e) { return R.error("被限流啦 -> id=" + id); } public static R blockHandler2(Long id, BlockException e) { return R.error("被熔断降级啦 -> id=" + id); } public static R fallback(Long id, Throwable e) { return R.error("被异常降级啦-> 业务出异常了。ex = " + e); } }
三、熔断降级规则
通过上面的了解,我们对 Java 客户端的方式使用 Sentinel有所认知,通过注解方式定义 熔断降级规则再来使用一下。
1、对请求资源进行 sentinel保护@Slf4j @RestController @RequestMapping("/orderDegrade") public class OrderDegradeController { @Autowired private OrderService orderService; public static final String RESOURCE_NAME_ANNOTATION_GET_BY_ID = "ANNOTATION_GET_BY_ID"; public static final String RESOURCE_NAME_ANNOTATION_GET_BY_ID2 = "ANNOTATION_GET_BY_ID2"; /**
* 方式1:http://127.0.0.1:18081/orderDegrade/getById1/200
*/ @SentinelResource(value = RESOURCE_NAME_ANNOTATION_GET_BY_ID, blockHandler = "blockHandler2", blockHandlerClass = SentinelExceptionUtil.class, fallback = "fallback", fallbackClass = SentinelExceptionUtil.class) @GetMapping(value = "/getById1/{id}") public R getById1(@PathVariable("id") Long id) { // 业务逻辑 Order order = orderService.getById(id); // 不管是业务异常还是手动抛异常,只要满足 异常熔断降级规则,就会触发 blockHandler2方法。 if (id == 5) { int res = 1 / 0; } else if (id == 50) { throw new RuntimeException("抛出xxx异常"); } return R.ok().put("order", order); } /**
* 方式2:http://127.0.0.1:18081/orderDegrade/getById2/200
*/ @SentinelResource(value = RESOURCE_NAME_ANNOTATION_GET_BY_ID, blockHandler = "blockHandler2", blockHandlerClass = SentinelExceptionUtil.class, fallback = "fallback", fallbackClass = SentinelExceptionUtil.class) @GetMapping(value = "/getById2/{id}") public R getById2(@PathVariable("id") Long id) throws InterruptedException { // 业务逻辑 Order order = orderService.getById(id); // 慢调用比例 TimeUnit.SECONDS.sleep(1); return R.ok().put("order", order); } }
2、定义规则
@PostConstruct public void initDegradeRule() { List<DegradeRule> degradeRules = new ArrayList<>(); /**
* 异常熔断降级规则:一分钟内: 执行了2次并出现了2次异常 就会触发熔断
*/ DegradeRule degradeRule1 = new DegradeRule(); degradeRule1.setResource(OrderDegradeController.RESOURCE_NAME_ANNOTATION_GET_BY_ID); // 设置规则侧率: 异常数 degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); // 触发熔断异常数:2 degradeRule1.setCount(2); // 触发熔断最小请求数:2 degradeRule1.setMinRequestAmount(2); // 统计时长:单位ms degradeRule1.setStatIntervalMs(60 * 1000); // 熔断持续时长 : 单位 秒 // 一旦触发了熔断, 再次请求对应的接口就会直接调用 降级方法。 degradeRule1.setTimeWindow(10); degradeRules.add(degradeRule1); /**
* 慢调用比率规则:
*/ DegradeRule degradeRule2 = new DegradeRule(); degradeRule2.setResource(OrderDegradeController.RESOURCE_NAME_ANNOTATION_GET_BY_ID2); degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT); degradeRule2.setCount(100); degradeRule2.setTimeWindow(10); // 请求总数小于minRequestAmount时不做熔断处理 degradeRule2.setMinRequestAmount(2); // 在这个时间段内2次请求 degradeRule2.setStatIntervalMs(60 * 1000 * 60); degradeRules.add(degradeRule2); // 加载配置好的规则 DegradeRuleManager.loadRules(degradeRules); }
3、测试
启动项目,根据规则,访问请求被 Sentinel流控管理OK。
– 求知若饥,虚心若愚。
