服務容錯治理框架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.pswp.cn/news/903767.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903767.shtml
英文地址,請注明出處:http://en.pswp.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;定義…