Introdução importante à classe do Sentinel

Conta pública do WeChat: Xiaoheihe, o proprietário, ainda tem um
longo caminho a percorrer, e o futuro é melhor
.

Este é Sentinelo primeiro artigo sobre o princípio da análise . Devido ao curto tempo de contato com o middleware, podem ocorrer alguns mal-entendidos. Espero que todos se comuniquem e corrijam ativamente. O conteúdo principal do artigo é escrito principalmente após a leitura de alguns artigos do Grande Deus e a adição de seu próprio entendimento.

O artigo de referência principal é encontrado Sentinelno github, o endereço específico é o seguinte: artigo de referência

As principais funções do Sentinel são controle de fluxo e degradação de fusíveis. Os conceitos específicos foram introduzidos na atual limitação e fusão do dubbo, que não serão repetidos aqui.

Deixe-me brevemente dar um exemplo de como usá-lo.

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

Os exemplos acima são dois exemplos típicos de controle de fluxo. Os leitores descobrirão que há uma diferença muito óbvia, ou seja, a Contextclasse, que é usada para representar o contexto de uma chamada, na verdade não a afeta.A análise específica será posterior.

Há também uma classe importante Entryno exemplo.O parâmetro HelloWorldpode ser considerado como um nome de recurso.Antes do uso específico, precisamos definir algumas regras. Você pode usar os seguintes métodos para definir uma regra sobre controle de fluxo:

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

Ao chamar SphU.entry("HelloWorld"), se nenhuma exceção for relatada, significa que ele pode executar seu próprio código comercial; se um erro for relatado, significa que a condição atual não é atendida e se recusa a executar o seguinte código comercial.

Vários conceitos principais

Recurso

Recurso é um conceito essencial do Sentinel, que pode ser um serviço fornecido por um aplicativo, outros serviços chamados por um aplicativo ou um trecho de código. Quando há muitas solicitações para um determinado serviço, geralmente é interrompido por um aumento repentino de tráfego, resultando em desempenho ou indisponibilidade reduzida.Neste momento, podemos definir um recurso do Sentinel, ajustar a solicitação por esse recurso e executar controle de fluxo e degradação do serviço.

No Sentinel, o tipo de recurso específico é ResourceWrapper.

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

Entrada

A entrada é uma credencial usada no sentinel para indicar se deve ser ultrapassado o limite atual.Se pode ser retornado normalmente, significa que você pode acessar o serviço de retorno protegido pelo sentinel, caso contrário, o sentinel lançará uma BlockException. Além disso, ele salva entry()algumas informações básicas sobre esse método de execução . Cada chamada de recurso criará uma 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;
复制代码

Pode apresentar algumas abstrações como essa: eu desenho um exemplo de outra pessoa e é muito vívido.

A partir da figura, podemos ver que existe um link de chamada de user-center-> getUserInfo-> getOrderInfo. De acordo com o código, sabemos que user-centeré um nome de contexto getUserInfoe getOrderInfodois nomes de recursos.

No exemplo acima, uma entrada é chamada em uma entrada e existe um link.Quando o Sphu.entry()método é chamado várias vezes em um contexto, é criada uma árvore de chamadas.Os nós dessa árvore são mantidos através do relacionamento entre pai e filho.

O nó salva dados estatísticos em tempo real dos recursos, como: passQps, blockQps, rt e outros dados em tempo real.

nó é uma interface que tem uma classe de implementação StatisticNode , mas StatisticNode em si também tem duas sub-categorias, uma é DefaultNode , o outro é ClusterNode , DefaultNode há uma subclasse chamada EntranceNode .

EntranceNodeÉ o ponto de entrada de cada contexto.O nó está diretamente vinculado à raiz e é globalmente exclusivo.Todo contexto possui um correspondente entranceNode. DefaultNodeEle registra os dados atuais em tempo real e cada um DefaultNodeé associado a um recurso ClusterNode. Os defaultNodes com os mesmos recursos estão associados ao mesmo 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 排版

Acho que você gosta

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