【SpringCloud Alibaba】(八)学习 Sentinel 核心技术与配置规则(下)

本文主要是介绍【SpringCloud Alibaba】(八)学习 Sentinel 核心技术与配置规则(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1. 热点规则
    • 1.1 演示热点规则
    • 1.2 演示热点高级选项规则
  • 2. 授权规则
    • 2.1 演示授权规则
  • 3. 系统规则
    • 3.1 演示系统规则
  • 4. @SentinelResource 注解
    • 4.1 @SentinelResource 注解概述
    • 4.2 演示 @SentinelResource 注解
      • 4.2.1 定义限流和降级后的处理方法
      • 4.2.2 在外部类中指定限流和异常调用的方法
  • 5. Sentinel 持久化
    • 5.1 Sentinel 持久化概述
    • 5.2 实现 Sentinel 的持久化
  • 代码地址

Sentinel 的核心规则包括 流控规则、熔断规则、热点规则、授权规则和系统规则。每种规则的配置方式不同。

在上一篇文章中,我们已经介绍了 流控规则、熔断规则。接下来我们来继续了解剩下的核心规则

1. 热点规则

Sentinel 的热点规则可以根据 具体的参数 来控制流量规则,适用于根据不同参数进行流量控制的场景

1.1 演示热点规则

1、在订单微服务的 SentinelController 类中新增 requestSentinel3() 方法,如下所示:

@GetMapping(value = "/request_sentinel3")
@SentinelResource("request_sentinel3")
public String requestSentinel3(String header, String body){log.info("测试Sentinel3");return "sentinel3";
}

2、在浏览器中访问 http://localhost:8080/order/request_sentinel3 接口,在 Sentinel 的簇点
链路中会显示 /request_sentinel3 接口

3、点击热点按钮,如下所示:

在这里插入图片描述

4、在弹出的热点规则配置框中的参数索引中输入 0,单机阈值输入 1,统计窗口时长输入 1,如下所
示:

在这里插入图片描述
表示:对 requestSentinel3() 方法的第一个参数 header 进行限流,如果每秒钟访问的次数超过 1 次,则触发限流

5、保存配置后,在浏览器中不断访问 http://localhost:8080/order/request_sentinel3? header=header ,当每秒访问的频率超过 1 次时,会触发 Sentinel 的限流操作,如下所示:

在这里插入图片描述
不断访问 http://localhost:8080/order/request_sentinel3?body=body ,则不会触发限流操作

1.2 演示热点高级选项规则

1、在弹出的热点规则配置框中打开高级选项,在参数类型中选择 java.lang.String,因为在参数索引中输入 0,表示的是对 header 参数限流,而 header 参数是 String 类型的。在参数值里输入 header,也就是为参数名为 header 的参数赋值为字符串 header。限流阈值为 1,如下所示:

在这里插入图片描述
2、点击保存按钮,在浏览器不断刷新 http://localhost:8080/order/request_sentinel3? header=header ,会触发 Sentinel 的限流操作

2. 授权规则

在某些场景下,需要根据 调用接口的来源 判断是否允许执行本次请求。此时就可以使用 Sentinel 提供的授权规则来实现,Sentinel 的授权规则能够根据请求的来源判断是否允许本次请求通过。

在 Sentinel 的授权规则中,提供了 白名单与黑名单 两种授权类型

2.1 演示授权规则

1、在订单微服务的 com.zzc.order.parse 包下新建 MyRequestOriginParser 类,如下所示:

@Component
public class MyRequestOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {return httpServletRequest.getParameter("serverName");}}

2、首先在浏览器中访问 http://localhost:8080/order/request_sentinel4 ,在 Sentinel 的簇点
链路里找到 /request_sentinel4

在这里插入图片描述

3、点击授权按钮,进入授权规则配置框,按照如下方式进行配置

在这里插入图片描述
其中,流控应用填写的是 test,授权类型为黑名单。

这里要结合新建的 MyRequestOriginParser 类进行理解,MyRequestOriginParser 类的 parseOrigin() 方法如下所示:

public String parseOrigin(HttpServletRequest httpServletRequest) {return httpServletRequest.getParameter("serverName");
}

parseOrigin() 方法中直接返回了从 HttpServletRequest 中获取的 serverName 参数,而在上图中的流控应用中输出的是 test,授权类型为黑名单。

所以,如果我们访问 http://localhost:8080/order/request_sentinel4?serverName=test 的话,是处于黑名单的状态,无法访问

4、点击新增按钮后,不断在浏览器中刷新 http://localhost:8080/order/request_sentinel4? serverName=test ,会发现无法访问,被 Sentinel 限流了

在这里插入图片描述

3. 系统规则

系统保护规则是 应用整体维度 的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过
    系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
  • CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护

3.1 演示系统规则

1、在订单微服务的 com.zzc.order.handler 包下新建 MyUrlBlockHandler 类,如下所示:

@Component
public class MyUrlBlockHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {String msg = null;if (e instanceof FlowException) {msg = "限流了";} else if (e instanceof DegradeException) {msg = "降级了";} else if (e instanceof ParamFlowException) {msg = "热点参数限流";} else if (e instanceof SystemBlockException) {msg = "系统规则(负载/...不满足要求)";} else if (e instanceof AuthorityException) {msg = "授权规则不通过";}// http状态码response.setStatus(500);response.setCharacterEncoding("utf-8");response.setHeader("Content-Type", "application/json;charset=utf-8");response.setContentType("application/json;charset=utf-8");JSONObject jsonObject = new JSONObject();jsonObject.put("code", 500);jsonObject.put("codeMsg", msg);response.getWriter().write(jsonObject.toJSONString());}
}

2、在订单微服务的 SentinelController 类中新增 requestSentinel5() 方法,如下所示:

@GetMapping(value = "/request_sentinel5")
@SentinelResource("request_sentinel5")
public String requestSentinel5(){log.info("测试Sentinel5");return "sentinel5";
}

3、首先在浏览器中访问 http://localhost:8080/order/request_sentinel5 ,在 Sentinel 的簇点链路里找到 /request_sentinel5

在这里插入图片描述

4、点击流控按钮,进入流控规则配置框,按照如下方式进行配置

在这里插入图片描述

5、在浏览器中不断刷新 http://localhost:8080/order/request_sentinel5 ,会显示如下信息:

在这里插入图片描述

说明触发了系统规则,捕获到了Sentinel全局异常。

4. @SentinelResource 注解

使用 Sentinel 时,可以使用 @SentinelResource 注解来指定异常处理策略

4.1 @SentinelResource 注解概述

在 Sentinel 中,指定发生异常时的处理策略非常简单,只需要使用 @SentinelResource 注解即可。

@SentinelResource 注解的源码如下所示:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {//资源名称String value() default "";//entry类型,标记流量的方向,取值IN/OUT,默认是OUTEntryType entryType() default EntryType.OUT;int resourceType() default 0;//处理BlockException的函数名称,函数要求://1. 必须是 public//2.返回类型 参数与原方法一致//3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置//blockHandlerClass ,并指定blockHandlerClass里面的方法。String blockHandler() default "";//存放blockHandler的类,对应的处理函数必须static修饰。Class<?>[] blockHandlerClass() default {};//用于在抛出异常的时候提供fallback处理逻辑。 fallback函数可以针对所//有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求://1. 返回类型与原方法一致//2. 参数类型需要和原方法相匹配//3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定//fallbackClass里面的方法。String fallback() default "";//存放fallback的类。对应的处理函数必须static修饰。String defaultFallback() default "";//用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常进//行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求://1. 返回类型与原方法一致//2. 方法参数列表为空,或者有一个 Throwable 类型的参数。//3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定fallbackClass 里面的方法。Class<?>[] fallbackClass() default {};//指定排除掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};//需要trace的异常Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

4.2 演示 @SentinelResource 注解

4.2.1 定义限流和降级后的处理方法

1、在订单微服务的 com.zzc.order.service.SentinelService 接口中新增 sendMessage2()方法,SentinelServiceImpl 并实现之。

并且定义一个成员变量 count,用来记录请求 sendMessage2() 方法的次数,同时定义 25% 的异常率。

sendMessage2() 方法上使用 @SentinelResource 指定了资源的名称、发生 BlockException 时进入的方法和发生异常时进入的方法,代码如下所示:

private int count = 0;@Override
@SentinelResource(value = "sendMessage2", blockHandler = "blockHandler", fallback = "fallback")
public String sendMessage2() {count ++;//25%的异常率if (count % 4 == 0){throw new RuntimeException("25%的异常率");}return "sendMessage2";
}public String blockHandler(BlockException e){log.error("限流了:{}", e);return "限流了";
}
public String fallback(Throwable e){log.error("异常了:{}", e);return "异常了";
}

3、在订单微服务的 com.zzc.order.controller.SentinelController 类中新增requestSentinel6() 方法,如下所示:

@GetMapping(value = "/request_sentinel6")
public String requestSentinel6(){log.info("测试Sentinel6");return sentinelService.sendMessage2();
}

4、首先在浏览器中访问 http://localhost:8080/order/request_sentinel6 ,在 Sentinel 的簇点
链路里找到 /request_sentinel6

在这里插入图片描述

5、点击流控按钮进入流控规则页面,按照下图方式进行配置

在这里插入图片描述

6、点击新增按钮后在浏览器中刷新 http://localhost:8080/order/request_sentinel6 ,当刷新
的频率超过每秒 2 次时,浏览器会显示如下信息:

在这里插入图片描述

当刷新的次数是4的倍数时,浏览器会显示如下信息:

在这里插入图片描述

4.2.2 在外部类中指定限流和异常调用的方法

1、在订单微服务的 com.zzc.order.handler 包下新建 MyBlockHandlerClass类,用于定义被 Sentinel 限流时的方法,源码如下所示:

@Slf4j
public class MyBlockHandlerClass {public static String blockHandler(BlockException e){log.error("限流了:{}", e);return "限流了";}
}

2、在订单微服务的 com.zzc.order.handler 包下新建 MyFallbackClass 类,用于定义抛出异常时调用的方法,源码如下所示:

@Slf4j
public class MyFallbackClass {public static String fallback(Throwable e){log.error("异常了:{}", e);return "异常了";}
}

3、修改 SentinelServiceImpl#sendMessage2() 方法上的注解

@Override
@SentinelResource(value = "sendMessage2",blockHandlerClass = MyBlockHandlerClass.class,blockHandler = "blockHandler",fallbackClass = MyFallbackClass.class,fallback = "fallback")
public String sendMessage2() {count ++;System.out.println(count);//25%的异常率if (count % 4 == 0){throw new RuntimeException("25%的异常率");}return "sendMessage2";
}

更上述步骤一致,可进行测试

5. Sentinel 持久化

Sentinel 中可以自定义配置的持久化来将 Sentinel 的配置规则持久化到服务器磁盘,使得重启应用或者 Sentinel 后,Sentinel 的配置规则不丢失

5.1 Sentinel 持久化概述

细心的小伙伴会发现:

我们之前配置的 Sentinel 规则在程序重启或者 Sentinel 重启后就会消失不见。

此时,就需要我们重新配置。如果这发生在高并发、大流量的场景下是不可接受的。那有没有什么办法让程序或 Sentinel 重启后配置不丢失呢?其实,Sentinel 中可以自定义配置的持久化来解决这个问题。

5.2 实现 Sentinel 的持久化

1、在订单微服务 shop-order 中新建 com.zzc.order.persistence 包,并创建
SentinelPersistenceRule 类,实现 com.alibaba.csp.sentinel.init.InitFunc 接口,并在
SentinelPersistenceRule 类中获取应用的名称,覆写 init() 方法,源码如下所示:

public class SentinelPersistenceRule implements InitFunc {private String applicationName = "server-order";@Overridepublic void init() throws Exception {String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + applicationName;String flowRulePath = ruleDir + "/flow-rule.json";String degradeRulePath = ruleDir + "/degrade-rule.json";String systemRulePath = ruleDir + "/system-rule.json";String authorityRulePath = ruleDir + "/authority-rule.json";String paramFlowRulePath = ruleDir + "/param-flow-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);this.createFileIfNotExits(paramFlowRulePath);// 流控规则ReadableDataSource<String, List<FlowRule>> flowRuleRDS = newFileRefreshableDataSource<>(flowRulePath,flowRuleListParser);FlowRuleManager.register2Property(flowRuleRDS.getProperty());WritableDataSource<List<FlowRule>> flowRuleWDS = newFileWritableDataSource<>(flowRulePath,this::encodeJson);WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);// 降级规则ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = newFileRefreshableDataSource<>(degradeRulePath,degradeRuleListParser);DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());WritableDataSource<List<DegradeRule>> degradeRuleWDS = newFileWritableDataSource<>(degradeRulePath,this::encodeJson);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);// 系统规则ReadableDataSource<String, List<SystemRule>> systemRuleRDS = newFileRefreshableDataSource<>(systemRulePath,systemRuleListParser);SystemRuleManager.register2Property(systemRuleRDS.getProperty());WritableDataSource<List<SystemRule>> systemRuleWDS = newFileWritableDataSource<>(systemRulePath,this::encodeJson);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);// 授权规则ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = newFileRefreshableDataSource<>(authorityRulePath,authorityRuleListParser);AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());WritableDataSource<List<AuthorityRule>> authorityRuleWDS = newFileWritableDataSource<>(authorityRulePath,this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);// 热点参数规则ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = newFileRefreshableDataSource<>(paramFlowRulePath,paramFlowRuleListParser);ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = newFileWritableDataSource<>(paramFlowRulePath,this::encodeJson);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);}private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {});private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {});private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {});private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {});private void mkdirIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.mkdirs();}}private void createFileIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.createNewFile();}}private <T> String encodeJson(T t) {return JSON.toJSONString(t);}
}

2、在订单微服务的 resources 目录下新建 META-INF 目录,并在 META-INF 目录下新建 services 目录,在 services 目录下新建名称为 com.alibaba.csp.sentinel.init.InitFunc 的文件,如下所示:

在这里插入图片描述

3、在 com.alibaba.csp.sentinel.init.InitFunc 文件中添加 com.zzc.order.persistence.SentinelPersistenceRule 类的全类名,如下所示。:

在这里插入图片描述

4、首先在浏览器中访问http://localhost:8080/order/request_sentinel6 ,在 Sentinel 的簇点
链路里找到 /request_sentinel6

在这里插入图片描述

5、点击流控按钮进入流控规则页面,按照下图方式进行配置:

在这里插入图片描述

6、点击新增按钮,此时打开电脑的 user.home 目录,我电脑的目录为C:\Users\Administrator ,可以发现 C :\Users\Administrator 目录中多了一个 sentinel-rules目录:

在这里插入图片描述

7、打开 sentinel-rules 目录,发现里面存在一个 server-order 目录。
8、打开 server-order 目录后,会发现生成了 Sentinel 的配置文件,并持久化到了磁盘上,如下所示:

在这里插入图片描述

9、打开 flow-rule.json 文件,内容如下所示:

[{"clusterConfig": {"acquireRefuseStrategy": 0,"clientOfflineTime": 2000,"fallbackToLocalWhenFail": true,"resourceTimeout": 2000,"resourceTimeoutStrategy": 0,"sampleCount": 10,"strategy": 0,"thresholdType": 0,"windowIntervalMs": 1000},"clusterMode": false,"controlBehavior": 0,"count": 2.0,"grade": 1,"limitApp": "default","maxQueueingTimeMs": 500,"resource": "/request_sentinel6","strategy": 0,"warmUpPeriodSec": 10}
]

可以看到,flow-rule.json 文件中持久化了对于 /request_sentinel6 接口的配置。

重启订单微服务后,需要再次访问 http://localhost:8080/order/request_sentinel6 后,才能看见持久化后的配置

代码地址

代码已经上传至码云,码云地址

其中,数据库文件位于 db 文件夹下。

这篇关于【SpringCloud Alibaba】(八)学习 Sentinel 核心技术与配置规则(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106753

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现