行百里er 行百里er
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)

行百里er

Java程序员一枚
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)
  • 系统架构演进与Spring Cloud Alibaba简介
  • 万字长文:Spring Cloud Alibaba组件之Nacos实战及Nacos客户端服务注册源码解析
  • 服务容错的必要性与Spring Cloud Alibaba Sentinel 限流配置实战
  • Spring Cloud Alibaba Sentinel 熔断降级策略实战
  • Spring Cloud Alibaba:将 Sentinel 熔断限流规则持久化到 Nacos 配置中心
  • Sentinel限流降级如何优雅的返回?SentinelResource注解之blockHander和fallback
  • 微服务间的远程接口调用:OpenFeign 的使用
  • 强强联合:OpenFeign 整合 Sentinel
    • 前言
    • 准备
      • Jar 包依赖
      • 配置文件
      • 全局统一异常处理
    • 操练
      • @FeignClient 的 fallback
      • @SentinelResource 限流
    • 小结
  • 网关 Spring Cloud Gateway - API 调用的组织者
  • Spring Cloud Gateway 网关限流
  • Spring Cloud Sleuth 整合 Zipkin 进行服务链路追踪
  • 高级版的 jvisualvm :Spring Boot Admin 监控 Spring Boot 微服务项目
  • 分布式事务解决方案之 Seata(一):分布式事务的常见解决方案及 Seata 简介
  • Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
  • 分布式事务解决方案之 Seata(二):Seata AT 模式
  • Spring Cloud Alibaba
行百里er
2022-08-19
目录

强强联合:OpenFeign 整合 Sentinel

作者:行百里er

博客:https://chendapeng.cn (opens new window)

提示

这里是 行百里er 的博客:行百里者半九十,凡事善始善终,吾将上下而求索!

# 前言

书接前文:

微服务间的远程接口调用:OpenFeign 的使用 (opens new window)

当项目中使用了 OpenFeign 后,可以很方便的进行远程服务调用,现在有个问题,假如远程服务出现故障了,调不了远程的接口,这边又着急等着返回结果,怎么办呢?

当然是使用 服务降级 ,本篇就使用 OpenFeign 进行远程调用,并结合 Sentinel 对出现的异常、故障等问题进行服务降级。

# 准备

仍以前面 open-feign-service 服务为调用方, nacos-provider 服务为提供方来进行操练。

# Jar 包依赖

open-feign-service 除了引入 spring-cloud-starter-openfeign 外,再引入 spring-cloud-starter-alibaba-sentinel 组件,另外我们这里使用 nacos 的配置中心做 Sentinel 限流规则的持久化,所以还需要引入 spring-cloud-alibaba-sentinel-datasource 和 sentinel-datasource-nacos :

<!-- 引入二方库 -->
<dependency>
    <groupId>cn.chendapeng.springcloud</groupId>
    <artifactId>internal-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

image-20220819160608694.png

# 配置文件

配置文件 application.yml :

spring:
  application:
    name: open-feign-service

  cloud:
    nacos:
      discovery:
        server-addr: 192.168.242.112:81
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
      # https://github.com/alibaba/Sentinel/issues/1213
      web-context-unify: false
      # Sentinel 规则持久化到 Nacos
      datasource:
        rule1:
          nacos:
            serverAddr: 192.168.242.112:81
            groupId: DEFAULT_GROUP
            dataId: sentinelFlowRule.json
            ruleType: flow
            
feign:
  client:
    config:
      # 默认的超时时间设置
      default:
        connectTimeout: 5000
        readTimeout: 5000
      # 在指定的 FeignClient 设置超时时间,覆盖默认的设置
      nacos-provider:
        connectTimeout: 1000
        readTimeout: 1000
        loggerLevel: full
  # 激活 Sentinel
  sentinel:
    enabled: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

这里增加了 Sentinel 的数据持久化内容,以及激活 OpenFeign 与 Sentinel 联合使用的 feign.sentinel.enabled=true 配置。

# 全局统一异常处理

不管是 Sentinel 限流后返回,还是 OpenFeign 的 fallback 返回,本质上他们都是出现异常了,这里配置一下全局的统一异常处理。

首先,增加一个业务异常类:

public class BusinessException extends RuntimeException {

    private String code;

    private String message;

    public BusinessException(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

然后使用 Spring 的 @RestControllerAdvice 注解进行全局的异常进行处理:

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 业务异常,统一处理
     * @param e 异常对象
     * @return ResponseResult 全局异常响应
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseResult<String> businessException(BusinessException e) {
        LOGGER.info("code={}, message={}", e.getCode(), e.getMessage());
        return ResponseResult.fail(e.getCode(), e.getMessage());
    }

    // 其他异常...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这样,只要指定了抛出的异常类型,就会返回统一的响应格式。

# 操练

# @FeignClient 的 fallback

在上一篇文章中,我们通过 FeignClient 接口调用远程的服务:

@Service
@FeignClient("nacos-provider")
public interface ProductService {

    /**
     * 调用远程服务 nacos-provider 的 product/{id} 接口
     * @param id 参数 id
     * @return 返回
     */
    @GetMapping("/product/{id}")
    String getProductById(@PathVariable("id") Long id);
}
1
2
3
4
5
6
7
8
9
10
11
12

如果远程接口不通,这里可以在 @FeignClient 注解上增加一个属性 fallback ,该属性定义一个容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback 指定的类必须实现 @FeignClient 标记的接口。

先来定义一个实现 ProductService 的类:

@Component
@Slf4j
public class ProductServiceImpl implements ProductService {

    /**
     * 调用远程服务 nacos-provider 的 product/{id} 接口失败后的处理方法
     *
     * @param id 参数 id
     * @return 返回
     */
    @Override
    public String getProductById(Long id) {
        log.error("调用接口 getProduct 失败,id={}", id);
        //return "OpenFeign 降级";
        throw new BusinessException(ResponseCode.RPC_ERROR.getCode(), ResponseCode.RPC_ERROR.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

该类需要被 Spring 识别,所以加个 @Component 。该类的实现方法可以添加实际业务的处理逻辑,本案例只是打印一些信息后直接抛出自定义的异常。

Tips :ResponseCode.RPC_ERROR 在二方库中有定义。

给 FeignClient 接口增加 fallback 属性:

@FeignClient(name = "nacos-provider", fallback = ProductServiceImpl.class)
1

OK,不启动服务提供方 nacos-provider,直接调用接口测试。

接口返回:

image-20220819163044024.png

控制台打印信息:

image-20220819162946588.png

这样就实现了 fallback 的容错处理,即时远程服务不可用,也能进行降级处理。

# @SentinelResource 限流

在 Controller 层使用 FeignClient 定义的接口进行远程调用服务时,还可以定义 Sentinel 资源,并设置规则对资源进行限流。

@SentinelResource 的一些使用方法在前几篇文章中已有提及,这里再结合 OpenFeign 使用,本例中有如下定义:

@GetMapping("/product/{id}")
@SentinelResource(value = "getProduct",
                  blockHandler = "getProductBlock",
                  fallback = "getProductFallback")
public String getProduct(@PathVariable("id") Long id) {
    return productService.getProductById(id);
}

public String getProductBlock(Long id, BlockException e) {
    log.error("访问资源 getProduct 被限流,id={}", id);
    throw new BusinessException("C0002", "访问资源 getProduct 被限流");
}

public String getProductFallback(Long id) {
    log.error("访问资源 getProduct fallback");
    return "请稍后重试";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在前面的准备工作中,我们已经配置了 Sentinel 资源限流规则持久化到 Nacos,现在 Nacos 中配置一下资源 getProduct 的限流规则:

[
  {
    "resource": "getProduct",
    "limitApp": "default",
    "grade": 1,
    "count": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  }
]
1
2
3
4
5
6
7
8
9
10
11

image-20220819164001324.png

限流规则是 QPS 阈值为1,只要我1秒大于1次请求就会被限流。

启动远程服务 nacos-provider ,下面来验证一下。

1秒只发一个请求的结果:

image-20220819164448540.png

1秒内快速刷新几次,造成QPS大于1,将会被限流:

image-20220819164343886.png

# 小结

  • OpenFeign 整合 Sentinel 需要引入 Sentinel 相关依赖包;
  • 在配置文件通过 feign.sentinel.enabled=true 来开启 Feign 与 Sentinel的结合使用;
  • 在 @FeignClient 注解中增加 fallback 属性,该属性定义远程接口访问有问题时的容错处理逻辑的类;
  • fallback 定义的类需实现 @FeignClient 定义的接口。

首发公众号 行百里er ,欢迎老铁们关注阅读指正。

#Spring Cloud Alibaba#微服务
上次更新: 2022/10/04, 18:14:30
微服务间的远程接口调用:OpenFeign 的使用
网关 Spring Cloud Gateway - API 调用的组织者

← 微服务间的远程接口调用:OpenFeign 的使用 网关 Spring Cloud Gateway - API 调用的组织者→

最近更新
01
重要数据不能丢!MySQL数据库定期备份保驾护航!
05-22
02
分布式事务解决方案之 Seata(二):Seata AT 模式
09-09
03
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
09-05
更多文章>
Theme by Vdoing | Copyright © 2020-2023 行百里er | MIT License | 豫ICP备2022020385号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式