服务容错治理框架resilience4jsentinel基础应用---微服务的限流/熔断/降级解决方案

继续上一章未完成的sentinel;

直接实操;

关于测试:本文使用线程池线程异步执行模拟并发结合Mock框架测试

 其他文章

服务容错治理框架resilience4j&sentinel基础应用---微服务的限流/熔断/降级解决方案-CSDN博客

conda管理python环境-CSDN博客

快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短链接请求改变浏览器地址等问题-CSDN博客

大模型LLMs的MCP入门-CSDN博客

使用LangGraph构建多代理Agent、RAG-CSDN博客

大模型LLMs框架Langchain之链详解_langchain.llms.base.llm详解-CSDN博客

大模型LLMs基于Langchain+FAISS+Ollama/Deepseek/Qwen/OpenAI的RAG检索方法以及优化_faiss ollamaembeddings-CSDN博客

大模型LLM基于PEFT的LoRA微调详细步骤---第二篇:环境及其详细流程篇-CSDN博客

大模型LLM基于PEFT的LoRA微调详细步骤---第一篇:模型下载篇_vocab.json merges.txt资源文件下载-CSDN博客 使用docker-compose安装Redis的主从+哨兵模式_使用docker部署redis 一主一从一哨兵模式 csdn-CSDN博客

docker-compose安装canal并利用rabbitmq同步多个mysql数据_docker-compose canal-CSDN博客

目录

Step1、引入依赖

Step2、启动dashboard控制台

Step3、配置application.yml

Demo1、限流FlowRule---自定义局部异常拦截

controller

测试

Demo2、限流FlowRule---使用自定义统一处理异常类

controller

定义:处理异常类UnifiedSentinelHandler.java

测试

Demo3、限流FlowRule---自定义全局异常处理类

controller

定义全局的统一处理类-低级:GlobalExceptionHandler.java

定义全局的统一处理类-高级:SentinelExceptionHandler.java

测试

Demo4、熔断DegradeRule---自定义全局异常

controller

测试

Demo5、授权AuthorityRule --- 自定义全局异常

controller

测试

Demo6、热点参数ParamFlowRule-自定义全局异常

controller

测试


Step1、引入依赖

<!-- 版本控制 --> <spring-boot.version>3.4.1</spring-boot.version><spring-cloud.version>2024.0.0</spring-cloud.version><spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>
<!-- 父项目依赖 --> <!-- spring boot 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!-- spring cloud 依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- spring cloud alibaba 依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!-- 子项目依赖 --><!-- SpringCloud Alibaba Sentinel --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!-- 引入Springboot-web SpringMVC --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

Step2、启动dashboard控制台

需要去官网下载“sentinel-dashboard-1.8.8.jar”版本自行选择...

登录WebUI:http://localhost:8080/#/login

密码账号:sentinel/sentinel    --- 默认的

启动命令:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar###CMD可能解析错误,所以用“""”转义
java "-Dserver.port=8080" "-Dcsp.sentinel.dashboard.server=localhost:8080" "-Dproject.name=sentinel-dashboard" -jar .\sentinel-dashboard-1.8.8.jar在项目中配置:spring.cloud.sentinel.transport.dashboard=localhost:8080,就可以将项目绑定在sentinel-dashboard中;

Step3、配置application.yml

spring:profiles:active: @profiles.active@### sentinel流量控制配置sentinel:.... 其他比如日志等配置略...eager: true # 取消控制台懒加载 即是否立即加载 Sentinel 规则transport:# 控制台地址 ... 目的是将这个注册到这个控制台,而不是在这个项目中打开控制台;# 如果要使用控制台,需要单独开启“sentinel-dashboard-1.8.8.jar”dashboard: 127.0.0.1:8080
#      filter:
#        enabled: false # 关闭 Web 层的自动资源名称生成web-context-unify: false # 打开调用链路

Demo1、限流FlowRule---自定义局部异常拦截

controller

@Slf4j
@RestController
@RequestMapping("/sentinel")
public class SentinelTestController {
/****************************************************************************************************************************//*** 案例一:自定义局部异常拦截:* blockHandler:Sentinel 流量控制或熔断、降级触发时执行的回调方法;方法参数、返回值类型要和partSentinel()方法一致;* fallback:业务逻辑抛出异常时才会执行;方法参数、返回值类型要和partSentinel()方法一致..*/@GetMapping("/part/{time}/{flag}")@SentinelResource(value = "part_sentinel", blockHandler = "partHandleBlock", fallback = "partFallbackMethod")public String partSentinel(@PathVariable("time") Long time, @PathVariable("flag") String flag) throws InterruptedException {if ("1".equals(flag)) {throw new NullPointerException("抛出异常...");}log.info("partSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("partSentinel 休眠结束...");return "partSentinel success";}private String partHandleBlock(Long time, String flag, BlockException ex) {return "熔断降级: " + ex.getClass().getSimpleName();}private String partFallbackMethod(Long time, String flag, Throwable ex) {return "方法执行异常: " + ex.getMessage();}/*** 如果使用了nacos那么要失效...* 使用这个只需要在浏览器连续访问即可*/@PostConstructprivate void partSentinelInitFlowRules() {FlowRule rule = new FlowRule();rule.setResource("part_sentinel");// FLOW_GRADE_QPS:基于QPS(每秒请求数)进行流量控制// FLOW_GRADE_THREAD:基于并发线程数进行流量控制rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);rule.setCount(1); // 每秒最多允许 1 个请求List<FlowRule> rules = new ArrayList<>();rules.add(rule);FlowRuleManager.loadRules(rules);}
}

测试

使用CompletableFuture.runAsync异步无返回值+for循环+线程池+MockMvc形式测试

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.hamcrest.Matchers.containsString;@SpringBootTest
@AutoConfigureMockMvc
public class SentinelTestControllerMockTest {@Autowiredprivate MockMvc mockMvc;static ThreadPoolExecutor threadPoolExecutor;static {/*** 5个核心线程、最多10个线程、5秒的线程空闲存活时间、能容纳100个任务的阻塞队列以及当任务无法添加到线程池时使用的策略;* 对于CPU密集型任务,你可能希望将核心线程数设置为与处理器数量相匹配;而对于IO密集型任务,则可以设置更高的线程数以提高并发度。*/threadPoolExecutor = new ThreadPoolExecutor(5,10,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),new ThreadPoolExecutor.CallerRunsPolicy());}/*** 测试流量控制(QPS = 1)* 连续发送两个请求,第二个会被限流* CompletableFuture.runAsync无返回值*/@Testvoid testQpsFlowControlRunAsync() throws Exception {List<CompletableFuture<Void>> futures = new ArrayList<>();for (int i = 0; i < 3; i++) {final int index = i + 1;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {String response = mockMvc.perform(get("/sentinel/part/1/0")).andReturn().getResponse().getContentAsString();System.out.println("请求[" + index + "] 成功: " + response);} catch (Exception e) {System.err.println("请求[" + index + "] 异常: " + e.getMessage());throw new RuntimeException("请求失败: " + e.getMessage(), e);}}, threadPoolExecutor);
//            future.join(); // 等待异步线程执行完毕// 添加到列表用于后续统一处理futures.add(future);}// 等待所有请求完成CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));// 可选:添加最终聚合操作allFutures.thenRun(() -> System.out.println("✅ 所有异步请求已完成"));// 阻塞主线程直到全部完成(测试用)allFutures.join();}/*** 测试业务异常触发 fallback*/@Testvoid testBusinessException() throws Exception {
//        mockMvc.perform(get("/sentinel/part/1/1"))
//                .andDo(MockMvcResultHandlers.print()) // 打印详细信息
//                .andExpect(status().isOk());System.out.println(mockMvc.perform(get("/sentinel/part/1/1")) // 打印返回值.andReturn().getResponse().getContentAsString());
//        mockMvc.perform(get("/sentinel/part/0/1"))
//                .andExpect(content().string("方法执行异常: 抛出异常..."));}
}

Demo2、限流FlowRule---使用自定义统一处理异常类

controller

    /*** 案例二:使用自定义统一处理异常类* 和案例一类似,方法参数、返回值保持一致;** @param time* @param flag* @return* @throws InterruptedException*/@GetMapping("/unified/{time}/{flag}")@SentinelResource(value = "unified_sentinel",blockHandlerClass = UnifiedSentinelHandler.class,blockHandler = "handleBlock1", // 指定熔断方法fallbackClass = UnifiedSentinelHandler.class,fallback = "fallbackMethod1")// 指定回调方public String unifiedSentinel(@PathVariable("time") Integer time, @PathVariable("flag") String flag) throws InterruptedException {if ("1".equals(flag)) {throw new NullPointerException("抛出异常...");}log.info("unifiedSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("unifiedSentinel 休眠结束...");return "unifiedSentinel success";}@PostConstructprivate void unifiedSentinelInitFlowRules() {List<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("unified_sentinel");// FLOW_GRADE_QPS:基于QPS(每秒请求数)进行流量控制// FLOW_GRADE_THREAD:基于并发线程数进行流量控制
//        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);rule.setCount(1);rules.add(rule);FlowRuleManager.loadRules(rules);}

定义:处理异常类UnifiedSentinelHandler.java

报错/限流熔断降级都会走这个类的返回值

public class UnifiedSentinelHandler {public static String handleBlock1(Integer time, String flag, BlockException ex) {/*** 限流了,会被抛出“FlowException”异常*/return "SentinelHandler handleBlock1: " + ex.getClass().getSimpleName();}public static String fallbackMethod1(Long time, String flag, Throwable ex) {return "SentinelHandler fallbackMethod1: " + ex.getMessage();}
}

测试

    /*** 案例二:使用自定义统一处理异常类:* 直接使用线程池测试** @throws Exception*/@Testvoid testDemo2QpsFlowControlThreadPool() throws Exception {// 第一个请求应该成功,后续会被限流/降级for (int i = 0; i < 3; i++) {threadPoolExecutor.execute(() -> {try {System.out.println(mockMvc.perform(get("/sentinel/unified/1/0")).andReturn().getResponse().getContentAsString());} catch (Exception e) {e.printStackTrace(); // 明确打印异常}});}// 使用Thread.sleep(2000);}/*** 案例二:使用自定义统一处理异常类:* 测试业务异常触发 fallback*/@Testvoid testDemo2BusinessException() throws Exception {System.out.println(mockMvc.perform(get("/sentinel/unified/1/1")).andReturn().getResponse().getContentAsString());}

Demo3、限流FlowRule---自定义全局异常处理类

controller

  /*** 案例三:自定义全局异常处理类;* 结合@RestControllerAdvice处理即“GlobalExceptionHandler/SentinelExceptionHandler.java”类* Throwable ---> Exception ---> BlockException ---> FlowException/DegradeException/ParamFlowException/AuthorityException* 在异常处理时,系统会依次捕获:所以不能同时将Throwable/Exception和FlowException/DegradeException/ParamFlowException/AuthorityException设置在同一个类中;* 所以如果要使用通用的异常处理类,并且要拦截Exception/Throwable* 可以将BlockException系列异常和Exception/Throwable分开,并利用@Order注解设置优先级;* 此处定义两个类:GlobalExceptionHandler(处理全局)、SentinelExceptionHandler(处理Sentinel相关异常)* 测试,限流:FlowException.class类* @param time* @param flag* @return* @throws InterruptedException*/@GetMapping("/globel/flow/{time}/{flag}")@SentinelResource(value = "globel_flow_sentinel")public String globleFlowSentinel(@PathVariable("time") Integer time, @PathVariable("flag") String flag) throws InterruptedException {if ("1".equals(flag)) {throw new RuntimeException("抛出异常...");}log.info("globleFlowSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("globleFlowSentinel 休眠结束...");return "globleFlowSentinel success";}@PostConstructprivate void globleFlowSentinelInitFlowRules() {List<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("globel_flow_sentinel");
//        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);rule.setGrade(RuleConstant.FLOW_GRADE_QPS);rule.setCount(1); // 每秒最多允许 1 个请求rules.add(rule);FlowRuleManager.loadRules(rules);
//        FlowRule{
//            resource=globel_flow_sentinel,
//                limitApp=default,
//                grade=0, // 0 表示线程数模式
//                count=1.0, // 限制并发线程数为 1
//                strategy=0, // 直接模式
//                controlBehavior=0, // 直接拒绝
//                warmUpPeriodSec=10, // 预热时间  ----- 有这个,所以启动项目以后,不能直接访问,要等几秒,限流才生效.
//                maxQueueingTimeMs=500 // 最大排队时间
//        }// 打印加载的规则log.info("Loaded flow rules: {}", FlowRuleManager.getRules());}

定义全局的统一处理类-低级:GlobalExceptionHandler.java

@RestControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE) // 最低优先级
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public Map<String, Object> handleException(Exception e) {log.error("捕获到Exception: ", e);return new HashMap<>() {{put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());put("msg", "服务器内部错误");}};}@ExceptionHandler(Throwable.class)public Map<String, Object> handleThrowable(Throwable e) {log.error("捕获到Throwable: ", e);return new HashMap<>() {{put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());put("msg", "系统异常");}};}
}

定义全局的统一处理类-高级:SentinelExceptionHandler.java


@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE) // 最高优先级
@Slf4j
public class SentinelExceptionHandler {@ExceptionHandler(FlowException.class)public Map<String, Object> handlerFlowException() {log.info("FlowException");return new HashMap<>() {{put("code", HttpStatus.TOO_MANY_REQUESTS.value());put("msg", "被限流");}};}@ExceptionHandler(DegradeException.class)public Map<String, Object> handlerDegradeException() {log.info("DegradeException");return new HashMap<>() {{put("code", HttpStatus.TOO_MANY_REQUESTS.value());put("msg", "被熔断");}};}@ExceptionHandler(ParamFlowException.class)public Map<String, Object> handlerParamFlowException() {log.info("ParamFlowException");return new HashMap<>() {{put("code", HttpStatus.TOO_MANY_REQUESTS.value());put("msg", "热点限流");}};}@ExceptionHandler(AuthorityException.class)public Map<String, Object> handlerAuthorityException() {log.info("AuthorityException");return new HashMap<>() {{put("code", HttpStatus.UNAUTHORIZED.value());put("msg", "暂无权限");}};}@ExceptionHandler(BlockException.class)public Map<String, Object> handleBlockException(BlockException e) {log.info("BlockException: {}", e.getClass().getSimpleName());return new HashMap<>() {{put("code", HttpStatus.TOO_MANY_REQUESTS.value());put("msg", "访问被限制");}};}
}

测试

 /*** 案例三:自定义全局异常处理类:* 直接使用线程池测试;* 限流返回:SentinelExceptionHandler里面的handlerFlowException方法“{"msg":"被限流","code":429}”** @throws Exception*/@Testvoid testDemo3QpsFlowControlThreadPool() throws Exception {// 第一个请求应该成功,后续会被限流/降级List<CompletableFuture<Void>> futures = new ArrayList<>();for (int i = 0; i < 10; i++) {final int index = i + 1;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {String response = mockMvc.perform(get("/sentinel/globel/flow/5/0")).andReturn().getResponse().getContentAsString();System.out.println("请求[" + index + "] 成功: " + response);} catch (Exception e) {System.err.println("请求[" + index + "] 异常: " + e.getMessage());throw new RuntimeException("请求失败: " + e.getMessage(), e);}}, threadPoolExecutor);
//            future.join(); // 等待异步线程执行完毕// 添加到列表用于后续统一处理futures.add(future);}// 等待所有请求完成CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));// 可选:添加最终聚合操作allFutures.thenRun(() -> System.out.println("✅ 所有异步请求已完成"));// 阻塞主线程直到全部完成(测试用)allFutures.join();}/*** 案例三:限流 --- 自定义全局异常处理类:* 测试业务异常触发 fallback;* 报错返回:GlobalExceptionHandler里面的handleException方法“{"msg":"服务器内部错误","code":500}”;* 如果没有设置Exception异常捕获那么会被handleFallback方法抛出“{"msg":"系统异常","code":500}”*/@Testvoid testDemo3FlowException() throws Exception {System.out.println(mockMvc.perform(get("/sentinel/globel/flow/1/1")).andReturn().getResponse().getContentAsString());}

Demo4、熔断DegradeRule---自定义全局异常

注意:完整的统一处理异常的类在demo3;

自定义全局;结合@RestControllerAdvice处理即“CustomExceptionHandler.java”类
* 测试熔断降级:DegradeException.class类

controller

    /*** 案例四:自定义全局;结合@RestControllerAdvice处理即“CustomExceptionHandler.java”类* 测试熔断降级:DegradeException.class类* <p>* 配置熔断规则方法一:在 Sentinel 控制台中,为资源 globelClass 添加降级规则,设置慢调用比例阈值(如响应时间超过 500ms 的比例超过 50%)* 配置熔断规则方法二:初始化DegradeRule** 在sentinel中不支持超时;只能由客户端控制该请求的时间,服务端无法控制;*  - 比如:在本案例中系统会阻塞在"Thread.sleep(time * 1000)(工作中,可能是第三方服务、redis、MySQL网络等原因造成)",*  - 如果每个请求都要阻塞了50s,那么只有在第三个请求时才会自动熔断降级;*  - 这样一来只能等1、2请求完毕也就是100s以后才会熔断降级*  官方目前好像没有自动超时熔断的方法;*  解决方法一:所以我们可以使用CompletableFuture.supplyAsync异步请求,并设置超时返回值:*         // 使用异步任务执行核心逻辑*          CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {*             try {*                 if ("1".equals(flag)) {*                     throw new RuntimeException("抛出异常...");*                 }*                 log.info("globleDegradeSentinel 休眠...{}s", time);*                 Thread.sleep(time * 1000);*                 log.info("globleDeggradeSentinel 休眠结束...");*                 return "globleDegradeSentinel success";*             } catch (InterruptedException e) {*                 Thread.currentThread().interrupt();*                 throw new RuntimeException("任务被中断", e);*             }*         });**         // 设置超时时间(例如 3 秒)*         try {*             return future.get(3, TimeUnit.SECONDS);*         } catch (Exception e) {*             future.cancel(true); // 中断任务*             log.warn("接口超时,已中断");*             return "请求超时,请稍后重试";*         }*  其他解决方法: ---- 不过这个是这个方法调用第三方接口的---对于本例的sleep方法不适用。*      server.servlet.session.timeout=3*      server.tomcat.connection-timeout=3000*      spring.mvc.async.request-timeout=3000 # 设置SpringMVC的超时时间为5s*/@GetMapping("/globel/degrade/{time}/{flag}")@SentinelResource(value = "globel_degrade_sentinel")public String globleDegradeSentinel(@PathVariable("time") Integer time, @PathVariable("flag") String flag) throws InterruptedException {if ("1".equals(flag)) {throw new RuntimeException("抛出异常...");}log.info("globleDegradeSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("globleDegradeSentinel 休眠结束...");return "globleDegradeSentinel success";}/*** 期望:在30s以内,有2个请求,接口响应时间超过 1000ms 时触发熔断,2s后恢复* 30s内请求2次:http://127.0.0.1:8077/weixin/sentinel/globel/degrade/5/10 被限制;哪怕是休眠时间结束了也会被限制;* 配置在nacos中的* {*         "resource": "globel_degrade_sentinel",*         "grade": 0,*         "count": 1000,*         "slowRatioThreshold": 0.1,*         "minRequestAmount":  2,*         "timeWindow": 2,*         "statIntervalMs": 30000*     }*/@PostConstructprivate void globleDegradeSentinelInitDegradeRules() {DegradeRule rule = new DegradeRule();rule.setResource("globel_degrade_sentinel");rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // // 基于响应时间的熔断rule.setCount(1000); // 响应时间超过 1000msrule.setTimeWindow(2); // 熔断时间窗口为 2 秒rule.setMinRequestAmount(2);  // 默认值,统计窗口内的最小请求数rule.setStatIntervalMs(30000); // 默认值,统计窗口长度为 30000msDegradeRuleManager.loadRules(Collections.singletonList(rule));// 打印加载的规则log.info("Loaded degrade rules: {}", DegradeRuleManager.getRules());}

测试

    /*** 案例四:熔断 --- 自定义全局异常处理类* 测试业务异常触发 熔断;* 正常情况,1、2会正常请求;3会熔断;4正常请求;5熔断;* 报错返回:CustomExceptionHandler/SentinelExceptionHandler里面的handlerDegradeException方法“{"msg":"被熔断","code":429}”;*/@Testvoid testDemo4DegradeException() throws Exception {for (int i = 1; i < 6; i++) {LocalTime now = LocalTime.now();System.out.printf("当前时间:%02d:%02d | 请求次数:%02d | 返回值:%s%n",now.getMinute(),now.getSecond(),i,mockMvc.perform(get("/sentinel/globel/degrade/10/0")).andReturn().getResponse().getContentAsString());Thread.sleep(1000);}}

Demo5、授权AuthorityRule --- 自定义全局异常

controller

    /*** 案例五:自定义全局;结合@RestControllerAdvice处理即“CustomExceptionHandler/GlobalExceptionHandler/SentinelExceptionHandler”类* 测试授权:AuthorityException.class类* <p>* 方法一:在 Sentinel 控制台中,为资源 globelClass 添加授权规则,设置黑名单或白名单。* 方法二:初始化AuthorityRule** @param time* @param flag* @return* @throws InterruptedException*/@GetMapping("/globel/auth/{time}/{flag}")@SentinelResource(value = "globel_auth_sentinel")public String globleAuthSentinel(@PathVariable("time") Integer time, @PathVariable("flag") String flag, HttpServletRequest request) throws InterruptedException {if ("1".equals(flag)) {throw new RuntimeException("抛出异常...");}
//        if ("2".equals(flag)) {
//            globleAuthSentinelInitAuthRules(getClientIpAddress(request));
//        }System.out.println(getClientIpAddress(request));log.info("globleAuthSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("globleAuthSentinel 休眠结束...");return "globleAuthSentinel success";}private String getClientIpAddress(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}// 如果经过多个代理,X-Forwarded-For 可能包含多个 IP,取第一个if (ip != null && ip.contains(",")) {ip = ip.split(",")[0].trim();}return ip;}/*** 如果我们使用Nacos管理配置,就可以配置如下内容* 配置在nacos中的* [* {* "resource": "globel_auth_sentinel",* "strategy": 1,* "limitApp": "192.168.3.58,192.168.3.49"* }* ]*/@PostConstructprivate void globleAuthSentinelInitAuthRules() {
//        globleAuthSentinelInitAuthRules("192.168.3.58");globleAuthSentinelInitAuthRules("可以设置为手机IP");}private void globleAuthSentinelInitAuthRules(String ip) {AuthorityRule rule = new AuthorityRule();rule.setResource("globel_auth_sentinel");
//        rule.setStrategy(RuleConstant.AUTHORITY_WHITE); // 白名单rule.setStrategy(RuleConstant.AUTHORITY_BLACK); // 黑名单rule.setLimitApp(ip); // 限制特定 IPAuthorityRuleManager.loadRules(Collections.singletonList(rule));// 打印加载的规则log.info("Loaded auth rules: {}", AuthorityRuleManager.getRules());}

测试

关于测试和其他测试有所不同,在配置的时候可以使用手机来测试;

step1、设置“rule.setStrategy(RuleConstant.AUTHORITY_BLACK); // 黑名单”,并设置ip为“127.0.0.1” --- 此步限制本地IP连接---主要是为了使用手机能连接进来;

step2、查看开发电脑的IP,使用CMD命令控制台:ipconfig(window使用命令)

step3、找到“无线局域网适配器 WLAN:"--->“IPv4 地址 . . . . . . . . . . . . : xxxx”;

step4、用手机请求地址:“xxx/globel/auth/3/2” ---- 这一步主要是为了利用“System.out.println(getClientIpAddress(request));”获取手机ip

step5、在rule.setLimitApp(ip)设置IP,将其设置为手机IP;

最后效果:

设置rule.setStrategy=RuleConstant.AUTHORITY_BLACK ip=127.0.0.1;手机可访问,电脑访问不了;

设置rule.setStrategy=RuleConstant.AUTHORITY_BLACK ip=手机IP;其余设备可访问,手机访问不了;

设置rule.setStrategy=RuleConstant.AUTHORITY_WHITE ip=127.0.0.1;电脑可访问,其余设备访问不了;

设置rule.setStrategy=RuleConstant.AUTHORITY_WHITE ip=手机IP;其余设备不可访问,手机可以访问;

Demo6、热点参数ParamFlowRule-自定义全局异常

controller

    /*** 案例六:自定义全局;结合@RestControllerAdvice处理即“CustomExceptionHandler.java”类* 测试热点参数:ParamFlowException.class类* <p>* 方法一:在 Sentinel 控制台中,为资源 globelClass 添加热点参数规则,设置特定参数值的 QPS 阈值。* 方法二:初始化AuthorityRule*/@GetMapping("/globel/paramflow/{time}/{flag}")@SentinelResource(value = "globel_param_flow_sentinel")public String globleParamFlowSentinel(@PathVariable("time") Integer time, @PathVariable("flag") String flag) throws InterruptedException {String threadName = Thread.currentThread().getName();Long threadId = Thread.currentThread().getId();System.out.printf("threadName: %s | threadId: %d \n", threadName, threadId);if ("1".equals(flag)) {throw new NullPointerException("抛出异常...");}log.info("globleParamFlowSentinel 休眠...{}s", time);Thread.sleep(time * 1000);log.info("globleParamFlowSentinel 休眠结束...");return "globleParamFlowSentinel success";}/*** 对参数索引为“1”下标位置的参数进行限制,即对参数flag进行限制;* 期望一:限流模式为线程数模式,即在20s内,携带flag参数的请求超过3次(http://127.0.0.1:8077/sentinel/globel/paramflow/10/0),第4次将被限流;其他地址请求到第6次限流* 期望二:对 flag=10 时,请求到第二次进行限流;当“http://127.0.0.1:8077/weixin/sentinel/globel/paramflow/10/10”请求到第2次时被限流* 期望三:对 flag=测试 时,请求到第三次进行限流;即“http://127.0.0.1:8077/sentinel/globel/paramflow/10/测试”请求到第3次时限流*/@PostConstructprivate void globleParamFlowSentinelInitParamFlowRules() {// 当“http://127.0.0.1:8077/sentinel/globel/paramflow/8/2”请求到第4次时被限流ParamFlowRule rule = new ParamFlowRule("globel_param_flow_sentinel").setParamIdx(1) // 参数索引(下标)(flag 参数) ;对应 SphU.entry(xxx, args) 中的参数索引位置
//                .setGrade(RuleConstant.FLOW_GRADE_THREAD) // 线程限流模式 .setGrade(RuleConstant.FLOW_GRADE_QPS) // QPS限流模式 .setDurationInSec(20) // 统计窗口时间 默认1s.setControlBehavior(0) // 流控制效果 匀速排队失败/快速失败(默认).setMaxQueueingTimeMs(0) // 最大排队等待时间 ,仅在匀速排队模式生效.setCount(3); // 限流阈值ParamFlowItem item1 = new ParamFlowItem();item1.setCount(1); // 阈值item1.setObject("10"); // 参数值 ---- 对“.setParamIdx()”位置的参数的值进行限制; 本例是对“flag”的值进行限制;item1.setClassType(String.class.getName()); // 参数类型ParamFlowItem item2 = new ParamFlowItem();item2.setCount(2); // 阈值item2.setObject("测试"); // 参数值 --- 当参数为“测试”时,请求到第二次被限流item2.setClassType(String.class.getName()); // 参数类型List<ParamFlowItem> rules = new ArrayList<>();rules.add(item1);rules.add(item2);rule.setParamFlowItemList(rules);ParamFlowRuleManager.loadRules(Collections.singletonList(rule));// 打印加载的规则log.info("Loaded ParamFlow rules: {}", ParamFlowRuleManager.getRules());}

测试

可以使用网页直接访问路径“/globel/paramflow/10/0”、“/globel/paramflow/10/10”、“/globel/paramflow/10/测试”;即可

使用Junit测试时

    /*** 案例六:热点参数* @throws Exception*/@Testvoid testDemo6ParamFlowException() throws Exception {// 第一个请求应该成功,后续会被限流/降级List<CompletableFuture<Void>> futures = new ArrayList<>();for (int i = 0; i < 10; i++) {final int index = i + 1;CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {try {String response = mockMvc.perform(get("/sentinel/globel/paramflow/8/2")).andReturn().getResponse().getContentAsString();System.out.println("请求[" + index + "] 成功,携带参数flag,第四次将被热点限流: " + response);} catch (Exception e) {System.err.println("请求[" + index + "] 异常: " + e.getMessage());throw new RuntimeException("请求失败: " + e.getMessage(), e);}}, threadPoolExecutor);CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {try {String response = mockMvc.perform(get("/sentinel/globel/paramflow/10/10")).andReturn().getResponse().getContentAsString();System.out.println("请求[" + index + "] 成功,携带参数flag=10,第2次将被热点限流: " + response);} catch (Exception e) {System.err.println("请求[" + index + "] 异常: " + e.getMessage());throw new RuntimeException("请求失败: " + e.getMessage(), e);}}, threadPoolExecutor);CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {try {String response = mockMvc.perform(get("/sentinel/globel/paramflow/10/测试")).andReturn().getResponse().getContentAsString();System.out.println("请求[" + index + "] 成功,携带参数flag=测试,第3次将被热点限流: " + response);} catch (Exception e) {System.err.println("请求[" + index + "] 异常: " + e.getMessage());throw new RuntimeException("请求失败: " + e.getMessage(), e);}}, threadPoolExecutor);
//            future.join(); // 等待异步线程执行完毕// 添加到列表用于后续统一处理futures.add(future1);futures.add(future2);futures.add(future3);}// 等待所有请求完成CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));// 可选:添加最终聚合操作allFutures.thenRun(() -> System.out.println("✅ 所有异步请求已完成"));// 阻塞主线程直到全部完成(测试用)allFutures.join();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解 C 语言中的变量作用域与链接性:`extern`、`static` 与全局变量

深入理解 C 语言中的变量作用域与链接性&#xff1a;extern、static 与全局变量 在 C 语言中&#xff0c;变量的作用域&#xff08;Scope&#xff09;和链接性&#xff08;Linkage&#xff09;是理解程序结构和模块化的关键概念。本文将详细探讨在函数外定义的变量是否为全局变…

实验三 软件黑盒测试

实验三 软件黑盒测试使用测试界的一个古老例子---三角形问题来进行等价类划分。输入三个整数a、b和c分别作为三角形的三条边&#xff0c;通过程序判断由这三条边构成的三角形类型是等边三角形、等腰三角形、一般三角形或非三角形(不能构成一个三角形)。其中要求输入变量&#x…

小米首个推理大模型开源——Xiaomi MiMo,为推理而战!

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、MiMo的惊人表现&#xff1a;小参数量&#xff0c;大能力二、双轮驱动&#…

《2025全球机器学习技术大会:阿里云讲师张玉明深度剖析通义灵码AI程序员》

4 月 18 日 - 19 日&#xff0c;由 CSDN & Boolan 联合举办的 2025 全球机器学习技术大会&#xff08;ML-Summit&#xff09;于上海顺利举行。大会聚焦人工智能与机器学习前沿技术&#xff0c;汇聚了来自科技与人工智能领域的数位顶尖专家以及数千名开发者和研究者&#xf…

MySQL事务隔离级别详解

MySQL事务隔离级别详解 事务隔离级别概述 MySQL支持四种标准的事务隔离级别&#xff0c;它们定义了事务在并发环境下的可见性规则和可能出现的并发问题&#xff1a; READ UNCOMMITTED&#xff08;读未提交&#xff09; • 最低隔离级别 • 事务可以读取其他事务未提交的数据&…

计算机视觉(CV)技术的优势和挑战(本片为InsCode)

计算机视觉&#xff08;CV&#xff09;技术是一种利用计算机和算法来模拟人类视觉实现图像和视频处理的技术。它在各个领域都有着广泛的应用&#xff0c;具有许多优势和挑战。 优势&#xff1a; 自动化&#xff1a;CV 技术可以自动识别、分类、跟踪和分析图像和视频数据&…

Android JIT编译:adb shell cmd package compile选项

Android JIT编译&#xff1a;adb shell cmd package compile选项 例如&#xff1a; adb shell cmd package compile -m speed -f --full 包名 配置参数指令说明&#xff1a; compile [-r COMPILATION_REASON] [-m COMPILER_FILTER] [-p PRIORITY] [-f] [--primary-dex] …

Android Kotlin 项目集成 Firebase Cloud Messaging (FCM) 全攻略

Firebase Cloud Messaging (FCM) 是 Google 提供的跨平台消息推送解决方案。以下是在 Android Kotlin 项目中集成 FCM 的详细步骤。 一、前期准备 1. 创建 Firebase 项目 访问 Firebase 控制台点击"添加项目"&#xff0c;按照向导创建新项目项目创建完成后&#x…

搭建PCDN大节点,服务器该怎么配

搭建P2P大节点时&#xff0c;服务器要怎么配呢&#xff1f;需要综合考虑硬件性能、网络带宽、存储能力、系统架构以及安全性等多个方面&#xff0c;以确保节点能够高效、稳定地运行。 一、硬件配置 CPU&#xff1a;选择高性能的多核处理器&#xff0c;以满足高并发处理需求。核…

(done) 吴恩达版提示词工程 8. 聊天机器人 (聊天格式设计,上下文内容,点餐机器人)

视频&#xff1a;https://www.bilibili.com/video/BV1Z14y1Z7LJ/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 别人的笔记&#xff1a;https://zhuanlan.zhihu.com/p/626966526 8. 聊天机器人&#xff08;Chatbot&#xff09; …

AtCoder Beginner Contest 403(题解ABCDEF)

A - Odd Position Sum #1.奇数数位和 #include<iostream> #include<vector> #include<stdio.h> #include<map> #include<string> #include<algorithm> #include<queue> #include<cstring> #include<stack> #include&l…

【Game】Powerful——Abandoned Ruins(9)

文章目录 1、新增古玩2、机关机制3、探索法宝4、智斗强敌5、地图6、参考 2025 年 1 月迎来的新玩法——荒废遗迹 每周四个宝藏铲&#xff08;老玩法&#xff09;或者两个遗迹线索&#xff08;新玩法&#xff09;&#xff0c;3 个宝藏铲也可以换一个遗迹线索&#xff0c;之前没时…

构建网页版IPFS去中心化网盘

前言&#xff1a;我把它命名为无限网盘 Unlimited network disks&#xff08;ULND&#xff09;&#xff0c;可以实现简单的去中心化存储&#xff0c;其实实现起来并不难&#xff0c;还是依靠强大的IPFS&#xff0c;跟着我一步一步做就可以了。 第一步&#xff1a;准备开发环境…

国标GB28181视频平台EasyGBS在物业视频安防管理服务中的应用方案​

一、方案背景​ 在现代物业服务中&#xff0c;高效的安全管理与便捷的服务运营至关重要。随着科技的不断发展&#xff0c;物业行业对智能化、集成化管理系统的需求日益增长。EasyGBS作为一款基于国标GB28181协议的视频监控平台&#xff0c;具备强大的视频管理与集成能力&#…

[Unity]设置自动打包脚本

背景 我们经常会使用自动打包功能 文件名称: AutoBuild.csusing System.IO; using System.Linq; using UnityEditor; using UnityEngine;public class AutoBuilder {[MenuItem("Build/GetCurrentBuildTarget")]public static void GetCurrentBuildTarget(){Debug.L…

正点原子STM32H743单片机实现ADC多通道检测

目标 使用STM32CubeMX工具&#xff0c;配置ADC相关参数&#xff0c;实现在STM32H743单片机上获取ADC多通道电压值。共14个ADC引脚&#xff0c;ADC2有5个&#xff0c;ADC3有9个&#xff0c;全部设置单通道 ADC引脚 PF3PF4PF5PF10PC0PC2PC3PH2PH3PA3PB0PB1PA4PA5PA6 STM32cube…

深度学习基础(四)——计算量(FLOPs)、参数量(Params)、计算速度(FLOPS/TOPS))

一、计算量FLOPs FLOPs&#xff0c;全称为Floating Point Operations, (s为复数缩写&#xff09;&#xff0c;浮点运算数&#xff0c;指模型完成一次前向传播所需的浮点运算次数&#xff0c;可以理解为计算量&#xff08;模型的时间复杂度&#xff09;&#xff0c;用来衡量算法…

电子秤检测管理系统开发实战:从数据采集到可视化大屏

简介 电子秤作为现代工业生产和商业流通中的核心计量设备,其准确性直接关系到产品质量和交易公平。针对仙贝生产企业的电子秤管理需求,我们开发了一套集电子秤检测信息录入、产品信息管理、实时称重数据采集和后台可视化大屏于一体的综合管理系统。该系统基于Django框架构建…

Cesium添加WMS,WMTS,地形图图,3D Tiles数据

在 Cesium 中&#xff0c;你可以添加 WMS、WMTS、地形图 和 3D Tiles 数据源。以下是详细的实现方法&#xff1a; 1. 添加 WMS 服务 WMS&#xff08;Web Map Service&#xff09;是一种动态地图服务&#xff0c;适用于加载栅格地图图层。 代码示例 const viewer new Cesium…

数据库基本概念:数据库的定义、特点、分类、组成、作用

一&#xff1a;数据库相关概念 1.1 定义 &#xff08;1&#xff09;数据库&#xff1a;存储数据的仓库 &#xff08;2&#xff09;数据库管理系统&#xff1a;模拟和管理数据库的大型软件 &#xff08;3&#xff09;SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;定义…