当前位置 : 首页 > 保养数据

Spring Cloud Alibaba Sentinel 整合 Feign:限流熔断与自定义降级实战

<|begin▁of▁sentence|># 1. 概述 本文分享 **Spring Cloud Alibaba 之 Sentinel 与 Feign 的整合**。Sentinel 提供了 `feign-sentinel` 的整合模块,提供 Feign 调用的限流、熔断等功能。 > 另外,在早期 Sentinel 还未提供 `feign-sentinel` 整合模块时,Spring Cloud Alibaba 通过自定义的 [SentinelInvocationHandler](https://github.com/alibaba/spring-cloud-alibaba/blob/2.2.x/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java) ,实现了对 Feign 调用的限流、熔断等功能。目前,该方式已经**废弃**,使用 Sentinel 提供的方案。 # 2. 快速入门 > 示例代码对应仓库: > > - 服务提供者:`labx-10-sc-sentinel-demo01-provider` > - 服务消费者:`labx-10-sc-sentinel-feign-demo01-consumer` 本小节,我们会在服务消费者中,使用 Feign 调用服务提供者提供的 HTTP 接口。同时,我们会使用 Sentinel 对该 Feign 调用进行限流。 ## 2.1 服务提供者 创建服务提供者 `labx-10-sc-sentinel-demo01-provider` 项目,提供服务 HTTP 接口。代码比较简单,如下: - 创建 [ProviderController](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/providerdemo/controller/ProviderController.java) 类,提供 `/demo/echo` 接口。 ## 2.2 服务消费者 创建服务消费者 `labx-10-sc-sentinel-feign-demo01-consumer` 项目,使用 Feign 调用服务提供者的 HTTP 接口。 ### 2.2.1 引入依赖 创建 [`pom.xml`](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo01-consumer/pom.xml) 文件中,引入相关依赖。 ```xml labx-10 cn.iocoder.springboot.labs 1.0-SNAPSHOT 4.0.0 labx-10-sc-sentinel-feign-demo01-consumer 2.2.4.RELEASE Hoxton.SR1 2.2.0.RELEASE org.springframework.boot spring-boot-dependencies ${spring.boot.version} pom import org.springframework.cloud spring-cloud-dependencies ${spring.cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${spring.cloud.alibaba.version} pom import org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-sentinel org.springframework.cloud spring-cloud-starter-openfeign com.alibaba.cloud spring-cloud-alibaba-sentinel-feign ``` 重点引入 `spring-cloud-alibaba-sentinel-feign` 依赖,实现对 Sentinel 对 Feign 的整合。 ### 2.2.2 配置文件 创建 [`application.yaml`](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo01-consumer/src/main/resources/application.yaml) 配置文件,添加相关配置。 ```yaml server: port: 8081 spring: application: name: demo-consumer cloud: # Sentinel 配置 sentinel: # 控制台地址 transport: dashboard: 192.168.3.196:7070 # 服务提供者的配置 provider: service: url: http://127.0.0.1:8080 # Feign 配置 feign: # Sentinel 配置 sentinel: enabled: true # 开启 Feign 对 Sentinel 的支持 ``` **重点**是 `feign.sentinel.enabled` 配置项,设置为 `true`,开启 Feign 对 Sentinel 的支持。 ### 2.2.3 ProviderService 创建 [ProviderService](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/service/ProviderService.java) 接口,作为 Feign 声明式调用接口。代码如下: ```java @FeignClient(name = "demo-provider", url = "${provider.service.url}") public interface ProviderService { @GetMapping("/demo/echo") String echo(); } ``` - 通过 `@FeignClient` 注解,声明一个 Feign 客户端,其中 `name` 为服务名,`url` 指向服务提供者的地址。 ### 2.2.4 ConsumerController 创建 [ConsumerController](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/controller/ConsumerController.java) 类,提供使用 Feign 声明式调用服务的 HTTP 接口。代码如下: ```java @RestController public class ConsumerController { @Autowired private ProviderService providerService; @GetMapping("/feign_echo") public String feignEcho() { return providerService.echo(); } } ``` ### 2.2.5 DemoConsumerApplication 创建 [DemoConsumerApplication](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/DemoConsumerApplication.java) 类,作为应用启动类。代码如下: ```java @SpringBootApplication @EnableFeignClients public class DemoConsumerApplication { public static void main(String[] args) { SpringApplication.run(DemoConsumerApplication.class, args); } } ``` ## 2.3 简单测试 ① 首先,启动服务提供者 `labx-10-sc-sentinel-demo01-provider` 项目。 ② 然后,启动服务消费者 `labx-10-sc-sentinel-feign-demo01-consumer` 项目。 ③ 最后,访问服务消费者的 http://127.0.0.1:8081/feign_echo 接口,保证 Feign 调用是成功的。返回结果如下: ``` echo:172.16.88.183:8080 ``` 此时,我们打开 Sentinel 控制台,可以看到 Feign 调用对应的**资源名**为 `GET:http://127.0.0.1:8080/demo/echo`。如下图所示:![资源列表](Spring Cloud Alibaba 之 Sentinel 与 Feign 的整合.assets/01.png) 并且,此时该资源的**实时监控**如下:![实时监控](Spring Cloud Alibaba 之 Sentinel 与 Feign 的整合.assets/11.png) ④ 给 `GET:http://127.0.0.1:8080/demo/echo` 资源设置一个每秒 1 次的限流规则。如下图所示:![限流规则](Spring Cloud Alibaba 之 Sentinel 与 Feign 的整合.assets/12.png) 然后,我们快速访问 http://127.0.0.1:8081/feign_echo 接口,会看到被限流的错误提示。返回结果如下: ``` Blocked by Sentinel (flow limiting) ``` 并且,此时该资源的**实时监控**如下:![实时监控](Spring Cloud Alibaba 之 Sentinel 与 Feign 的整合.assets/13.png) # 3. 整合说明 > 友情提示:本小节为选读,不感兴趣的同学可以跳过。 在 `feign-sentinel` 的整合模块中,Sentinel 自定义了 [SentinelFeign](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-feign-adapter/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelFeign.java) 类,通过 [Feign 的 Builder 模式](https://www.iocoder.cn/Spring-Cloud/Feign/?self),创建了具有 Sentinel 功能的 Feign 客户端。 SentinelFeign 的创建代码如下: ```java // SentinelFeign.java public final class SentinelFeign { public static Builder builder() { return new Builder(); } public static final class Builder extends Feign.Builder { // ... 省略中间代码 @Override public Feign build() { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map dispatch) { // 创建「SentinelInvocationHandler」对象,并将 dispatch 包装成具有 Sentinel 功能的 MethodHandler 映射 return new SentinelInvocationHandler(target, dispatch); } }); // 设置 Contract 为 SentinelContractHolder,用于创建具有 Sentinel 功能的 MethodHandler super.contract(new SentinelContractHolder(contract)); return super.build(); } } } ``` - 通过创建 [SentinelInvocationHandler](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-feign-adapter/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelInvocationHandler.java) 类,作为 Feign 调用的 InvocationHandler 处理器。这样,每次 Feign 调用,都会触发 `SentinelInvocationHandler#invoke(...)` 方法,从而调用 Sentinel 的 API,实现限流、熔断等功能。 - 通过创建 [SentinelContractHolder](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-feign-adapter/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelContractHolder.java) 类,在创建 Feign 调用的 MethodHandler 时,包装成具有 Sentinel 功能的 [SentinelMethodHandler](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-feign-adapter/src/main/java/com/alibaba/cloud/sentinel/feign/SentinelMethodHandler.java) 类。 # 4. 自定义 Fallback > 示例代码对应仓库: > > - 服务提供者:`labx-10-sc-sentinel-demo01-provider` > - 服务消费者:`labx-10-sc-sentinel-feign-demo02-consumer` 在 Sentinel 与 Feign 的整合中,我们可以通过定义 [Fallback](https://github.com/OpenFeign/feign/wiki/Custom-error-handling#fallback) 类,在 Feign 调用被限流、熔断时,返回 Fallback 处理结果,实现**服务降级**的效果。 本小节,我们会在[「2. 快速入门」](https://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/Feign/?self#)的小节的基础上,进行 Fallback 功能的演示。 ## 4.1 服务消费者 创建服务消费者 `labx-10-sc-sentinel-feign-demo02-consumer` 项目,使用 Feign 调用服务提供者的 HTTP 接口。 ### 4.1.1 引入依赖 和[「2.2.1 引入依赖」](https://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/Feign/?self#)一致,见 [`pom.xml`](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/pom.xml) 文件。 ### 4.1.2 配置文件 和[「2.2.2 配置文件」](https://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/Feign/?self#)一致,见 [`application.yaml`](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/src/main/resources/application.yaml) 文件。 ### 4.1.3 ProviderService 修改 [ProviderService](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/service/ProviderService.java) 接口,增加 `fallback` 配置项,设置 Fallback 处理类为 ProviderServiceFallback。代码如下: ```java @FeignClient(name = "demo-provider", url = "${provider.service.url}", fallback = ProviderServiceFallback.class) public interface ProviderService { @GetMapping("/demo/echo") String echo(); } ``` 创建 [ProviderServiceFallback](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/service/ProviderServiceFallback.java) 类,实现 ProviderService 接口,作为 Fallback 处理类。代码如下: ```java @Component public class ProviderServiceFallback implements ProviderService { @Override public String echo() { return "fallback"; } } ``` ### 4.1.4 ConsumerController 和[「2.2.4 ConsumerController」](https://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/Feign/?self#)一致,见 [ConsumerController](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/controller/ConsumerController.java) 类。 ### 4.1.5 DemoConsumerApplication 和[「2.2.5 DemoConsumerApplication」](https://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/Feign/?self#)一致,见 [DemoConsumerApplication](https://github.com/YunaiV/SpringBoot-Labs/blob/master/labx-10-spring-cloud-alibaba-sentinel/labx-10-sc-sentinel-feign-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx10/sentineldemo/consumerdemo/DemoConsumerApplication.java) 类。 ## 4.2 简单测试 ① 首先,启动服务提供者 `labx-10-sc-sentinel-demo01-provider` 项目。 ② 然后,启动服务消费者 `labx-10-sc-sentinel-feign-demo02-consumer` 项目。 ③ 最后,访问服务消费者的 http://127.0.0.1:8081/feign_echo 接口,保证 Feign 调用是成功的。 ④ 给 `GET:http://127.0.0.1:8080/demo/echo` 资源设置一个每秒 1 次的限流规则。 然后,我们快速

栏目列表