Alliance forte : OpenFeign intègre Sentinel

Travailler ensemble pour créer et grandir ensemble ! C'est le 22ème jour de ma participation au "Nuggets Daily New Plan · August Update Challenge", cliquez pour voir les détails de l'événement

avant-propos

Le livre continue :

Appels d'interface à distance entre microservices : l'utilisation d'OpenFeign

OpenFeignAprès avoir utilisé dans le projet , il est très pratique d'appeler le service distant. Il y a maintenant un problème. Si le service distant échoue, l'interface distante ne peut pas être ajustée et j'attends avec impatience le résultat de retour. Que dois-je faire ?

Bien sûr, il s'agit d'utiliser la rétrogradation de service Dans cet article, nous utiliserons OpenFeignpour effectuer des appels à distance, et nous combinerons avec Sentinelpour effectuer une rétrogradation de service pour des problèmes tels que des exceptions et des échecs.

Préparer

Utilisez toujours le open-feign-serviceservice comme appelant et le nacos-providerservice comme fournisseur pour effectuer l'exercice.

Dépendances du package Jar

open-feign-serviceEn plus d'introduire spring-cloud-starter-openfeign, puis d'introduire spring-cloud-starter-alibaba-sentineldes composants, et nacosle Sentinelconserver les règles de limitation actuelles, nous devons donc également introduire spring-cloud-alibaba-sentinel-datasourceet 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>
复制代码

image-20220819160608694.png

fichier de configuration

Fichier de configurationapplication.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
复制代码

SentinelLe contenu de persistance des données de et la configuration de l'activation OpenFeignet de l'utilisation Sentinelcombinée sont ajoutés ici feign.sentinel.enabled=true.

Gestion globale unifiée des exceptions

Qu'il s'agisse du retour après la Sentinellimite actuelle ou OpenFeigndu fallbackretour du , ils sont tous anormaux par essence. Ici, configurez la gestion globale unifiée des exceptions.

Tout d'abord, ajoutez une classe d'exception métier :

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;
    }
}
复制代码

然后使用 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());
    }

    // 其他异常...
}
复制代码

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

操练

@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);
}
复制代码

如果远程接口不通,这里可以在 @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());
    }
}
复制代码

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

TipsResponseCode.RPC_ERROR 在二方库中有定义。

FeignClient 接口增加 fallback 属性:

@FeignClient(name = "nacos-provider", fallback = ProductServiceImpl.class)
复制代码

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

接口返回:

image-20220819163044024.png

控制台打印信息:

image-20220819162946588.png

De cette manière, le traitement tolérant aux pannes du repli est réalisé , et même si le service distant n'est pas disponible, il peut également être rétrogradé.

@SentinelResource limitation de courant

Lorsque la couche Contrôleur utilise l'interface définie par FeignClient pour appeler des services à distance, vous pouvez également définir des ressources Sentinel et définir des règles pour limiter le flux actuel de ressources.

Certaines méthodes d'utilisation de @SentinelResource ont été mentionnées dans des articles précédents, et elles sont OpenFeignutilisées . Dans cet exemple, les définitions suivantes sont fournies :

@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 "请稍后重试";
}
复制代码

Dans les préparations précédentes, nous avons configuré les règles de limitation de courant des ressources Sentinel pour qu'elles persistent dans Nacos. Configurez maintenant les règles de limitation de getProductcourant :

[
  {
    "resource": "getProduct",
    "limitApp": "default",
    "grade": 1,
    "count": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  }
]
复制代码

image-20220819164001324.png

La règle de limitation actuelle est que le seuil de QPS est de 1, tant que j'ai plus d'une requête par seconde, je serai limité.

Démarrez le service à distance nacos-provideret vérifiez-le ci-dessous.

Le résultat de l'envoi d'une seule requête en 1 seconde :

image-20220819164448540.png

Actualisez rapidement plusieurs fois en 1 seconde, ce qui entraîne un QPS supérieur à 1, et le courant sera limité :

image-20220819164343886.png

sommaire

  • OpenFeignL'intégration Sentinelnécessite l'introduction de Sentinelpackages de dépendances pertinents ;
  • Utiliser dans le fichier de configuration feign.sentinel.enabled=truepour permettre l'utilisation combinée de Feign et Sentinel ;
  • Ajoutez l'attribut à l' annotation @FeignClient , qui définit la classe de la logique de traitement tolérante aux pannes lorsque l'accès à l'interface distante est problématique ;fallback
  • fallbackLa classe définie doit implémenter l'interface définie par @FeignClient .

Donnez-lui un coup de pouce et allons-y ~

Je suppose que tu aimes

Origine juejin.im/post/7133509818425278471
conseillé
Classement