Introducción de clase importante de Sentinel

Cuenta pública de WeChat: Xiaoheihe del propietario tiene un
largo camino por recorrer, y el futuro es mejor
. El aprendizaje es interminable. ¡Vamos!

Este es Sentinelel primer artículo sobre el principio de análisis . Debido al corto tiempo de contacto con el middleware, pueden ocurrir algunos malentendidos. Espero que todos se comuniquen y corrijan activamente. El contenido principal del artículo está escrito principalmente después de leer algunos artículos del Gran Dios y agregar su propia comprensión.

El artículo de referencia principal se encuentra Sentinelen github, la dirección específica es la siguiente: artículo de referencia

Las funciones principales de Sentinel son el control de flujo y la degradación del fusible. Los conceptos específicos se han introducido en la limitación y fusión actual de dubbo, que no se repetirá aquí.

Permítanme brevemente dar un ejemplo de cómo usarlo.

public static void main(String[] args) {
    try {
        Context context=ContextUtil.enter("context1");
        Entry entry=SphU.entry("HelloWorld");
        entry.exit();
        ContextUtil.exit();
    } catch (BlockException ex) {
        // 处理被流控的逻辑
        System.out.println("blocked!");
    }catch (Exception e){
        e.printStackTrace();
    }
}
复制代码
try (Entry entry = SphU.entry("HelloWorld")) {
    // Your business logic here.
    System.out.println("hello world");
catch (BlockException e) {
    // Handle rejected request.
    e.printStackTrace();
}
复制代码

Los anteriores son dos ejemplos típicos de control de flujo. Los lectores encontrarán que hay una diferencia muy obvia, es decir, la Contextclase, que se usa para representar el contexto de una llamada, en realidad no la afecta. El análisis específico será más adelante.

También hay una clase importante Entryen el ejemplo. El parámetro que HelloWorldcontiene puede considerarse como un nombre de recurso. Antes de un uso específico, debemos definir algunas reglas nosotros mismos. Puede usar los siguientes métodos para definir una regla sobre el control de flujo:

private void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule(resourceName);
    // set limit qps to 20
    rule.setCount(20);
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setLimitApp("default");
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}
复制代码

Al llamar SphU.entry("HelloWorld"), si no se informa ninguna excepción, significa que puede ejecutar su propio código comercial; si se informa un error, significa que no se cumple la condición actual y se niega a ejecutar el siguiente código comercial.

Varios conceptos centrales

Recurso

El recurso es un concepto central en Sentinel, puede ser un servicio proporcionado por una aplicación, otros servicios llamados por una aplicación o un fragmento de código. Cuando hay muchas solicitudes para un determinado servicio, a menudo se ve afectado por un aumento repentino del tráfico, lo que resulta en un rendimiento reducido o falta de disponibilidad. En este momento, podemos definir un recurso Sentinel, ajustar la solicitud a través de este recurso y realizar el control de flujo y la degradación del servicio.

En Sentinel, el tipo de recurso específico es ResourceWrapper.

public abstract class ResourceWrapper {
    # 资源名
    protected final String name;
    # 是入站还是出站
    protected final EntryType entryType;
    # 资源类型
    protected final int resourceType;
复制代码

Entrada

La entrada es una credencial utilizada en sentinel para indicar si se debe pasar el límite actual. Si puede regresar normalmente, significa que puede acceder al servicio de respaldo protegido por sentinel, de lo contrario, centinela lanzará una BlockException. Además, guarda entry()información básica sobre este método de ejecución . Cada llamada de recurso creará una Entry.

public abstract class Entry implements AutoCloseable {
    # 当前Entry的创建时间,主要用来后期计算rt
    private long createTime;
    # 当前Entry所关联的node,该node主要是记录了当前context下该资源的统计信息
    private Node curNode;
    # 当前Entry的调用来源,通常是调用方的应用名称
    private Node originNode;
    private Throwable error;
    # 当前Entry所关联的资源
    protected ResourceWrapper resourceWrapper;
复制代码
class CtEntry extends Entry {
    protected Entry parent = null;
    protected Entry child = null;
    protected ProcessorSlot<Object> chain;
    protected Context context;
复制代码

Puede introducir algunas abstracciones como esta. Me baso en un ejemplo de otra persona y es muy vívido.

De la figura podemos ver que hay un enlace de llamada de user-center-> getUserInfo-> getOrderInfo. Según el código, sabemos que user-centeres un nombre de contexto getUserInfoy getOrderInfodos nombres de recursos.

En el ejemplo anterior, se llama a una entrada en una entrada y hay un enlace. Cuando Sphu.entry()se llama al método varias veces en un contexto, se crea un árbol de llamadas. Los nodos de este árbol se mantienen a través de la relación entre padre e hijo.

Nodo

El nodo guarda datos estadísticos en tiempo real de recursos, como: passQps, blockQps, rt y otros datos en tiempo real.

nodo es una interfaz que tiene una clase de implementación StatisticNode , pero StatisticNode sí también tiene dos sub-categorías, uno es DefaultNode , el otro es ClusterNode , DefaultNode hay una subclase llamada EntranceNode .

EntranceNodeEs el punto de entrada de cada contexto. El nodo está directamente vinculado a la raíz y es globalmente único. Cada contexto tiene uno correspondiente entranceNode. DefaultNodeRegistra los datos actuales en tiempo real, y cada uno DefaultNodeestá asociado con un recurso ClusterNode. Los DefaultNodes con los mismos recursos están asociados con el mismo clusterNode.

public interface Node extends OccupySupportDebugSupport {
    long totalRequest();
    long totalPass();
    long totalSuccess();
复制代码
public class DefaultNode extends StatisticNode {
    private ResourceWrapper id;
    private volatile Set<Node> childList = new HashSet<>();
    private ClusterNode clusterNode;
复制代码

Contexto

public class Context {
    //上下文名称
    private final String name;
    //当前调用链的入口节点
    private DefaultNode entranceNode;
   //调用链中当前正在处理的entry
    private Entry curEntry;
    //此上下文的来源(通常表示不同的调用方,例如服务使用者名称或来源IP)
    private String origin = "";
复制代码

Context代表调用链路上下文,贯穿一次调用链路中的所有Entry
每次调用SphU.entry()都需要在一个context中执行,如果没有当前执行时还没有context,那么框架会使用默认的context,即sentinel_default_context

Context是保存在ThreadLocal中的,每次执行的时候会优先到ThreadLocal中获取。如果Context为null才会再次去创建一个context。

Entry执行exit方法时,当当前的entry的parent为null时,说明当前entry是最上层的节点,该上下文的entry已执行完,所以在此时需要将context设置为null,从ThreadLocal中清除。

以上就是比较重要的实体类介绍。

参考文章:
Sentinel核心类解析
Sentinel原理-实体类
阿里Sentinel源码解析

本文使用 mdnice 排版

Supongo que te gusta

Origin juejin.im/post/5e9daec56fb9a03c6e643882
Recomendado
Clasificación