¡Trabajar juntos para crear y crecer juntos! Este es el día 22 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de agosto", haga clic para ver los detalles del evento
prefacio
El libro continúa:
Llamadas de interfaz remota entre microservicios: el uso de OpenFeign
OpenFeign
Después de usar en el proyecto , es muy conveniente llamar al servicio remoto. Ahora hay un problema. Si el servicio remoto falla, la interfaz remota no se puede ajustar y estoy esperando ansiosamente el resultado de la devolución. ¿Qué debo hacer?
Por supuesto, es para usar la degradación del servicio . En este artículo, usaremos OpenFeign
para realizar llamadas remotas y combinaremos con Sentinel
para llevar a cabo la degradación del servicio por problemas tales como excepciones y fallas.
Preparar
Todavía use el open-feign-service
servicio como la persona que llama y el nacos-provider
servicio como el proveedor para realizar el simulacro.
Dependencias del paquete Jar
open-feign-service
Además de introducir spring-cloud-starter-openfeign
, y luego introducir spring-cloud-starter-alibaba-sentinel
componentes, y nacos
el Sentinel
mantener las reglas de limitación actuales, por lo que también necesitamos introducir spring-cloud-alibaba-sentinel-datasource
y 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>
复制代码
archivo de configuración
Archivo de configuración 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
复制代码
Sentinel
Aquí se añade el contenido de persistencia de datos y la configuración de activación OpenFeign
y uso Sentinel
combinado feign.sentinel.enabled=true
.
Manejo global unificado de excepciones
Ya sea el retorno después del Sentinel
límite actual , o OpenFeign
el fallback
retorno del, todos ellos son anormales en esencia.Aquí, configure el manejo de excepciones unificado global.
Primero, agregue una clase de excepción empresarial:
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 esta forma, se realiza el procesamiento tolerante a fallas del respaldo , e incluso si el servicio remoto no está disponible, también se puede degradar.
Limitación de corriente de @SentinelResource
Cuando la capa del controlador usa la interfaz definida por FeignClient para llamar a los servicios de forma remota, también puede definir los recursos de Sentinel y establecer reglas para limitar el flujo actual de recursos.
Algunos métodos de uso de @SentinelResource se han mencionado en artículos anteriores y se OpenFeign
usan . En este ejemplo, se proporcionan las siguientes definiciones:
@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 "请稍后重试";
}
复制代码
En las preparaciones anteriores, hemos configurado las reglas de limitación de corriente de recursos de Sentinel para que persistan en Nacos. Ahora configure las reglas de limitación de getProduct
corriente :
[
{
"resource": "getProduct",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
复制代码
La regla de limitación actual es que el umbral de QPS es 1, siempre que tenga más de 1 solicitud por segundo, seré limitado.
Inicie el servicio remoto nacos-provider
y verifíquelo a continuación.
El resultado de enviar solo una solicitud en 1 segundo:
Actualice rápidamente varias veces en 1 segundo, lo que dará como resultado un QPS superior a 1, y la corriente será limitada:
resumen
OpenFeign
La integraciónSentinel
requiere la introducción deSentinel
paquetes de dependencia relevantes;- Usar en el archivo de configuración
feign.sentinel.enabled=true
para habilitar el uso combinado de Feign y Sentinel; - Agregue el atributo a la anotación @FeignClient , que define la clase de lógica de procesamiento tolerante a fallas cuando el acceso a la interfaz remota es problemático;
fallback
fallback
La clase definida necesita implementar la interfaz definida por @FeignClient .
Dale un pulgar hacia arriba y vamos ~