sentinel的资源数据指标是如何采集

这篇具有很好参考价值的文章主要介绍了sentinel的资源数据指标是如何采集。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

资源数据采集

之前的NodeSelectorSlotClusterBuilderSlot已经完成了对资源调用树的构建, 现在则是要对资源进行收集, 核心点就是这些资源数据是如何统计

LogSlot

作用: 记录异常请求日志, 用于故障排查

public class LogSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode obj, int count, boolean prioritized, Object... args)
        throws Throwable {
        try {
            // 啥也没干, 直接调用下一个Slot
            fireEntry(context, resourceWrapper, obj, count, prioritized, args);
        } catch (BlockException e) {
            // 被流控或者熔断降级后直接打印log
            EagleEyeLogUtil.log(resourceWrapper.getName(), e.getClass().getSimpleName(), e.getRuleLimitApp(),
                                context.getOrigin(), e.getRule().getId(), count);
            throw e;
        } catch (Throwable e) {
            RecordLog.warn("Unexpected entry exception", e);
        }

    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        try {
            // 啥也没干,直接调用下一个 Slot
            fireExit(context, resourceWrapper, count, args);
        } catch (Throwable e) {
            RecordLog.warn("Unexpected entry exit exception", e);
        }
    }
}

LogSlot只做了一件事, 当出现BlockException 异常时, 记录log日志(EagleEyeLogUtil.log 会将日志写到 sentinel-block.log 文件中)
sentinel的资源数据指标是如何采集,sentinel,sentinel,java,开发语言

StatisticSlot

初始StatisticSlot

如果要设计一个 StatisticSlot,首先需要明确其需要实现的功能,即收集各种指标数据,如请求总数、请求成功数、请求失败数、响应时间等。

目前先把核心结构先列出来, 后续填充其他功能

public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                      boolean prioritized, Object... args) throws Throwable {
        try {
            // 调用责任链下一个 Slot
            fireEntry(context, resourceWrapper, node, count, prioritized, args);
        } catch (Throwable e) {
            throw e;
        }
    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        DefaultNode node = (DefaultNode)context.getCurNode();
        // 调用责任链下一个 Slot
        fireExit(context, resourceWrapper, count);
    }
}

错误信息和异常数统计

fireEntry()调用的是真正验证用于的Slot, 比如FlowSlot, DegradeSlot等, 如果后续验证不通过的话, 那么会抛出BlockException, 那么此时就可以使用try-catch捕获, 捕获后记录异常错误信息以及异常数

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    try {
        // 调用下一个Slot, 如果验证不通过, 那就捕获异常
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    } catch (BlockException e) {
        // 捕获 BlockException
        throw e;
    } catch (Throwable e) {
        // .....
        throw e;
    }
}

QPS和线程数统计

QPS和线程数的统计应该在什么时候统计?

可以fireEntry()之后进行统计, 调用fireEntry()

  • 如果没有报BlockException, 则表示没有被流控熔断降级
    • 将当前资源占用的线程数 + 1以及当前请求QPS + 1
  • 如果报了BlockException, 则表示被拦截了, 即请求失败
    • 将请求拒绝的QPS + 1

对于总的QPS则可以通过公式计算 总QPS = 成功QPS + 失败QPS

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    try {
        // 规则验证
        fireEntry(context, resourceWrapper, node, count, prioritized, args);

        // 如果能走到这里,则将当前资源占用的线程数 + 1 以及当前资源请求成功的 QPS 数 + 1
        node.increaseThreadNum();
        node.addPassRequest();
    } catch (BlockException e) { // 捕获 BlockException
        // 如果规则验证失败,则将 BlockQps + 1
        node.increaseBlockQps();
        throw e;
    } catch (Throwable e) {
        // .....
        throw e;
    }
}

响应时间统计

entry()是入口方法,相当于 AOP的before() 方法,那我们肯定会对应一个after() 方法,exit()是出口方法, 也就说可以在exit()中记录响应时间

@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
    Node node = context.getCurNode();
    if (context.getCurEntry().getBlockError() == null) {
        // 获取系统当前时间
        long completeStatTime = TimeUtil.currentTimeMillis();
        context.getCurEntry().setCompleteTimestamp(completeStatTime);
        // 得到响应时间,这个时间是哪里来的呢?是我们最初最开始为资源创建Entry对象时记录的。
        long rt = completeStatTime - context.getCurEntry().getCreateTimestamp();

        // 记录响应时间等信息
        recordCompleteFor(node, count, rt, error);

    }

    fireExit(context, resourceWrapper, count, args);
}

结束时间是在 StatisticsSlot 里的exit方法记录的,那开始时间是在哪记录的呢?在entry方法里记录可以吗?显然不妥,因为StatisticsSlot不是第一个Slot,不能作为请求的起始时间,起始时间应该放到初始化Entry资源管理对象,也就是只要资源诞生就意味着此次请求开始了,而且我们在设计 Entry 类的时候也将开始时间和结束时间两个字段设计进去了,因此我们开始时间我们可以直接通过 context.getCurEntry().getCreateTimestamp() 获取
流程图如下
sentinel的资源数据指标是如何采集,sentinel,sentinel,java,开发语言

DefaltNode, EntranceNode和ClusterNode的指标如何统计

  • DefaltNode:用于统计某个 Context 下某个资源的指标信息,维度是 Context + 资源
  • EntranceNode:用于统计某个 Context 下全部资源的指标信息,维度是 Context
  • ClusterNode:用于统计某个资源在全部 Context 下的指标信息,维度是资源,与 Context 无关

收集指标信息也就是每次请求就记录一下, 问题就是在哪里出发记录的动作?

即下述三个问题

  • 如何统计某个资源在某个Context下的指标?
  • 如何统计某个Context下所有资源的指标?
  • 如何统计某个资源在全部Context中的指标?
如何统计某个资源在某个Context下的指标?
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    try {
        fireEntry(context, resourceWrapper, node, count, prioritized, args);

        // 数据统计
        node.increaseThreadNum();
        node.addPassRequest(count);
    }
}

可以发现 increaseThreadNum()addPassRequest() 方法都是node调用的,那node是什么呢?

node是DefaultNode类型的方法参数,我们还知道 entry() 方法是通过上一个责任链:ClusterSlot调用的,也就是说node这个参数是前面Slot传过来的,其实,我们回溯回去,会发现这个node就是DefaultNode本身,并不是它的子类EntranceNode。因此,我们得出一个结论:StatisticSlot直接调用DefaultNode里的方法进行指标收集,我们又知道DefaultNode的维度是Context + 资源

public class DefaultNode extends StatisticNode {
    // 和资源绑定
    private ResourceWrapper id;

    private ClusterNode clusterNode;

    // 增加线程数
    @Override
    public void increaseThreadNum() {
        super.increaseThreadNum();
        this.clusterNode.increaseThreadNum();
    }

    // 增加请求成功数
    @Override
    public void addPassRequest(int count) {
        super.addPassRequest(count);
        this.clusterNode.addPassRequest(count);
    }
}

DefaultNode核心源码

public class DefaultNode extends StatisticNode {
    // 和资源绑定
    private ResourceWrapper id;

    private ClusterNode clusterNode;
    
    // 增加线程数
    @Override
    public void increaseThreadNum() {
        super.increaseThreadNum();
        this.clusterNode.increaseThreadNum();
    }

    // 增加请求成功数
    @Override
    public void addPassRequest(int count) {
        super.addPassRequest(count);
        this.clusterNode.addPassRequest(count);
    }
}

DefaultNode 的维度是 Context + 资源,DefaultNode源码里只看到了资源 ResourceWrapper,没有看到Context呢?在NodeSelectorSlot的entry()方法里我们会初始化DefaultNode 且与Context进行绑定(Key-Value形式),核心代码

public class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> {
    // Context#name与DefaultNode 进行绑定
    private volatile Map<String, DefaultNode> map = new HashMap<String, DefaultNode>(10);

    public void entry(...) {
        DefaultNode node = new DefaultNode(resourceWrapper, null);
        map.put(context.getName(), node);
    }
}

要想获取某个资源在某 Context 下的指标时

  1. 从map中获取DefaultNode
  2. 从DefaultNode获取资源Id

流程图如下
sentinel的资源数据指标是如何采集,sentinel,sentinel,java,开发语言

如何统计某个Context下所有资源的指标?

也就是不细分资源,直接统计Context

如何找到当前Context下的全部资源呢?

  1. 一个资源肯定对应一个DefaultNode
  2. EntranceNode相当于树干,它有很多树枝 DefaultNode 挂到其下面
public class EntranceNode extends DefaultNode {
    // 树枝
    private volatile Set<Node> childList = new HashSet<>();
}

有了这个 childList 事情就变得简单了,直接 for 循环遍历即可,获取到的是每个 DefaultNode,然后调用每个 DefaultNode 的统计方法进行求和即可,如下所示:

public class EntranceNode extends DefaultNode {
    @Override
    public int curThreadNum() {
        int r = 0;
        // 遍历 DefaultNode 子集
        for (Node node : getChildList()) {
            // += 操作求和
            r += node.curThreadNum();
        }
        return r;
    }

    @Override
    public double passQps() {
        double r = 0;
        for (Node node : getChildList()) {
            r += node.passQps();
        }
        return r;
    }
}
如何统计某个资源在全部Context中的指标?

我们知道 ClusterNode 是在 DefaultNode 下的,一个资源至少对应一个 DefaultNode 以及会对应唯一一个 ClusterNode (因为 ClusterNode 的维度是资源,所以不管资源在哪几个 Context 下,都只会对应唯一一个 ClusterNode)

上边的DefaultNode 的时候不管是 increaseThreadNum() 还是 addPassRequest() 都会调用一个方法叫:this.clusterNode.increaseXxx(),其实这就是用于统计某个资源在所有 Context 下的指标信息的

public void increaseThreadNum() {
    super.increaseThreadNum();
    // clusterNode.xxx
    this.clusterNode.increaseThreadNum();
}
public void addPassRequest(int count) {
    super.addPassRequest(count);
    // clusterNode.xxx
    this.clusterNode.addPassRequest(count);
}

总结

StatisticSlot只负责指标统计, 调用相关的统计方法进行实现, Sentinel底层采用滑动窗口, 令牌桶, 漏桶三个算法

参考资料

通关 Sentinel 流量治理框架 - 编程界的小學生文章来源地址https://www.toymoban.com/news/detail-831923.html

到了这里,关于sentinel的资源数据指标是如何采集的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 夜莺初探四·mtail插件采集日志指标

    上一篇介绍了Categraf的配置,这篇我们尝试通过使用google开源的mtail工具来作为Categraf的插件,从应用日志中提取指标数据。 通过mtail -h可以很方便看到参数详细,也推荐乔克-从日志中提取指标的瑞士军刀或者Dream运维梦工厂-categraf-mtail日志收集插件详解来了解更多,我就不再班

    2024年02月04日
    浏览(33)
  • idea Springboot 高校科研资源共享系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

    一、源码特点   springboot 高校科研资源共享系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发), 系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 springboot 高校科研资源共享

    2024年02月07日
    浏览(68)
  • 【C语言】数据结构的基本概念与评价算法的指标

    1.1 基本概念和术语 1.1.1 数据 数据是信息的载体,是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。数据是计算机程序加工的原料 1.1.2 数据元素 数据元素是数据的基本单位,通常作为一个整体进行考虑和处理,一个数据元素

    2024年02月09日
    浏览(36)
  • 如何构建大数据指标分析系统

    前言 :技术是为了需求服务。技术的第一性原则是解决问题,不同的技术方案都能实现同样的需求,那在公司原有技术架构上,如何设计技术架构,尽量用最少的大数据组件解决多种应用场景问题。分析分为实事状态分析和预测分析(特征工程),本文用对事实状态指标分析

    2024年01月20日
    浏览(44)
  • Sentinel源码分析-ProceesorSlotChain调用链及树状资源节点

    Sentinel 实现流控,隔离,降级等功能,本质要做两件事: 数据统计: 统计某个资源的访问数据(QPS,RT(响应时间),异常比例)等信息 规则判断: 判断流控规则,隔离规则,降级规则是否满足。 ProcessorSlotChian 实现上述功能的骨架,这个类是基于责任链模式设计,将不同功

    2024年02月09日
    浏览(40)
  • 【开源】基于JAVA语言的教学资源共享平台

    基于JAVA+Vue+SpringBoot+MySQL的教学资源共享平台,包含了课程管理、课程课件、授课中心、作业发布、课程评价、课程质量分析、交流互动模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,教学资源

    2024年01月20日
    浏览(54)
  • MySQL性能监控全掌握,快来get关键指标及采集方法!

    数据库中间件监控实战,MySQL中哪些指标比较关键以及如何采集这些指标了。帮助提早发现问题,提升数据库可用性。 监控哪类指标? 如何采集数据? 第10讲监控方法论如何落地? 这些就可以在MySQL中应用起来。MySQL是个服务,所以可借用Google四个黄金指标解决问题: 1.1 延

    2024年02月02日
    浏览(44)
  • 大数据开发之Hive(统计影音视频网站的常规指标)

    1、视频表 字段 备注 详细描述 videoId 视频唯一id(String) 11位字符串 uploader 视频上传者(String) 上传视频的用户名String age 视频年龄(int) 视频在平台上的整天数 category 视频类别(Array) 上传视频指定的视频分类 length 视频长度(Int) 整形数字标识的视频长度 views 观看次数(Int) 视频被浏

    2024年01月19日
    浏览(45)
  • 【开源】基于JAVA语言的课程案例资源库系统

    基于JAVA+Vue+SpringBoot+MySQL的课程案例资源库系统,包含了案例资源模块、用户交流模块、意见反馈模块、敏感信息模块、举报信息模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,课程案例资源库

    2024年01月23日
    浏览(53)
  • C语言爬虫采集图书网站百万数据

    最近需要查阅一些资料,只给到相关项目名称以及,想通过图书文库找到对应书籍,那么怎么才能在百万数据库中找到自己需要的文献呢? 今天我依然用C语言写个爬虫程序,从百万数据库中查找到适合的文章,能节省很多事情。 下面是一个简单的C#爬虫程序,它使用

    2024年01月21日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包