From 07e7e978dc20c58bebb00d05a0d943509edc3160 Mon Sep 17 00:00:00 2001 From: qyx <565485304@qq.com> Date: Sun, 29 Sep 2024 15:42:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(master):sentinel=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 代码完成 --- .../SpringCloud项目介绍.md | 3 +- .../README.md | 3 + .../dev-protocol-springcloud-sentinel/pom.xml | 76 +++++++++++++++++ .../example/SentinelClientApplication.java | 18 +++++ .../example/block_handler/QBlockHandler.java | 29 +++++++ .../conf/RestTemplateExceptionUtil.java | 44 ++++++++++ .../java/org/example/conf/SentinelConfig.java | 26 ++++++ .../controller/FlowRuleCodeController.java | 81 +++++++++++++++++++ .../controller/RateLimitController.java | 43 ++++++++++ .../SentinelFallbackController.java | 72 +++++++++++++++++ .../controller/SentinelFeignController.java | 33 ++++++++ .../SentinelRestTemplateController.java | 53 ++++++++++++ .../fallback_handler/QFallbackHandler.java | 33 ++++++++ .../example/feign/SentinelFeignClient.java | 20 +++++ .../feign/SentinelFeignClientFallback.java | 22 +++++ .../src/main/resources/bootstrap.yml | 59 ++++++++++++++ .../main/resources/http/flow-rule-code.http | 3 + .../src/main/resources/http/rate-limit.http | 7 ++ .../resources/http/sentinel-fallback.http | 12 +++ .../resources/http/sentinel-feign-client.http | 3 + .../http/sentinel-rest-template.http | 8 ++ pom.xml | 1 + 22 files changed, 648 insertions(+), 1 deletion(-) create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/README.md create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/pom.xml create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/SentinelClientApplication.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/block_handler/QBlockHandler.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/RestTemplateExceptionUtil.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/SentinelConfig.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/FlowRuleCodeController.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/RateLimitController.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFallbackController.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFeignController.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelRestTemplateController.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/fallback_handler/QFallbackHandler.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClient.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClientFallback.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/bootstrap.yml create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/flow-rule-code.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/rate-limit.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-fallback.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-feign-client.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-rest-template.http diff --git a/dev-protocol-springcloud/SpringCloud项目介绍.md b/dev-protocol-springcloud/SpringCloud项目介绍.md index c31245c..434697f 100644 --- a/dev-protocol-springcloud/SpringCloud项目介绍.md +++ b/dev-protocol-springcloud/SpringCloud项目介绍.md @@ -37,4 +37,5 @@ - [dev-protocol-springcloud-project-goods-service](dev-protocol-springcloud-project-goods-service) - 订单微服务 - [dev-protocol-springcloud-project-order-service](dev-protocol-springcloud-project-order-service) -- 物流微服务 \ No newline at end of file +- 物流微服务 + - [dev-protocol-springcloud-project-logistics-service](dev-protocol-springcloud-project-logistics-service) \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/README.md b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/README.md new file mode 100644 index 0000000..3f6cfc7 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/README.md @@ -0,0 +1,3 @@ +# sentinel + + diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/pom.xml b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/pom.xml new file mode 100644 index 0000000..fc23223 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + org.example + dev-protocol + 1.0-SNAPSHOT + ../../pom.xml + + + dev-protocol-springcloud-sentinel + 1.0-SNAPSHOT + jar + + + dev-protocol-springcloud-sentinel + Sentinel Client + + + 8 + 8 + UTF-8 + + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + com.alibaba.csp + sentinel-datasource-nacos + + + + org.example + dev-protocol-springcloud-project-mvc-config + 1.0-SNAPSHOT + + + + + + ${artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/SentinelClientApplication.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/SentinelClientApplication.java new file mode 100644 index 0000000..93ad36a --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/SentinelClientApplication.java @@ -0,0 +1,18 @@ +package org.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +/** + *

Sentinel 集成到 SpringCloud 工程中

+ * */ +@EnableFeignClients +@EnableDiscoveryClient +@SpringBootApplication +public class SentinelClientApplication { + public static void main(String[] args) { + SpringApplication.run(SentinelClientApplication.class, args); + } +} \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/block_handler/QBlockHandler.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/block_handler/QBlockHandler.java new file mode 100644 index 0000000..f9af17c --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/block_handler/QBlockHandler.java @@ -0,0 +1,29 @@ +package org.example.block_handler; + +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.fastjson2.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.vo.CommonResponse; + +/** + *

自定义通用的限流处理逻辑

+ * */ +@Slf4j +public class QBlockHandler { + + + /** + *

通用限流处理方法

+ * 这个方法必须是 static 的 + * */ + public static CommonResponse qHandleBlockException(BlockException exception) { + + log.error("trigger q block handler: [{}], [{}]", + JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp()); + return new CommonResponse<>( + -1, + "flow rule trigger block exception", + null + ); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/RestTemplateExceptionUtil.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/RestTemplateExceptionUtil.java new file mode 100644 index 0000000..d05bcde --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/RestTemplateExceptionUtil.java @@ -0,0 +1,44 @@ +package org.example.conf; + +import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.vo.JwtToken; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; + +/** + *

RestTemplate 在限流或异常时的兜底方法

+ * */ +@Slf4j +public class RestTemplateExceptionUtil { + + /** + *

限流后的处理方法

+ * */ + public static SentinelClientHttpResponse handleBlock(HttpRequest request, + byte[] body, + ClientHttpRequestExecution execution, + BlockException ex) { + log.error("Handle RestTemplate Block Exception: [{}], [{}]", + request.getURI().getPath(), ex.getClass().getCanonicalName()); + return new SentinelClientHttpResponse( + JSON.toJSONString(new JwtToken("q-block")) + ); + } + + /** + *

异常降级之后的处理方法

+ * */ + public static SentinelClientHttpResponse handleFallback(HttpRequest request, + byte[] body, + ClientHttpRequestExecution execution, + BlockException ex) { + log.error("Handle RestTemplate Fallback Exception: [{}], [{}]", + request.getURI().getPath(), ex.getClass().getCanonicalName()); + return new SentinelClientHttpResponse( + JSON.toJSONString(new JwtToken("q-block")) + ); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/SentinelConfig.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/SentinelConfig.java new file mode 100644 index 0000000..26e5ae8 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/conf/SentinelConfig.java @@ -0,0 +1,26 @@ +package org.example.conf; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + *

开启服务间的调用保护, 需要给 RestTemplate 做一些包装

+ * */ +@Slf4j +@Configuration +public class SentinelConfig { + + /** + *

包装 RestTemplate

+ * */ + @Bean +// @SentinelRestTemplate( +// fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class, +// blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class +// ) + public RestTemplate restTemplate() { + return new RestTemplate(); // 可以对其做一些业务相关的配置 + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/FlowRuleCodeController.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/FlowRuleCodeController.java new file mode 100644 index 0000000..98e1521 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/FlowRuleCodeController.java @@ -0,0 +1,81 @@ +package org.example.controller; + +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import com.alibaba.csp.sentinel.slots.block.BlockException; +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 com.alibaba.fastjson2.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.block_handler.QBlockHandler; +import org.example.vo.CommonResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; + +/** + *

流控规则硬编码的 Controller

+ * */ +@Slf4j +@RestController +@RequestMapping("/code") +public class FlowRuleCodeController { + + /** + *

初始化流控规则

+ * */ + @PostConstruct + public void init() { + + // 流控规则集合 + List flowRules = new ArrayList<>(); + // 创建流控规则 + FlowRule flowRule = new FlowRule(); + // 设置流控规则 QPS, 限流阈值类型 (QPS, 并发线程数) + flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); + // 流量控制手段 + flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); + // 设置受保护的资源 + flowRule.setResource("flowRuleCode"); + // 设置受保护的资源的阈值 + flowRule.setCount(1); + flowRules.add(flowRule); + + // 加载配置好的规则 + FlowRuleManager.loadRules(flowRules); + } + + /** + *

采用硬编码限流规则的 Controller 方法

+ * */ + @GetMapping("/flow-rule") +// @SentinelResource(value = "flowRuleCode") +// @SentinelResource(value = "flowRuleCode", blockHandler = "handleException") + @SentinelResource( + value = "flowRuleCode", blockHandler = "qHandleBlockException", + blockHandlerClass = QBlockHandler.class + ) + public CommonResponse flowRuleCode() { + log.info("request flowRuleCode"); + return new CommonResponse<>(0, "", "q-ecommerce"); + } + + /** + *

当限流异常抛出时, 指定调用的方法

+ * 是一个兜底策略, 必须和上面使用的方法在一个类中 + * */ + public CommonResponse handleException(BlockException exception) { + log.error("has block exception: [{}]", JSON.toJSONString(exception.getRule())); + return new CommonResponse<>( + -1, + "flow rule exception", + exception.getClass().getCanonicalName() + ); + } + + +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/RateLimitController.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/RateLimitController.java new file mode 100644 index 0000000..283de8c --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/RateLimitController.java @@ -0,0 +1,43 @@ +package org.example.controller; + +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import lombok.extern.slf4j.Slf4j; +import org.example.block_handler.QBlockHandler; +import org.example.vo.CommonResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

基于 Sentinel 控制台配置流控规则

+ * Sentinel 是懒加载的, 先去访问一下, 就可以在 Sentinel Dashboard 看到了 + * */ +@Slf4j +@RestController +@RequestMapping("/dashboard") +public class RateLimitController { + + /** + *

在 dashboard 中 "流控规则" 中按照资源名称新增流控规则

+ * */ + @GetMapping("/by-resource") + @SentinelResource( + value = "byResource", + blockHandler = "qHandleBlockException", + blockHandlerClass = QBlockHandler.class + ) + public CommonResponse byResource() { + log.info("coming in rate limit controller by resource"); + return new CommonResponse<>(0, "", "byResource"); + } + + /** + *

在 "簇点链路" 中给 url 添加流控规则

+ * */ + @GetMapping("/by-url") + @SentinelResource(value = "byUrl") + public CommonResponse byUrl() { + log.info("coming in rate limit controller by url"); + return new CommonResponse<>(0, "", "byUrl"); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFallbackController.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFallbackController.java new file mode 100644 index 0000000..b64b1c7 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFallbackController.java @@ -0,0 +1,72 @@ +package org.example.controller; + +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.fallback_handler.QFallbackHandler; +import org.example.vo.JwtToken; +import org.example.vo.UsernameAndPassword; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; + +/** + *

Sentinel 提供容错降级的功能

+ * */ +@SuppressWarnings("all") +@Slf4j +@RestController +@RequestMapping("/sentinel-fallback") +public class SentinelFallbackController { + + /** 注入没有增强的 RestTemplate */ + private final RestTemplate restTemplate; + + public SentinelFallbackController(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @PostMapping("/get-token") + @SentinelResource( + value = "getTokenFromAuthorityService", + fallback = "getTokenFromAuthorityServiceFallback", + fallbackClass = { QFallbackHandler.class } + ) + public JwtToken getTokenFromAuthorityService( + @RequestBody UsernameAndPassword usernameAndPassword) { + + String requestUrl = + "http://127.0.0.1:7000/dev-protocol-springcloud-project-authority-center/authority/token"; + log.info("RestTemplate request url and body: [{}], [{}]", + requestUrl, JSON.toJSONString(usernameAndPassword)); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + return restTemplate.postForObject( + requestUrl, + new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers), + JwtToken.class + ); + } + + /** + *

让 Sentinel 忽略一些异常

+ * */ + @GetMapping("/ignore-exception") + @SentinelResource( + value = "ignoreException", + fallback = "ignoreExceptionFallback", + fallbackClass = { QFallbackHandler.class }, + exceptionsToIgnore = { NullPointerException.class } + ) + public JwtToken ignoreException(@RequestParam Integer code) { + + if (code % 2 == 0) { + throw new NullPointerException("yout input code is: " + code); + } + + return new JwtToken("qinyi-imooc"); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFeignController.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFeignController.java new file mode 100644 index 0000000..2f805c4 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelFeignController.java @@ -0,0 +1,33 @@ +package org.example.controller; + +import lombok.extern.slf4j.Slf4j; +import org.example.feign.SentinelFeignClient; +import org.example.vo.CommonResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + *

OpenFeign 集成 Sentinel 实现熔断降级

+ * */ +@Slf4j +@RestController +@RequestMapping("/sentinel-feign") +public class SentinelFeignController { + + private final SentinelFeignClient sentinelFeignClient; + + public SentinelFeignController(SentinelFeignClient sentinelFeignClient) { + this.sentinelFeignClient = sentinelFeignClient; + } + + /** + *

通过 Feign 接口去获取结果

+ * */ + @GetMapping("/result-by-feign") + public CommonResponse getResultByFeign(@RequestParam Integer code) { + log.info("coming in get result by feign: [{}]", code); + return sentinelFeignClient.getResultByFeign(code); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelRestTemplateController.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelRestTemplateController.java new file mode 100644 index 0000000..2d58b3a --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/controller/SentinelRestTemplateController.java @@ -0,0 +1,53 @@ +package org.example.controller; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.vo.JwtToken; +import org.example.vo.UsernameAndPassword; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + *

使用 Sentinel 保护 RestTemplate 服务间调用

+ * */ +@Slf4j +@RestController +@RequestMapping("/sentinel-rest-template") +public class SentinelRestTemplateController { + + private final RestTemplate restTemplate; + + public SentinelRestTemplateController(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + /** + *

从授权服务中获取 JwtToken

+ * 1. 流控降级: + * 是针对于簇点链路中的 http://127.0.0.1:7000/ecommerce-authority-center/authority/token + * 2. 容错降级: 对于服务不可用时不能生效 + * */ + @PostMapping("/get-token") + public JwtToken getTokenFromAuthorityService( + @RequestBody UsernameAndPassword usernameAndPassword) { + + String requestUrl = + "http://127.0.0.1:7000/dev-protocol-springcloud-project-authority-center/authority/token"; + log.info("RestTemplate request url and body: [{}], [{}]", + requestUrl, JSON.toJSONString(usernameAndPassword)); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + return restTemplate.postForObject( + requestUrl, + new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers), + JwtToken.class + ); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/fallback_handler/QFallbackHandler.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/fallback_handler/QFallbackHandler.java new file mode 100644 index 0000000..f019816 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/fallback_handler/QFallbackHandler.java @@ -0,0 +1,33 @@ +package org.example.fallback_handler; + +import com.alibaba.fastjson2.JSON; +import lombok.extern.slf4j.Slf4j; +import org.example.vo.JwtToken; +import org.example.vo.UsernameAndPassword; + +/** + *

Sentinel 回退降级的兜底策略

+ * 都需要是静态方法 + * */ +@Slf4j +public class QFallbackHandler { + + /** + *

getTokenFromAuthorityService 方法的 fallback

+ * */ + public static JwtToken getTokenFromAuthorityServiceFallback( + UsernameAndPassword usernameAndPassword + ) { + log.error("get token from authority service fallback: [{}]", + JSON.toJSONString(usernameAndPassword)); + return new JwtToken("q-fallback"); + } + + /** + *

ignoreException 方法的 fallback

+ * */ + public static JwtToken ignoreExceptionFallback(Integer code) { + log.error("ignore exception input code: [{}] has trigger exception", code); + return new JwtToken("q-fallback"); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClient.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClient.java new file mode 100644 index 0000000..ecbae1b --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClient.java @@ -0,0 +1,20 @@ +package org.example.feign; + +import org.example.vo.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + *

通过 Sentinel 对 OpenFeign 实现熔断降级

+ * */ +@FeignClient( + value = "dev-protocol-springcloud-sentinel-null", // 定义不存在的服务名称, 测试是否正常执行 + fallback = SentinelFeignClientFallback.class +) +public interface SentinelFeignClient { + + @RequestMapping(value = "qinyi", method = RequestMethod.GET) + CommonResponse getResultByFeign(@RequestParam Integer code); +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClientFallback.java b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClientFallback.java new file mode 100644 index 0000000..7e394d9 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/java/org/example/feign/SentinelFeignClientFallback.java @@ -0,0 +1,22 @@ +package org.example.feign; + +import lombok.extern.slf4j.Slf4j; +import org.example.vo.CommonResponse; +import org.springframework.stereotype.Component; + +/** + *

Sentinel 对 OpenFeign 接口的降级策略

+ * */ +@Slf4j +@Component +public class SentinelFeignClientFallback implements SentinelFeignClient{ + @Override + public CommonResponse getResultByFeign(Integer code) { + log.error("request supply for test has some error: [{}]", code); + return new CommonResponse<>( + -1, + "sentinel feign fallback", + "input code: "+ code + ); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/bootstrap.yml b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..2d6028c --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/bootstrap.yml @@ -0,0 +1,59 @@ +server: + port: 8100 + servlet: + context-path: /dev-protocol-springcloud-sentinel + +spring: + application: + name: dev-protocol-springcloud-sentinel # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时) + cloud: + nacos: + # 服务注册发现 + discovery: + enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可 + server-addr: 127.0.0.1:8848 + # server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 # Nacos 服务器地址 + namespace: 1ccc74ae-9398-4dbe-b9d7-4f9addf9f40c + metadata: + management: + context-path: ${server.servlet.context-path}/actuator + sentinel: + # 配置 sentinel dashboard 地址 + transport: + dashboard: 127.0.0.1:7777 + port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互 + datasource: + # 名称任意, 代表数据源 + ds: + nacos: + # NacosDataSourceProperties.java 中定义 + server-addr: ${spring.cloud.nacos.discovery.server-addr} + dataId: ${spring.application.name}-sentinel + namespace: ${spring.cloud.nacos.discovery.namespace} + groupId: DEFAULT_GROUP + data-type: json + # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType + # FlowRule 就是限流规则 + rule-type: flow + # 服务启动直接建立心跳连接 + eager: true + +# 暴露端点 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: always + +# 打开 Sentinel 对 Feign 的支持 +feign: + sentinel: + enabled: true + +# 开启或关闭 @SentinelRestTemplate 注解 +resttemplate: + sentinel: + enabled: true diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/flow-rule-code.http b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/flow-rule-code.http new file mode 100644 index 0000000..7c02a6d --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/flow-rule-code.http @@ -0,0 +1,3 @@ +### 硬编码的流控规则 +GET 127.0.0.1:8100/dev-protocol-springcloud-sentinel/code/flow-rule +Content-Type: application/json diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/rate-limit.http b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/rate-limit.http new file mode 100644 index 0000000..e7ccbe4 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/rate-limit.http @@ -0,0 +1,7 @@ +### 根据资源名称限流 +GET 127.0.0.1:8100/dev-protocol-springcloud-sentinel/dashboard/by-resource +Content-Type: application/json + +### 根据 URL 限流 +GET 127.0.0.1:8100/dev-protocol-springcloud-sentinel/dashboard/by-url +Content-Type: application/json diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-fallback.http b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-fallback.http new file mode 100644 index 0000000..76cd68d --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-fallback.http @@ -0,0 +1,12 @@ +### 获取 token +POST 127.0.0.1:8100/dev-protocol-springcloud-sentinel/sentinel-fallback/get-token +Content-Type: application/json + +{ + "username": "1@qqq.com", + "password": "25d55ad283aa400af464c76d713c07ad" +} + +### 忽略异常 +GET 127.0.0.1:8100/dev-protocol-springcloud-sentinel/sentinel-fallback/ignore-exception?code=2 +Content-Type: application/json diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-feign-client.http b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-feign-client.http new file mode 100644 index 0000000..67fd1f3 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-feign-client.http @@ -0,0 +1,3 @@ +### Sentinel Feign Client +GET 127.0.0.1:8100/dev-protocol-springcloud-sentinel/sentinel-feign/result-by-feign?code=200 +Content-Type: application/json diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-rest-template.http b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-rest-template.http new file mode 100644 index 0000000..1f4620b --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-sentinel/src/main/resources/http/sentinel-rest-template.http @@ -0,0 +1,8 @@ +### 获取 Token +POST 127.0.0.1:8100/dev-protocol-springcloud-sentinel/sentinel-rest-template/get-token +Content-Type: application/json + +{ + "username": "1@qqq.com", + "password": "25d55ad283aa400af464c76d713c07ad" +} diff --git a/pom.xml b/pom.xml index bc97e08..417463d 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,7 @@ dev-protocol-springcloud/dev-protocol-springcloud-message-study dev-protocol-springcloud/dev-protocol-springcloud-project-order-service dev-protocol-springcloud/dev-protocol-springcloud-project-logistics-service + dev-protocol-springcloud/dev-protocol-springcloud-sentinel