Directorio de artículos
Descripción general
página web oficial
https://github.com/alibaba/Sentinel
chino:
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
https://sentinelguard.io/zh-cn /docs/introducción.html
problema resuelto
- Avalancha de servicio
- degradación del servicio
- Disyuntor de servicio
- Límite actual del servicio
Principales características
Configuración
Descargue la consola de visualización
https://github.com/alibaba/Sentinel/releases
POM
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
Carga diferida adoptada por Sentinel
Reglas de control de flujo
directo (predeterminado)
- Nombre del recurso: nombre de ruta de descanso predeterminado
- Fuente: predeterminado
asociado
Cuando el recurso B asociado con A alcanza el umbral, el propio A quedará restringido (B hace que A se bloquee).
B causa problemas y A se bloquea
. 1. Calentamiento
- Fórmula: el umbral se divide por coldFactor (el valor predeterminado es 3). El umbral se alcanzará después del tiempo de calentamiento.
- El coldFactor predeterminado es 3, es decir, el QPS solicitado comienza desde el umbral / 3 y aumenta gradualmente hasta el umbral de QPS establecido después del tiempo de calentamiento.
- Al principio no funcionó, pero poco a poco fue mejorando.
Escenario de aplicación:
por ejemplo: cuando se enciende el sistema de venta flash, aparecerá mucho tráfico, lo que es muy probable que acabe con el sistema. El método de precalentamiento consiste en proteger el sistema dejando entrar el tráfico lentamente y aumentando lentamente el umbral Crece hasta el umbral establecido.
2. Hacer cola a velocidad constante
Para colas uniformes, el umbral debe establecerse en QPS
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
Significado de la configuración: /testA 1 solicitud por segundo, más de Si es así, espere en la fila y el tiempo de espera es de 20000 milisegundos.
enlace
Reglas de degradación
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
-
La degradación del disyuntor Sentinel limitará la llamada de este recurso cuando un recurso en el enlace de llamada esté en un estado inestable (como tiempo de espera de llamada o aumento anormal de la proporción), de modo que la solicitud
falle rápidamente y evite afectar otros recursos y causar degradación. error. -
Cuando se degrada un recurso, las llamadas al recurso se desconectarán automáticamente dentro del siguiente período de degradación (el comportamiento predeterminado es generar una DegradeException).
En el estado medio abierto, el sistema detecta automáticamente si hay una anomalía en la solicitud. Si
no hay ninguna anomalía, cerrará el disyuntor y reanudará el uso.
Si hay una anomalía, continuará abriendo el disyuntor. y hacerlo no disponible. Para obtener más información, consulte Hystrix.
Los disyuntores Sentinel no están medio abiertos .
Estrategia de degradación en acción
RT
proporción anormal
De acuerdo con la configuración anterior,
si accede solo, se informará un error una vez (int age = 10/0) y se producirá un error una vez que lo ajuste;
Después de abrir jmeter, podemos enviar solicitudes directamente con alta concurrencia y varias llamadas pueden cumplir con nuestras condiciones de configuración.
El disyuntor se enciende (el fusible se dispara), el microservicio ya no está disponible y el error ya no se informa pero el servicio se degrada.
numero anormal
La ventana de tiempo debe ser mayor o igual a 60 segundos.
Límite actual de la clave de hotspot
Sitio web oficial:
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6% B5 %81¿Qué
es un hotspot
? Los hotspots son datos a los que se accede con frecuencia. Muchas veces queremos contar o limitar los datos TopN con la mayor frecuencia de acceso en determinados datos del hotspot y realizar limitaciones actuales u otras operaciones en su acceso.
Método de ida y vuelta:
dividido en predeterminado del sistema y definido por el cliente, dos tipos,
desde HystrixCommand hasta @SentinelResource
El modo de limitación actual solo admite el modo QPS, que está fijo hasta la muerte. (esto se llama punto caliente)
- El índice del parámetro del método de la anotación @SentinelResource, 0 representa el primer parámetro, 1 representa el segundo parámetro, y así sucesivamente.
- El umbral independiente y la duración de la ventana estadística indican que el flujo será limitado si el tiempo de la ventana excede el umbral.
- La captura de pantalla anterior muestra que si el primer parámetro tiene un valor, el QPS por segundo es 1. Si excede el límite actual, se llama al método de soporte dealHandler_testHotKey después del límite actual.
Ejemplo:
class TestController{
// 此处value的值是资源名可以为abc都行与之后dashboard中配置的资源名对应就可以
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
//int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
}
Opciones avanzadas: excepciones de parámetros
Requisitos previos
Nota: Puntos a tener en cuenta para los parámetros activos; los parámetros deben ser tipos básicos o Cadena
Cuando p1 es igual a 5, el umbral pasa a ser 200
otro
@SentinelResource
maneja las violaciones de la configuración de la consola Sentinel y tiene el procesamiento ascendente de la configuración del método blockHandler;
RuntimeException
int age = 10/0, esta es la excepción de tiempo de ejecución que RunTimeException genera cuando se ejecuta Java, a @SentinelResource no le importa
Resumen
@SentinelResource error de configuración del supervisor, error de operación, se debe realizar una operación anormal
// 有fallback解决后面会细看
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey" fallBack="")
Reglas del sistema
Sitio web oficial:
https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9% 99 %90%E6%B5%81
solo es efectivo para el tráfico de entrada
- Carga adaptable (solo efectiva para máquinas tipo Linux/Unix): la carga1 del sistema se utiliza como indicador de inspiración para la protección adaptable del sistema. La protección del sistema (fase BBR) se activará cuando la carga del sistema1 exceda el valor heurístico establecido y el número actual de subprocesos simultáneos en el sistema exceda la capacidad estimada del sistema. La capacidad del sistema se estima mediante maxQps * minRt del sistema. El valor de referencia de configuración es generalmente núcleos de CPU * 2,5.
- Uso de CPU (versión 1.5.0+): cuando el uso de CPU del sistema excede el umbral, se activa la protección del sistema (rango de valores 0.0-1.0), que es relativamente sensible.
- RT promedio: cuando el RT promedio de todo el tráfico de entrada en una sola máquina alcanza el umbral, se activa la protección del sistema y la unidad es de milisegundos.
- Número de subprocesos simultáneos: cuando el número de subprocesos simultáneos para todo el tráfico de entrada en una sola máquina alcanza el umbral, se activa la protección del sistema.
- QPS de ingreso: cuando el QPS de todo el tráfico de ingreso en una sola máquina alcanza el umbral, se activa la protección del sistema.
@SentinelResource
Limitación actual por nombre de recurso + procesamiento posterior
Limitación actual basada en la dirección URL + procesamiento posterior
el problema al que nos enfrentamos
- El valor predeterminado del sistema no refleja nuestros propios requisitos comerciales.
- Según las condiciones existentes, nuestro método de procesamiento personalizado se combina con el código comercial, que no es intuitivo.
- Agregar una cobertura a cada método comercial aumentará la sobrecarga del código.
- No se refleja un enfoque globalmente unificado.
Lógica de procesamiento de limitación de corriente definida por el cliente
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,//异常处理类
blockHandler = "handlerException2")//异常处理方法
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
public class CustomerBlockHandler
{
public static CommonResult handlerException(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----1");
}
public static CommonResult handlerException2(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----2");
}
}
Función de interrupción del circuito de servicio
Sentinel integra cinta + openFeign + respaldo
La administración alternativa se ejecuta de manera anormal (administrar Java)
blockHandler administra las violaciones de configuración de la consola (administra la configuración en el panel)
@SentinelResource(value = "fallback",
fallback = "handlerFallback",
blockHandler = "blockHandler")
Si se configuran tanto blockHandler como el respaldo, solo se ingresará la lógica de procesamiento de blockHandler cuando se genere una BlockException debido a una degradación de limitación actual.
excepciones para ignorar
//exceptionsToIgnore 忽略该种异常,sentinel不进行流量拦截
@SentinelResource(value = "fallback",
fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {
IllegalArgumentException.class})
AbiertoFingimiento
POM
<!--SpringCloud openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Activar el soporte de Sentinel para Feign
# 激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
Interfaz empresarial con anotación @FeignClient
/**
* 使用 fallback 方式是无法获取异常信息的,
* 如果想要获取异常信息,可以使用 fallbackFactory参数
*/
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
Servicio de respaldo de pago
@Component
public class PaymentFallbackService implements PaymentService
{
@Override
public CommonResult<Payment> paymentSQL(Long id)
{
return new CommonResult<>(444,"服务降级返回,没有该流水信息",new Payment(id, "errorSerial......"));
}
}
Controlador
//==================OpenFeign
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/openfeign/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
if(id == 4)
{
throw new RuntimeException("没有该id");
}
return paymentService.paymentSQL(id);
}
arranque principal
@EnableFeignClients
Comparación de varios marcos de fusibles.
Persistencia de reglas
Configuración
POM
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
YML
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务注册中心地址
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard地址
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
Agregar configuración de reglas comerciales de Nacos
[
{
"resource": "/rateLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
Después de actualizar Sentinel
y reiniciar el servicio, se puede llamar a la interfaz varias veces antes de que se pueda pasar la verificación de persistencia.
Otros ejemplos
Extraído del sitio web oficial.
Ejemplo de limitación de corriente adaptativa
public class SystemGuardDemo {
private static AtomicInteger pass = new AtomicInteger();
private static AtomicInteger block = new AtomicInteger();
private static AtomicInteger total = new AtomicInteger();
private static volatile boolean stop = false;
private static final int threadCount = 100;
private static int seconds = 60 + 40;
public static void main(String[] args) throws Exception {
tick();
initSystemRule();
for (int i = 0; i < threadCount; i++) {
Thread entryThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Entry entry = null;
try {
entry = SphU.entry("methodA", EntryType.IN);
pass.incrementAndGet();
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
// ignore
}
} catch (BlockException e1) {
block.incrementAndGet();
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
// ignore
}
} catch (Exception e2) {
// biz exception
} finally {
total.incrementAndGet();
if (entry != null) {
entry.exit();
}
}
}
}
});
entryThread.setName("working-thread");
entryThread.start();
}
}
private static void initSystemRule() {
SystemRule rule = new SystemRule();
// max load is 3
rule.setHighestSystemLoad(3.0);
// max cpu usage is 60%
rule.setHighestCpuUsage(0.6);
// max avg rt of all request is 10 ms
rule.setAvgRt(10);
// max total qps is 20
rule.setQps(20);
// max parallel working thread is 10
rule.setMaxThread(10);
SystemRuleManager.loadRules(Collections.singletonList(rule));
}
private static void tick() {
Thread timer = new Thread(new TimerTask());
timer.setName("sentinel-timer-task");
timer.start();
}
static class TimerTask implements Runnable {
@Override
public void run() {
System.out.println("begin to statistic!!!");
long oldTotal = 0;
long oldPass = 0;
long oldBlock = 0;
while (!stop) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
long globalTotal = total.get();
long oneSecondTotal = globalTotal - oldTotal;
oldTotal = globalTotal;
long globalPass = pass.get();
long oneSecondPass = globalPass - oldPass;
oldPass = globalPass;
long globalBlock = block.get();
long oneSecondBlock = globalBlock - oldBlock;
oldBlock = globalBlock;
System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:"
+ oneSecondTotal + ", pass:"
+ oneSecondPass + ", block:" + oneSecondBlock);
if (seconds-- <= 0) {
stop = true;
}
}
System.exit(0);
}
}
}