- 官方中文文档: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,甚至服务名称作为资源名来标示资源。
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
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依赖:
com.alibaba.csp
sentinel‐core
1.8.4
1、代码定义资源
1.1 对请求资源进行 sentinel保护
在我们正常的 controller的请求中,
- 代码定义 Sentinel保护的资源,
- 处理业务或者资源的异常逻辑。
@Slf4j
@RestController
@RequestMapping("/orderJava")
public class OrderJavaController {
@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 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
所以,还需要引入它的依赖:
com.alibaba.csp
sentinel-annotation-aspectj
1.8.4
2.1 对请求资源进行 sentinel保护
@Autowired
private OrderService orderService;
public static final String RESOURCE_NAME_ANNOTATION_GET_BY_ID = "ANNOTATION_GET_BY_ID";
@SentinelResource(value = RESOURCE_NAME_ANNOTATION_GET_BY_ID, blockHandler = "blockHandlerForGetById", fallback = "fallbackForGetById")
@GetMapping(value = "/getById/{id}")
public R getById(@PathVariable("id") Long id) {
// 业务逻辑
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 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 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。
– 求知若饥,虚心若愚。