您当前的位置: 首页 >  Java

Charge8

暂无认证

  • 11浏览

    0关注

    447博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Sentinel简介与使用(Java客户端)

Charge8 发布时间:2022-10-11 22:19:45 ,浏览量:11

一、Sentinel简介
  • 官方中文文档: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 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
2、基本概念 2.1 资源

资源是 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依赖:

		 
		  com.alibaba.csp 
		  sentinel‐core 
		  1.8.4 
		 
1、代码定义资源 1.1 对请求资源进行 sentinel保护

在我们正常的 controller的请求中,

  1. 代码定义 Sentinel保护的资源,
  2. 处理业务或者资源的异常逻辑。
@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。

在这里插入图片描述

2、注解方式定义资源

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。

在这里插入图片描述

2.4 注解属性的使用

通过 @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。

在这里插入图片描述

– 求知若饥,虚心若愚。

关注
打赏
1664721914
查看更多评论
立即登录/注册

微信扫码登录

0.0440s