四、搭建springCloudAlibaba2021.1版本分布式微服务-加入openFeign远程调用和sentinel流量控制

发布时间:2022-07-08 21:46:03 作者:yexindonglai@163.com 阅读(1117)

OpenFeign远程调用

1、OpenFeign  

  OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。

2、Feign与OpenFeign的区别  

  Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务。  

  OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

说明:springcloud F 及F版本以上 springboot 2.0 以上基本上使用openfeign,openfeign 如果从框架结构上看就是2019年feign停更后出现版本,也可以说大多数新项目都用openfeign ,2018年以前的项目在使用 feign。

Sentinel流量控制

1、Sentinel简介

  Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。

官网:https://github.com/alibaba/Sentinel/wiki

Sentinel主要特性:

2、Sentinel与Hystrix的区别


关于Sentinel与Hystrix的区别见:https://yq.aliyun.com/articles/633786/

总体来说:

  Hystrix常用的线程池隔离会造成线程上下切换的overhead比较大;Hystrix使用的信号量隔离对某个资源调用的并发数进行控制,效果不错,但是无法对慢调用进行自动降级;Sentinel通过并发线程数的流量控制提供信号量隔离的功能;

此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。

  Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。

Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。

openFeign整合Sentinel

第一个项目 spring-cloud-alibaba-2021-user(调用者)

创建项目名为 spring-cloud-alibaba-2021-user

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring-cloud-alibaba-2021</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>spring-cloud-alibaba-2021-user</artifactId>
  12. <dependencies>
  13. <!-- springweb 启动依赖 -->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-web</artifactId>
  17. </dependency>
  18. <!-- nacos 服务注册发现(客户端)依赖 -->
  19. <dependency>
  20. <groupId>com.alibaba.cloud</groupId>
  21. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  22. </dependency>
  23. <!-- nacos-config 配置中心依赖 -->
  24. <dependency>
  25. <groupId>com.alibaba.cloud</groupId>
  26. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  27. </dependency>
  28. <!--spring-cloud-dependencies 2020.0.0 版本不在默认加载bootstrap.yml 文件,如果需要加载bootstrap 文件需要手动添加依赖-->
  29. <dependency>
  30. <groupId>org.springframework.cloud</groupId>
  31. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  32. </dependency>
  33. <!--openfeign-->
  34. <dependency>
  35. <groupId>org.springframework.cloud</groupId>
  36. <artifactId>spring-cloud-starter-openfeign</artifactId>
  37. </dependency>
  38. <!--loadbalancer ,负载均衡,用来替代ribbon的组件 -->
  39. <dependency>
  40. <groupId>org.springframework.cloud</groupId>
  41. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  42. </dependency>
  43. <!-- sentinel流量控制,必须加上后降级和限流才会生效-->
  44. <dependency>
  45. <groupId>com.alibaba.cloud</groupId>
  46. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  47. </dependency>
  48. </dependencies>
  49. </project>

application.yml 内容如下

  1. server:
  2. port: 8089
  3. spring:
  4. # 后面的bean会覆盖前面相同名称的bean
  5. main:
  6. allow-bean-definition-overriding: true
  7. # 激活Sentinel对Feign的支持,默认为false。必须设为true后sentinel降级才会生效
  8. feign:
  9. sentinel:
  10. enabled: true

bootstrap.yml 内容如下,bootstrap.yml 文件比 application.yml 先加载,主要用于存放一些不会改变的配置,application.yml 存放一些经常需要改动的配置;

  1. spring:
  2. application:
  3. name: user-demo
  4. profiles:
  5. active: yexindong_active
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: chn520.cn:8848 # 服务注册中心地址
  10. namespace: public # 注册到nacos的名称空间,默认为public
  11. config:
  12. prefix: yexindong_nacos_prefix
  13. file-extension: yaml # 指定yaml格式的配置, 必须要放到bootstrao.yml 才会生效,放到application下不会生效
  14. server-addr: chn520.cn:8848 #配置中心地址
  15. group: DEFAULT_GROUP

父项目的 pom.xml 文件加入modules

  1. <modules>
  2. <module>spring-cloud-alibaba-2021-user</module>
  3. </modules>

新建启动类 UserApp.java

  1. package com.alibaba.cloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.openfeign.EnableFeignClients;
  6. @SpringBootApplication
  7. @EnableDiscoveryClient
  8. @EnableFeignClients // // 开启feign远程调用
  9. public class UserApp {
  10. public static void main(String[] args) {
  11. SpringApplication.run(UserApp.class, args);
  12. }
  13. }

新建controller层 UserController.java

  1. package com.alibaba.cloud.controller;
  2. import com.alibaba.cloud.feign.OrderClient;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.cloud.context.config.annotation.RefreshScope;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. @RestController
  9. @RefreshScope // 不重启即可刷新 nacos配置
  10. @RequestMapping("/user")
  11. public class UserController {
  12. // 调用order远程服务
  13. @RequestMapping("/getOrder")
  14. public String getOrder(){
  15. return orderClient.getOrderById();
  16. }
  17. }

远程调用接口 OrderClient.java

  1. package com.alibaba.cloud.feign;
  2. import com.alibaba.cloud.feign.fallback.OrderFallback;
  3. import org.springframework.cloud.openfeign.FeignClient;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. /**
  6. * value : 其他远程服务的名称,对应配置文件的 spring.application.name 值
  7. * name: 和value功能一样
  8. * path : url前缀,和 @RequestMapping 注解功能类似
  9. * fallback : 降级回调的实现类,当被调服务不可用、发生异常或者超时会直接走降级逻辑,返回友好提示
  10. */
  11. @FeignClient(value="order-demo",path = "order",fallback = OrderFallback.class)
  12. public interface OrderClient {
  13. @GetMapping("/getOrderById")
  14. String getOrderById();
  15. }

添加降级回调类 OrderFallback.java

  1. package com.alibaba.cloud.feign.fallback;
  2. import com.alibaba.cloud.feign.OrderClient;
  3. import org.springframework.stereotype.Component;
  4. /**
  5. * 降级回调类
  6. */
  7. @Component
  8. public class OrderFallback implements OrderClient {
  9. public String getOrderById() {
  10. return "order服务暂时不可用!!!";
  11. }
  12. }

此时 项目结构如下

创建第二个项目 spring-cloud-alibaba-2021-order (被调者)

新建工程,起名为 spring-cloud-alibaba-2021-order

pom.xml 文件内容如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring-cloud-alibaba-2021</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>spring-cloud-alibaba-2021-order</artifactId>
  12. <dependencies>
  13. <!-- springweb 启动依赖 -->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-web</artifactId>
  17. </dependency>
  18. <!-- nacos 服务注册发现(客户端)依赖 -->
  19. <dependency>
  20. <groupId>com.alibaba.cloud</groupId>
  21. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  22. </dependency>
  23. <!-- nacos-config 配置中心依赖 -->
  24. <dependency>
  25. <groupId>com.alibaba.cloud</groupId>
  26. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  27. </dependency>
  28. <!--spring-cloud-dependencies 2020.0.0 版本不在默认加载bootstrap.yml 文件,如果需要加载bootstrap 文件需要手动添加依赖-->
  29. <dependency>
  30. <groupId>org.springframework.cloud</groupId>
  31. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  32. </dependency>
  33. <!--openfeign-->
  34. <dependency>
  35. <groupId>org.springframework.cloud</groupId>
  36. <artifactId>spring-cloud-starter-openfeign</artifactId>
  37. </dependency>
  38. <!--loadbalancer ,负载均衡,用来替代ribbon的组件 -->
  39. <dependency>
  40. <groupId>org.springframework.cloud</groupId>
  41. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  42. </dependency>
  43. </dependencies>
  44. </project>

application.yml 内容如下

  1. server:
  2. port: 8088
  3. spring:
  4. # 后面的bean会覆盖前面相同名称的bean
  5. main:
  6. allow-bean-definition-overriding: true

bootstrap.yml 内容如下

  1. spring:
  2. application:
  3. name: order-demo
  4. profiles:
  5. active: yexindong_active
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: chn520.cn:8848 # 服务注册中心地址
  10. namespace: public # 注册到nacos的名称空间,默认为public
  11. config:
  12. prefix: yexindong_nacos_prefix
  13. file-extension: yaml # 指定yaml格式的配置, 必须要放到bootstrao.yml 才会生效,放到application下不会生效
  14. server-addr: chn520.cn:8848 #配置中心地址
  15. group: DEFAULT_GROUP

启动类 OrderApp.java 内容如下

  1. package com.alibaba.cloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.openfeign.EnableFeignClients;
  6. @SpringBootApplication
  7. @EnableDiscoveryClient
  8. @EnableFeignClients // // 开启feign远程调用
  9. public class OrderApp {
  10. public static void main(String[] args) {
  11. SpringApplication.run(OrderApp.class, args);
  12. }
  13. }

controller层 OrderController.java 内容如下

  1. package com.alibaba.cloud.controller;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.cloud.context.config.annotation.RefreshScope;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. @RefreshScope // 不重启即可刷新 nacos配置
  8. @RequestMapping("/order")
  9. public class OrderController {
  10. @Value("${cache:default}")
  11. private String cache;
  12. @RequestMapping("/getOrderById")
  13. public String getOrderById(){
  14. return "yexindong order" + cache;
  15. }
  16. }

此时项目结构如下

修改 nacos 配置,添加 yexindong_nacos_prefix-yexindong_active.yaml文件
此时会打开新建配置的页面,

  1. DataId 输入:yexindong_nacos_prefix-yexindong_active.yaml
  2. 配置格式 选择: YAML
  3. 配置内容 中输入:cache: hello openFeign sentinal!!! `
  4. 点击 右下角的 发布 按钮

测试

启动 OrderApp.java 和 UserApp.java 中的main方法,一会后发现这2个服务已经注册到nacos了

在浏览器输入 http://localhost:8089/user/getOrder,可以正常访问

测试熔断降级

接下来我们修改一下OrderController.java中的 getOrderById() 方法,增加一行代码,System.out.println(1/0); 让程序在运行中抛出异常,修改后的内容如下

  1. @RequestMapping("/getOrderById")
  2. public String getOrderById(){
  3. System.out.println(1/0);
  4. return "yexindong order" + cache;
  5. }

然后重启 orderApp ,再次访问 http://localhost:8089/user/getOrder,发现已经出发了熔断,返回了falllback 的友好提示

配置 openFeign 日志

有时候我们遇到bug,接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置OpenFeignde的日志了,以此让openFeign把请求信息输出来。

OpenFeign提供了日志打印功能,我们可以通过配置来调整日恙级别,从而了解Feign 中 Http请求的细节。

日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据;
    全局配置
    添加 OpenFeignConfig.java 文件,内容如下
    ```java
    package com.alibaba.cloud.config;
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

/**

  • 全局配置:当使用@Configuration 会将配置作用所有的服务提供方
  • 局部配置:如果只想针对某一个服务进行配置,就不要加@Configuration
    /
    @Configuration
    public class OpenFeignConfig {
    /

    日志级别:
    1. NONE:默认的,不显示任何日志;
    2. BASIC:仅记录请求方法、URL、响应状态码及执行时间;
    3. HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
    4. FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据;
    */
    @Bean
    public Logger.Level feignLoggerLevel(){
    1. return Logger.Level.FULL;
    }
    }
    ```

application.yml加上以下配置

  1. # openfeign配置包下(或指定哪些业务接口)以什么日志级别监听,springboot的默认日志级别是info,openFeign的日志级别debug就不会输出,所以需要加上此配置
  2. logging:
  3. level:
  4. com:
  5. alibaba:
  6. cloud:
  7. feign: debug

重新请求后就可以在控制台打印日志了;

局部配置:方式一

直接在接口上指定,在@FeignClient注解加上configuration = OpenFeignConfig.class属性

  1. package com.alibaba.cloud.feign;
  2. import com.alibaba.cloud.feign.fallback.OrderFallback;
  3. import org.springframework.cloud.openfeign.FeignClient;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. /**
  6. * value : 其他远程服务的名称,对应配置文件的 spring.application.name 值
  7. * name: 和value功能一样
  8. * path : url前缀,和 @RequestMapping 注解功能类似
  9. * fallback : 降级回调的实现类,当被调服务不可用、发生异常或者超时会直接走降级逻辑,返回友好提示
  10. */
  11. @FeignClient(value="order-demo",path = "order",fallback = OrderFallback.class,configuration = OpenFeignConfig.class)
  12. public interface OrderClient {
  13. @GetMapping("/getOrderById")
  14. String getOrderById();
  15. }

注意:这种方式需要将OpenFeignConfig.java类的@Configuration注解去掉,否则会变成全局配置

局部配置:方式二

application.yml 添加以下配置

  1. # openfeign日志局部配置
  2. feign:
  3. client:
  4. config:
  5. order-demo:
  6. loggerLevel: basic

超时时间配置

方式一:添加配置类

创建配置类 OpenFeignTimeOutConfig.java,内容如下

  1. package com.alibaba.cloud.config;
  2. import feign.Request;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. @Configuration
  6. public class OpenFeignTimeOutConfig {
  7. /**
  8. * 超时时间配置
  9. * @return
  10. */
  11. @Bean
  12. public Request.Options options(){
  13. // Options 的第一个参数是连接的超时时间(ms),默认值是 2s;第二个是请求处理的超时时间(ms),默认值是 5s。
  14. return new Request.Options(5000,10000);
  15. }
  16. }
方式二:配置文件修改

application.yml 添加配置

  1. feign:
  2. client:
  3. config:
  4. order-demo:
  5. # 配置指定服务连接超时(单位:ms)
  6. connectTimeout: 5000
  7. # 配置指定服务等待超时(单位:ms)
  8. readTimeout: 5000
  9. default:
  10. # 配置所有服务的连接超时时间(单位:ms)
  11. connectTimeout: 5000
  12. # 配置所有服务的等待超时时间(单位:ms)
  13. readTimeout: 5000

自定义拦截器

全局配置

添加拦截器类CustomFeignInterceptor.java

  1. package com.alibaba.cloud.interceptor;
  2. import feign.RequestInterceptor;
  3. import feign.RequestTemplate;
  4. import org.springframework.context.annotation.Configuration;
  5. /**
  6. * 自定义feign拦截器
  7. */
  8. @Configuration
  9. public class CustomFeignInterceptor implements RequestInterceptor {
  10. @Override
  11. public void apply(RequestTemplate requestTemplate) {
  12. System.out.println("执行openFeign自定义拦截器");
  13. }
  14. }
局部配置

如果写在配置文件中指明了服务,则为具体的服务指定一个或者多个拦截器, 在 application.yml 加入以下内容

  1. # 在配置文件中设置feign拦截器
  2. feign:
  3. client:
  4. config:
  5. order-demo:
  6. # openFeign拦截器
  7. requestInterceptors[0]: com.alibaba.cloud.interceptor.CustomFeignInterceptor

再次请求http://127.0.0.1:8089/user/getOrder发现已经打印了拦截器的内容

关键字SpringCloud