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
OpenFeign
Aprè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 OpenFeign
pour effectuer des appels à distance, et nous combinerons avec Sentinel
pour effectuer une rétrogradation de service pour des problèmes tels que des exceptions et des échecs.
Préparer
Utilisez toujours le open-feign-service
service comme appelant et le nacos-provider
service comme fournisseur pour effectuer l'exercice.
Dépendances du package Jar
open-feign-service
En plus d'introduire spring-cloud-starter-openfeign
, puis d'introduire spring-cloud-starter-alibaba-sentinel
des composants, et nacos
le Sentinel
conserver les règles de limitation actuelles, nous devons donc également introduire spring-cloud-alibaba-sentinel-datasource
et 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>
复制代码
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
复制代码
Sentinel
Le contenu de persistance des données de et la configuration de l'activation OpenFeign
et de l'utilisation Sentinel
combinée sont ajoutés ici feign.sentinel.enabled=true
.
Gestion globale unifiée des exceptions
Qu'il s'agisse du retour après la Sentinel
limite actuelle ou OpenFeign
du fallback
retour 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 。该类的实现方法可以添加实际业务的处理逻辑,本案例只是打印一些信息后直接抛出自定义的异常。
Tips :ResponseCode.RPC_ERROR 在二方库中有定义。
给 FeignClient 接口增加 fallback 属性:
@FeignClient(name = "nacos-provider", fallback = ProductServiceImpl.class)
复制代码
OK,不启动服务提供方 nacos-provider
,直接调用接口测试。
接口返回:
控制台打印信息:
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 OpenFeign
utilisé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 getProduct
courant :
[
{
"resource": "getProduct",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
复制代码
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-provider
et vérifiez-le ci-dessous.
Le résultat de l'envoi d'une seule requête en 1 seconde :
Actualisez rapidement plusieurs fois en 1 seconde, ce qui entraîne un QPS supérieur à 1, et le courant sera limité :
sommaire
OpenFeign
L'intégrationSentinel
nécessite l'introduction deSentinel
packages de dépendances pertinents ;- Utiliser dans le fichier de configuration
feign.sentinel.enabled=true
pour 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
fallback
La classe définie doit implémenter l'interface définie par @FeignClient .
Donnez-lui un coup de pouce et allons-y ~