センチネルソースコード解析(秒):NodeSelectorSlot分析とClusterBuilderSlot

1.はじめに

前は、情報コンテキストのセンチネル、エントリ、ノードの関連を提供します。あなたはノードを作成すると、それはNodeSelectorSlotとClusterBuilderSlot、作成したエントリに来るとき、それはチェーンを作成します。これらのオブジェクトの役割は、給紙元によって分析されます。

2.フィーチャースロット

2.1機能スロットアクション

Entryオブジェクト作成リソースへSphU.entry()アクセスを使用する場合、方法は、責任の連鎖と共に、各スロットは、それぞれ異なる機能を処理することを関数スロットの系列を作成します。

ない場合は取得鎖にCtSph#entryWithPriority()メソッドの試みでは、作成します。

 ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);
复制代码

具体的な取得方法:

源码位置:CtSph.java

private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap
        = new HashMap<ResourceWrapper, ProcessorSlotChain>();
        
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
    //先从缓存中获取,如果没有再创建
    ProcessorSlotChain chain = chainMap.get(resourceWrapper);
    if (chain == null) {
        synchronized (LOCK) {
            chain = chainMap.get(resourceWrapper);
            if (chain == null) {
                // Entry size limit. 处理链的数量不能超过6000,
                if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) {
                    return null;
                }
                //创建处理链
                chain = SlotChainProvider.newSlotChain();
                Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
                    chainMap.size() + 1);
                newMap.putAll(chainMap);
                newMap.put(resourceWrapper, chain);
                chainMap = newMap;
            }
        }
    }
    return chain;
}
复制代码

あなたが見ることができ、チェーンファイルは、キー、値のチェーンなので、一つだけの鎖を持つリソースとして静的な世界地図、リソース名に保存されます。

どこ実際の作成チェーンは)(SlotChainProvider.newSlotChainです:

#源码位置:SlotChainProvider.java

 private static volatile SlotChainBuilder slotChainBuilder = null;

 public static ProcessorSlotChain newSlotChain() {

    //如果builder不为空,创建chain,否则先创建builder,再创建chain
    if (slotChainBuilder != null) {
        return slotChainBuilder.build();
    }

    resolveSlotChainBuilder();

    if (slotChainBuilder == null) {
        RecordLog.warn("[SlotChainProvider] Wrong state when resolving slot chain builder, using default");
        slotChainBuilder = new DefaultSlotChainBuilder();
    }
    return slotChainBuilder.build();
}
复制代码

2.2。SlotChainBuilder

ファンクションスロットチェーンの作成を担当SlotChainBuilder、SlotChainBuilderは、カスタム関数のスロットを作成する方法のみビルド方式であるインターフェース、です。

私たちは、SlotChainBuilder初めて目には、3つの異なる実装が異なる処理機能を追加があります実現を見ることができます。

  • DefaultSlotChainBuilder:デフォルトのコンストラクタ関数スロット
  • GatewaySlotChainBuilder:ゲートウェイスロットコンストラクタ、ゲートウェイ制限機能を追加しました
  • HotParamSlotChainBuilder:ホットに追加されたパラメータのホットスロットコンストラクタのパラメータ、

ここではデフォルトコンストラクタ関数スロットを見て、所定の位置にスロットハンドルを追加する他の二つだけです。

public class DefaultSlotChainBuilder implements SlotChainBuilder {

    @Override
    public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
        chain.addLast(new NodeSelectorSlot());
        chain.addLast(new ClusterBuilderSlot());
        chain.addLast(new LogSlot());
        chain.addLast(new StatisticSlot());
        chain.addLast(new SystemSlot());
        chain.addLast(new AuthoritySlot());
        chain.addLast(new FlowSlot());
        chain.addLast(new DegradeSlot());

        return chain;
    }
}
复制代码

私たちは、その後、別の関数にスロットを追加し、ビルド方法はDefaultProcessorSlotChainを作成することです見ることができます。

なお、SentinelはSlotChainBuilderが機能スロットを作成するかを選択SPIの形態です。

private static final ServiceLoader<SlotChainBuilder> LOADER = ServiceLoader.load(SlotChainBuilder.class);
复制代码

2.3。ProcessorSlot

スロットオブジェクトに代わってProcessorSlot関数はスロット及び出口機能スロットにインタフェース機能を定義し、スロットは、インタフェースを達成するために、特定の機能を有します。

次のようにProcessorSlotの継承構造は次のようになります。

継承、ProcessorSlot主に二つのタイプを介して見つけることができ、一方はこのような電流制限、統計、降格などのように、特定の機能を有するスロットの関数であり、カテゴリは、スロットチェーン、主DefaultProcessorSlotChainの形成主として存在します。

2.3.1。DefaultProcessorSlotChain

二つのノード、第1のノードと最後のノード、ノードを定義し、追加のメソッドを提供する機能処理チェーンを示す開始DefaultProcessorSlotChain、。


public class DefaultProcessorSlotChain extends ProcessorSlotChain {

    //默认先创建一个头结点插槽
    AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {

        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
            throws Throwable {
            super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
        }

        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
            super.fireExit(context, resourceWrapper, count, args);
        }

    };
    AbstractLinkedProcessorSlot<?> end = first;

    @Override
    public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
        protocolProcessor.setNext(first.getNext());
        first.setNext(protocolProcessor);
        if (end == first) {
            end = protocolProcessor;
        }
    }

    @Override
    public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
        end.setNext(protocolProcessor);
        end = protocolProcessor;
    }
}
复制代码
2.3.2。AbstractLinkedProcessorSlot

ProcessorSlotを達成するだけでなく、非常に重要なAbstractLinkedProcessorSlotが、また、スロットチェーンの機能との間の接続を実現する方法。

    private AbstractLinkedProcessorSlot<?> next = null;
复制代码

AbstractLinkedProcessorSlot出口が同じ論理である場合、機能プロセスフロースロットが終了した後、次の関数は、次の溝によって見つけることができるようになっている次の処理槽への次の関数ポインタ新しいマークが通ります。

2.4機能のスロット概要

作成したプロセス能力スロット上述したように、Sentinelは、スロットのすべての仕事を整理する方法です。しかし、各スロットの特定の機能は、最初の場所で話すことはありません、それがどのように動作するかです。最後に、マップ機能スロット鎖構造を見DefaultSlotChainBuilderを作成しました:

3. NodeSelectorSlot

公式文書に記載NodeSelectorSlotある:パスが収集リソースへのスロットのために主に責任があり、そしてこれらのリソースは、呼経路に応じてフロー制御のために記憶されたツリー構造で経路を呼び出します。

ソースコードを見てください:

public class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> {

    /**
     * {@link DefaultNode}s of the same resource in different context.
     */
    private volatile Map<String, DefaultNode> map = new HashMap<String, DefaultNode>(10);

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
        throws Throwable {
        DefaultNode node = map.get(context.getName());
        if (node == null) {
            synchronized (this) {
                node = map.get(context.getName());
                if (node == null) {
                    node = new DefaultNode(resourceWrapper, null);
                    HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size());
                    cacheMap.putAll(map);
                    cacheMap.put(context.getName(), node);
                    map = cacheMap;
                    // Build invocation tree
                    ((DefaultNode) context.getLastNode()).addChild(node);
                }

            }
        }

        context.setCurNode(node);
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        fireExit(context, resourceWrapper, count, args);
    }
}
复制代码

NodeSelectorSlotは、コンテキストリストの下に新しいノードの子ノードにノードを設定し、ベースのビューが作成され、現在のノードのノードのコンテキストを設定し、DefaultNodeを作成します。

public Node getLastNode() {
    if (curEntry != null && curEntry.getLastNode() != null) {
        return curEntry.getLastNode();
    } else {
        return entranceNode;
    }
}
复制代码

上記のロジックは、最新のノードを得ることです。

NodeSelectorSlot主な役割は、収集リソース・パスにあります。このスロットでは、前回の記事では、統計的指標の保全のためのコンテキストとリソース寸法を基にしていますが、この場所は、保存するためにマップコンテキストに基づいていますDefaultNodeの話DefaultNodeを作成し、これはなぜですか?注処理チェーンがリソースへのリソースに基づいて作成スロットの機能は、チェーンを作成することは、異なるリソースは異なるチェーンを作成するので、この場所をキーとして、コンテキストを使用することであるが、実際のコンテキストおよびリソースであるが寸法。

4. ClusterBuilderSlot

NodeSelector上記ソースノードを作成し、クラスタノードの主な原因DefaultNodeノード、CLusterBuilderSlotを作成することです。すでにについて話した上で、これらの二つのノードの役割について。

public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

    private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap = new HashMap<>();

    private static final Object lock = new Object();

    private volatile ClusterNode clusterNode = null;

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                      boolean prioritized, Object... args)
        throws Throwable {
        if (clusterNode == null) {
            synchronized (lock) {
                if (clusterNode == null) {
                    // Create the cluster node.
                    clusterNode = new ClusterNode();
                    HashMap<ResourceWrapper, ClusterNode> newMap = new HashMap<>(Math.max(clusterNodeMap.size(), 16));
                    newMap.putAll(clusterNodeMap);
                    newMap.put(node.getId(), clusterNode);

                    clusterNodeMap = newMap;
                }
            }
        }
        node.setClusterNode(clusterNode);

        /*
         * if context origin is set, we should get or create a new {@link Node} of
         * the specific origin.
         */
        //如果context定义了来源名称,需要给当前的entry创建一个originNode
        if (!"".equals(context.getOrigin())) {
            Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
            context.getCurEntry().setOriginNode(originNode);
        }

        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }
}
复制代码

CLUSTERNODEはこの場所を作成したので、あなたは、リソースの統計寸法CLUSTERNODEので、統計データのリソースである、唯一のチェーン付きリソース、前に言ったので、変数の型がある、ClusterBuilderSlot CLUSTERNODEを見ることができます。

あなたはまた、ソースノード、ノード、リソースおよびorginと同じ寸法のノードに関連する統計データのソースとして、この場所の統計的な寸法を作成入り口のソースを定義する場合。

ノード、コンテキスト、エントリ全体のプロセスを作成します。5.

全体の構造は、あなたがすることができ、より混沌とこの内容で空想場合は、この必要性は、あなたに伝えるために、ポストノードの種類を作成することであるとして、単に一般的プロセスについての話、時間の上NodeSelectorSlotとClusterBuilderSlotを話しますこの小さな休日を見て、その後、前に内容を見てください。この全体のセンチネルは、統計データのプロセスを保存するので終了しました。

5.1。再度のエントリ、ノード、思い出機会コンテキストを作成

  • コンテキスト:コンテキストがContextUtil.entry()またはSphU.entryを()の使用時に作成されます。
  • EntranceNode:コンテキストを作成するときにEntranceNodeを作成し、コンテキストに割り当てられています。
  • ProcessorSlot ::作成、同じリソースを共有することSphU.entry()を使用。
  • エントリ:使用SphU.entry()を作成し、そして親と子エントリチェーンによって接続され、一方、エントリにcurEntryコンテキストオブジェクトの割り当て。
  • DefaultNode:NodeSelectorSlotは寸法リソースとコンテキストために作成されました
  • CLUSTERNODE:寸法ためのリソースにClusterBuilderSlotを作成しました。
  • ソースソースノード:寸法のためのリソースとorginするためにClusterBuilderSlotを作成します。

5.2フロー・チャート

まず、コードを見て:

 ContextUtil.enter("context1","origin1");
 Entry entry = SphU.entry("resource1");
复制代码

エントリを作成する場合、以下のように、全体の関係は、

一度に同じリソースを取得するためにこの時間:

 Entry entry2 = SphU.entry("resource1");
复制代码

次のような関係は以下のとおりです。

次に、我々は、異なるリソースを作成します。

Entry entry3 = SphU.entry("resource2");
Entry entry4 = SphU.entry("resource3");
复制代码

次のような関係は以下のとおりです。

上記は、異なるコンテキストにある場合、次の複数のコンテキスト、図は地図上に複製することであるので、チェーンが次元のリソースであるので、同じリソース上でクラスタノードがあるので、同じコンテキストにあります同じにコピーしますが、CLUSTERNODEポイント。

図によれば、あなたは明らかにCLUSTERNODEは、DefaultNode、OrginNodeがどのような大きさの統計に基づいていることがわかります。

6.まとめ

データは、責任の連鎖を通じて、この章話すセンチネルに格下げし、他の機能を制限するスロットの多様性を達成するために組み合わせて、最初の2つのスロットを解析されます。NodeSelectorSlotとClusterNodeSlotの役割を。最後に、異なるシナリオの下のエントリは、ノード、関係のコンテキストの最初の章の内容を描画し、よりCLUSTERNODE、DefaultNode、ソースノードは、統計何寸法に従っている反映。次は、統計StatisticSlotセンチネルを分析していきます、だけでなく、ノードノードの様々なデータを保存する方法です。

7.参考

センチネル作業主な流れ

おすすめ

転載: juejin.im/post/5dd34664f265da0bf350d419