前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Sentinel服务治理中各个插槽职责【源码笔记】

Sentinel服务治理中各个插槽职责【源码笔记】

作者头像
瓜农老梁
发布2019-10-09 14:42:00
5050
发布2019-10-09 14:42:00
举报
文章被收录于专栏:瓜农老梁

一、插槽链类结构

1.插槽链类图

2.插槽链运行时内存结构

二、NodeSelectorSlot&ClusterBuilderSlot调用结构

先看示例,然后分析在内存中形成的调用结构,最后分析源码。

1.1 示例代码
代码语言:javascript
复制
@Test
public void test01(){
    try{
        ContextUtil.enter("entrance1", "appA");
        Entry nodeA = SphU.entry("nodeA");
        if (nodeA != null) {
            nodeA.exit();
        }
        ContextUtil.exit();
    }catch(Exception e){
        e.printStackTrace();
    }
 }
1.2 调用结构图示

上面的示例代码会在内存中形成如下结构

1.3 内存运行结构
2.1 代码示例
代码语言:javascript
复制
@Test
 public void test02(){
    try{
        ContextUtil.enter("entrance1", "appA");
        Entry nodeA = SphU.entry("nodeA");
        if (nodeA != null) {
            nodeA.exit();
        }
        ContextUtil.exit();
        ContextUtil.enter("entrance2", "appA");
        nodeA = SphU.entry("nodeA");
        if (nodeA != null) {
            nodeA.exit();
        }
        ContextUtil.exit();
    }catch(Exception e){

    }
 }
2.2 调用结构图示
2.3 内存运行结构

entrance1跟上图一样,下图为entrance2的结构

3.1 NodeSelectorSlot源码

NodeSelectorSlot#entry

代码语言:javascript
复制
DefaultNode node = map.get(context.getName());
if (node == null) {
    synchronized (this) {
        node = map.get(context.getName());
        if (node == null) {
            // 构造该资源Node
            node = new DefaultNode(resourceWrapper, null);
            HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size());
            cacheMap.putAll(map);
            // 将该Node放入缓存 key为上下文名称
            cacheMap.put(context.getName(), node);
            map = cacheMap;
        }
        // Build invocation tree
        // 将该Node加入上下文调用链
        ((DefaultNode)context.getLastNode()).addChild(node);
    }
}
// 在上下文中 设置当前Node
context.setCurNode(node);
// 触发链条向下调用
fireEntry(context, resourceWrapper, node, count, prioritized, args);
3.2 ClusterBuilderSlot源码
代码语言:javascript
复制
// 只在第一次调用时生成
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;
        }
    }
}
// 设置当前节点的ClusterNode
node.setClusterNode(clusterNode);
if (!"".equals(context.getOrigin())) {
    Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin());
    context.getCurEntry().setOriginNode(originNode);
}
fireEntry(context, resourceWrapper, node, count, prioritized, args);
3.3 小结

1.NodeSelectorSlot职责记录调用轨迹,Entry调用会在内存中形成调用轨迹; 2.ClusterBuilderSlot职责构造ClusterNode,为当前节点设置ClusterNode; 3.ClusterNode为ClusterBuilderSlot的成员变量,一个资源对应一个ClusterNode; 4.Context会记录每次调用的元数据信息,EntranceNode为调用的根节点,DefaultNode和ClusterNode均为资源的统计信息; 5.不同的上下文生成不同的DefaultNode统计节点,相同资源的不同的上下文使用同一个ClusterNode

三、LogSlot职责
代码语言:javascript
复制
try {
    fireEntry(context, resourceWrapper, obj, count, prioritized, args);
} catch (BlockException e) {
    EagleEyeLogUtil.log(resourceWrapper.getName(), e.getClass().getSimpleName(), e.getRuleLimitApp(),
        context.getOrigin(), count);
    throw e;
}

小结:LogSlot没有过多的逻辑,在被阻塞时在sentinel-block.log记录日志,格式如下:

代码语言:javascript
复制
2019-10-01 20:33:02|1|abc,FlowException,default,|12,0
四、StatisticSlot职责
1.流程图
2.主要源码走查
代码语言:javascript
复制
public void entry() throws Throwable {
try {
    // 触发向下插槽执行
    fireEntry();
    // 请求通过递增线程数量与请求数量
    node.increaseThreadNum();
    node.addPassRequest(count);
    // 调用源统计信息
    if (context.getCurEntry().getOriginNode() != null) {
    // 调用源递增线程数和请求数
      context.getCurEntry().getOriginNode().increaseThreadNum();
      context.getCurEntry().getOriginNode().addPassRequest(count);
    }
    // 进入流量全局统计
    if (resourceWrapper.getType() == EntryType.IN) {
        // 全局ClusterNode统计递增线程数和请求数
        Constants.ENTRY_NODE.increaseThreadNum();
        Constants.ENTRY_NODE.addPassRequest(count);
    }
} catch (BlockException e) {
    // 设置阻塞异常信息
    context.getCurEntry().setError(e);
   // 递增被阻塞的数量
    node.increaseBlockQps(count);
    if (context.getCurEntry().getOriginNode() != null) {
        context.getCurEntry().getOriginNode().increaseBlockQps(count);
    }
    if (resourceWrapper.getType() == EntryType.IN) {
        // 全局ClusterNode递增阻塞请求数
        Constants.ENTRY_NODE.increaseBlockQps(count);
    }
   }
    throw e;
}

@Override
public void exit() {
DefaultNode node = (DefaultNode)context.getCurNode();
if (context.getCurEntry().getError() == null) {
    // 统计RT
    long rt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime();
    if (rt > Constants.TIME_DROP_VALVE) {
        rt = Constants.TIME_DROP_VALVE;
    }
    node.addRtAndSuccess(rt, count);
    if (context.getCurEntry().getOriginNode() != null) {
        context.getCurEntry().getOriginNode().addRtAndSuccess(rt, count);
    }
    // 递降线程数
    node.decreaseThreadNum();
    // 递降调用源线程数统计
    if (context.getCurEntry().getOriginNode() != null) {
        context.getCurEntry().getOriginNode().decreaseThreadNum();
    }
    // 全局ClusterNode递减请求数
    if (resourceWrapper.getType() == EntryType.IN) {
        Constants.ENTRY_NODE.addRtAndSuccess(rt, count);
        Constants.ENTRY_NODE.decreaseThreadNum();
    }
}
    fireExit(context, resourceWrapper, count);
}

小结:StatisticSlot职责主要统计信息:在请求通过时递增线程数和请求数;在被阻塞时设置异常信息以及递增被阻塞请求的数量;当退出时统计RT及递降线程数。Constants.ENTRY_NODE为final static的全局ClusterNode,为系统规则{@link SystemRule} 服务

五、SystemSlot职责

SystemSlot职责在于给予StatisticSlot的Constants.ENTRY_NODE全局ClusterNode统计信息与设定的阀值进行判断。代码详见:SystemSlot#entry

流程图
六、AuthoritySlot职责

AuthoritySlot职责主要在于对黑白名单进行判断。 代码详见:SystemSlot#entry

七、FlowSlot职责概览

代码详见:FlowSlot#entry

小结:FlowSlot主要职责在于给予之前的Node统计信息,根据不同的策略进行规则校验;未达到阀值放行,超过阀值触发流控抛出FlowException。详细FlowSlot实现后面写文章整理。

八、DegradeSlot职责概览

代码详见:DegradeSlot#entry

小结:DegradeSlot职责在于给予CluserNode统计信息提供不同的降级策略,根据设定的阀值进行降级

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 瓜农老梁 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.插槽链类图
  • ?
  • 二、NodeSelectorSlot&ClusterBuilderSlot调用结构
  • 1.1 示例代码
  • 1.2 调用结构图示
  • 1.3 内存运行结构
  • 2.1 代码示例
  • 2.2 调用结构图示
  • 2.3 内存运行结构
  • 3.1 NodeSelectorSlot源码
  • 3.2 ClusterBuilderSlot源码
  • 3.3 小结
  • 三、LogSlot职责
  • 四、StatisticSlot职责
  • 1.流程图
  • 2.主要源码走查
  • 五、SystemSlot职责
  • 流程图
  • 六、AuthoritySlot职责
  • 七、FlowSlot职责概览
  • 八、DegradeSlot职责概览
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档