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 文件中)
在这里插入图片描述

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() 获取
流程图如下
在这里插入图片描述

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

流程图如下
在这里插入图片描述

如何统计某个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 流量治理框架 - 编程界的小學生

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/397865.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Docker 安装 Kibana 8.4.3

使用 Docker 安装 Kibana 8.4.3 一. 安装启动 Kibana 8.4.3二. 简单使用2.1 向 Elasticsearch 发送请求2.2 搜索2.3 整体页面 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 安装k…

十五、Object 类

文章目录 Object 类6.1 public Object()6.2 toString方法6.3 hashCode和equals(Object)6.4 getClass方法6.5 clone方法6.6 finalize方法 Object 类 本文为书籍《Java编程的逻辑》1和《剑指Java&#xff1a;核心原理与应用实践》2阅读笔记 java.lang.Object类是类层次结构的根…

医卫医学试题及答案,分享几个实用搜题和学习工具 #笔记#笔记#微信

收录了大量考试类型的题库&#xff0c;大到考公&#xff0c;小到知识竞赛&#xff0c;题库资源算是比较丰富的了。操作起来也不难&#xff0c;我们只需输入题目内容&#xff0c;即可快速搜索出答案&#xff0c;而且它在给出答案的同时还会附带解析。最重要的是&#xff0c;搜题…

软件工具安装遇到bug、报错不知道怎么解决?看这里!

前言 本文举例了几个常见的软件工具使用问题&#xff0c;文末会提供一些我自己整理和使用的工具资料 。 "在追逐零 Bug 的路上&#xff0c;我们不断学习、改进&#xff0c;更加坚定自己的技术信念。让我们相信&#xff0c;每一个 Bug 都是我们成长的机会。" 一、VM…

09MARL深度强化学习policy gradient

文章目录 前言1、Multi-Agent Policy Gradient Theorem2、Centralised State-Value Critics2、Centralised Action-Value Critics 前言 Independent learning算法当中每个智能体看待其他智能体为环境的一部分&#xff0c;加剧了环境非平稳性&#xff0c;而CTDE框架的算法能够降…

防火墙——计算机网络

前述基于密码的安全机制不能有效解决以下安全问题&#xff1a; 用户入侵&#xff1a; 利用系统漏洞进行未授权登录&#xff1b; 授权用户非法获取更高级别权限等。 软件入侵&#xff1a; 通过网络传播病毒、蠕虫和特洛伊木马。 拒绝服务攻击等。 解决方法&#xff1a; 防火墙&a…

Camera2 setRepeatingRequest源码分析

当createCaptureSession流程执行完成后&#xff0c;应用在回调方法onConfigured就可以获得创建的CameraCaptureSession&#xff0c;接下来就可以调用CameraCaptureSession#setRepeatingRequest来下发camera stream命令获取camera数据。在CameraCaptureSession#setRepeatingRequ…

离线升级esp32开发板升级包esp32-2.0.14(最新版已经3.0alpha了)

1.Arduino IDE 2.3.2最新 2024.2.20升级安装:https://www.arduino.cc/en/software 2.开发板地址 地址&#xff08;esp8266,esp32&#xff09; http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32…

【Redis高手修炼之路】④主从复制

主从复制 就是 redis集群的策略配从&#xff08;库&#xff09;不配主&#xff08;库&#xff09;&#xff1a;小弟可以选择谁是大哥&#xff0c;但大哥没有权利去选择小弟读写分离&#xff1a;主机写&#xff0c;从机读 一主二仆 准备三台服务器&#xff0c;并修改redis.co…

HTTP 与HTTPS笔记

HTTP 80 HTTP是一个在计算机世界里专门在【两点】之间【传输】文字、图片、音频、视频等【超文本】数据的约定和规范。 HTTP状态码 1xx 提示信息&#xff0c;表示目前是协议处理的中间状态&#xff0c;还需要后续的操作&#xff1b;2xx 200 204 026 成功3xx 重定向&#xff…

MySQL篇之覆盖索引

一、定义 覆盖索引是指查询使用了索引&#xff0c;并且需要返回的列&#xff0c;在该索引中已经全部能够找到。 二、例子 1. id为主键&#xff0c;默认是主键索引。 2. name字段为普通索引。 select * from tb_user where id 1 覆盖索引 select id&#xff0c;na…

OPPO公布全新AI战略,AI 手机时代再提速

2024年2月20日&#xff0c;深圳——今日OPPO 举办 AI 战略发布会&#xff0c;分享新一代 AI 手机的四大能力特征&#xff0c;展望由AI驱动的手机全栈革新和生态重构的趋势&#xff0c;并发布由OPPO AI 超级智能体和 AI Pro 智能体开发平台组成的OPPO 1N 智能体生态战略&#xf…

提升网络灵活性,SD-WAN助您快速应对备用线路需求

随着企业规模不断扩大&#xff0c;传统网络架构在面对快速扩张的业务需求时显得力不从心&#xff0c;如同狭窄的道路难以容纳日益增多的车流和人群&#xff0c;访问流量的激增可能导致网络拥堵和延误&#xff0c;极大地影响业务正常访问。本文将详细介绍SD-WAN如何快速调整备用…

【MySQL】Navicat/SQLyog连接Ubuntu中的数据库(MySQL)

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、安装…

C++结合Lambda表达式在函数内部实现递归

529. 扫雷游戏 已解答 中等 相关标签 相关企业 让我们一起来玩扫雷游戏&#xff01; 给你一个大小为 m x n 二维字符矩阵 board &#xff0c;表示扫雷游戏的盘面&#xff0c;其中&#xff1a; M 代表一个 未挖出的 地雷&#xff0c;E 代表一个 未挖出的 空方块&#xff…

【贪心算法】代码随想录算法训练营第三十七天 |738.单调递增的数字,968.监控二叉树,总结(待补充)

738.单调递增的数字 1、题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 2、文章讲解&#xff1a;代码随想录 3、题目&#xff1a; 给定一个非负整数 N&#xff0c;找出小于或等于 N 的最大的整数&#xff0c;同时这个整数需要…

Java学习心得感悟

在我踏入Java学习的道路之前&#xff0c;我对编程只是一知半解&#xff0c;对于代码的世界充满了好奇和向往。然而&#xff0c;当我真正开始学习Java时&#xff0c;我才意识到&#xff0c;学习Java不仅仅是学习一门编程语言&#xff0c;更是一种思维方式和解决问题的能力的培养…

WireShark 安装指南:详细安装步骤和使用技巧

Wireshark是一个开源的网络协议分析工具&#xff0c;它能够捕获和分析网络数据包&#xff0c;并以用户友好的方式呈现这些数据包的内容。Wireshark 被广泛应用于网络故障排查、安全审计、教育及软件开发等领域。接下将讲解Wireshark的安装与简单使用。 目录 Wireshark安装步骤…

ArcGIS API for JavaScript 4.X 本地部署(js,字体)

0 目录&#xff08;4.19&#xff09; /4.19/ 1 修改文件 1.1 init.js 编辑器打开/4.19/init.js搜索文本[HOSTNAME_AND_PATH_TO_JSAPI]&#xff0c;然后将其连同前面的https://替换为http://ip地址/4.19&#xff0c;可以是localhost&#xff0c;只能本机引用 替换后&#xff…

对象的接口

“类”&#xff0c;那个类具有自己的通用特征与行为。 因此&#xff0c;在面向对象的程序设计中&#xff0c;尽管我们真正要做的是新建各种各样的数据“类型”&#xff08;Type&#xff09;&#xff0c;但几乎所有面向对象的程序设计语言都采用了“class”关键字。当您看到“ty…