Ali-Sentinel-节点与度量

归档

  • GitHub: Ali-Sentinel-节点与度量

作用

  • 保存资源的实时统计信息

节点

节点-类结构

  • com.alibaba.csp.sentinel.slots.statistic.metric.DebugSupport
/** 调试支持 */
public interface DebugSupport {void debug();   // 打印统计信息
}
  • com.alibaba.csp.sentinel.node.OccupySupport
/** 占用支持 */
public interface OccupySupport {...
}
  • com.alibaba.csp.sentinel.node.Node
/** 节点 (用于统计) */
public interface Node extends OccupySupport, DebugSupport {long totalRequest();    // 获取每分钟传入的请求long totalPass();       // 获取每分钟的通过次数long totalSuccess();    // 每分钟完成的请求(Entry.exit())总数long blockRequest();    // 获取每分钟阻止的请求计数long totalException();  // 获取每分钟的异常计数double passQps();       // 获取每秒已通过请求的 QPSdouble blockQps();      // 获取每秒被阻止请求的 QPSdouble totalQps();      // 获取每秒总请求的 QPSdouble successQps();    // 获取每秒已完成请求的(Entry.exit()) QPSdouble maxSuccessQps(); // 获得最大已完成请求的 QPSdouble exceptionQps();  // 发生异常的 QPSdouble avgRt();         // 平均每秒响应时间 (Rt: response time)double minRt();int curThreadNum();double previousBlockQps();double previousPassQps();void addPassRequest(int count);void addRtAndSuccess(long rt, int success);void increaseBlockQps(int count);void increaseExceptionQps(int count);void increaseThreadNum();void decreaseThreadNum();void reset();
}
  • com.alibaba.csp.sentinel.node.StatisticNode
/** 统计节点 */
public class StatisticNode implements Node {// 保存最近 INTERVAL(1000) 毫秒的统计信息。// 节点的统计逻辑都委派给其处理,ref: sign_i_100 & sign_c_100private transient volatile Metric rollingCounterInSecond = new ArrayMetric(                 // sign_cm_101SampleCountProperty.SAMPLE_COUNT,   // def: 2IntervalProperty.INTERVAL           // def: 1000);// 保存最近 60 秒的统计信息。// 节点的统计逻辑都委派给其处理,ref: sign_i_100 & sign_c_100private transient Metric rollingCounterInMinute = new ArrayMetric(60, 60 * 1000, false);    // sign_cm_102// -----------private LongAdder curThreadNum = new LongAdder();private long lastFetchTime = -1;
}
  • com.alibaba.csp.sentinel.node.DefaultNode
/** 默认节点 */
public class DefaultNode extends StatisticNode {private ResourceWrapper id;         // 关联的资源 (标识)private volatile Set<Node> childList = new HashSet<>(); // 子节点集private ClusterNode clusterNode;    // 关联的群集节点。
}
  • com.alibaba.csp.sentinel.node.EntranceNode
/** 入口节点 */
public class EntranceNode extends DefaultNode {... // 只是根据所有的子节点进行计算统计结果
}
  • com.alibaba.csp.sentinel.node.ClusterNode
/** 集群节点 */
public class ClusterNode extends StatisticNode {private final String name;          // 名称private final int resourceType;     // 资源类型 (0: COMMON; 1: WEB; 2: RPC; 3: ApiGateway; 4: DB)private Map<String, StatisticNode> originCountMap = new HashMap<>(); // 保存不同来源的 StatisticNodeprivate final ReentrantLock lock = new ReentrantLock(); // 操作 originCountMap 的 DCL 锁
}

节点-调用链

  • 基本委派给度量指标了

度量指标

  • 节点的统计都委派给 ArrayMetric

度量指标-类结构

  • com.alibaba.csp.sentinel.slots.statistic.metric.Metric
/** sign_i_100 度量接口 */
public interface Metric extends DebugSupport {long success();                 // 获取总成功数。long maxSuccess();              // 获取最大成功次数。long exception();               // 获取异常总数。long block();                   // 获取总阻塞次数。long pass();                    // 获取总通过数。 不包括 occupiedPass()long rt();                      // 获取总响应时间。long minRt();                   // 获得最小的 RT。List<MetricNode> details();     // 获取所有资源的聚合指标节点。MetricBucket[] windows();       // 获取原始窗口数组。void addException(int n);       // 添加当前异常计数。void addBlock(int n);           // 添加当前阻塞数。void addSuccess(int n);         // 添加当前完成的计数。...
}
  • com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric
/** sign_c_100 度量实现类 */
public class ArrayMetric implements Metric {    // 实现 sign_i_100private final LeapArray<MetricBucket> data; // 统计依然向下委派处理,ref: sing_ac_110// sign_cm_101public ArrayMetric(int sampleCount, int intervalInMs) {this.data = new OccupiableBucketLeapArray(sampleCount, intervalInMs);   // 秒统计的使用此,ref: sign_cm_110}// sign_cm_102public ArrayMetric(int sampleCount, int intervalInMs, boolean enableOccupy) {if (enableOccupy) {this.data = new OccupiableBucketLeapArray(sampleCount, intervalInMs);} else {this.data = new BucketLeapArray(sampleCount, intervalInMs);         // 分统计的使用此,ref: sign_cm_110}}
}
  • com.alibaba.csp.sentinel.slots.statistic.base.LeapArray
/** sing_ac_110 统计指标的基本数据结构 */
public abstract class LeapArray<T> {protected int windowLengthInMs;     // 窗口时间跨度protected int sampleCount;protected int intervalInMs;private double intervalInSecond;protected final AtomicReferenceArray<WindowWrap<T>> array;      // T: MetricBucket, ref: sign_c_130 | sing_c_140// 更新锁,仅在当前 bucket 已弃用时使用。private final ReentrantLock updateLock = new ReentrantLock();// sign_cm_110public LeapArray(int sampleCount, int intervalInMs) {... // 省略校验 (两参必须大于 0,且能整除)this.windowLengthInMs = intervalInMs / sampleCount;this.intervalInMs = intervalInMs;this.intervalInSecond = intervalInMs / 1000.0;this.sampleCount = sampleCount;this.array = new AtomicReferenceArray<>(sampleCount);}}
  • com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap
/** sign_c_130 一段时间窗口的包装实体类 */
public class WindowWrap<T> {private final long windowLengthInMs;    // 单个窗口桶的时间长度(以毫秒为单位)。private long windowStart;               // 窗口的开始时间戳(以毫秒为单位)。private T value;                        // 统计数据。一般为: MetricBucket, ref: sing_c_140public WindowWrap(long windowLengthInMs, long windowStart, T value) {this.windowLengthInMs = windowLengthInMs;this.windowStart = windowStart;this.value = value;}}
  • com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket
/** sing_c_140 度量桶 (一段时间内的度量数据) */
public class MetricBucket {private final LongAdder[] counters; // sign_f_110 各事件的计数器private volatile long minRt;        // 记录最小 RT 值。def: 5000public MetricBucket() {MetricEvent[] events = MetricEvent.values();        // ref: sign_ec_140this.counters = new LongAdder[events.length];for (MetricEvent event : events) {counters[event.ordinal()] = new LongAdder();    // 每个事件,一个计数器}initMinRt();    // 使用配置的最大 RT 值初始化}}
  • com.alibaba.csp.sentinel.slots.statistic.MetricEvent
/** sign_ec_140 事件枚举 */
public enum MetricEvent {PASS,BLOCK,EXCEPTION,SUCCESS,RT,/*** 在未来配额中通过(自 1.5.0 起,预先占用)*/OCCUPIED_PASS
}

度量指标-调用链

addPass()
  • 添加 PASS 计数

  • com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric

    @Overridepublic void addPass(int count) {WindowWrap<MetricBucket> wrap = data.currentWindow();   // 获取当前时间戳的桶  ref: sign_m_201wrap.value().addPass(count);    // 添加 PASS 计数  ref: sign_m_210}
  • com.alibaba.csp.sentinel.slots.statistic.base.LeapArray
    // sign_m_201 获取当前时间戳的桶public WindowWrap<T> currentWindow() {return currentWindow(TimeUtil.currentTimeMillis()); // sign_m_202}// sign_m_202 在提供的时间戳处获取桶public WindowWrap<T> currentWindow(long timeMillis) {... // 省略小于 0 的判断int idx = calculateTimeIdx(timeMillis);                 // sign_m_203 计算当前索引long windowStart = calculateWindowStart(timeMillis);    // sign_m_204 计算当前窗口的开始时间/*** 从数组中获取给定时间的存储桶。** (1) Bucket 不存在,则只需创建一个新的 Bucket 并 CAS 更新为循环数组。* (2) Bucket 是最新的,那么只需返回 Bucket 即可。* (3) Bucket 已弃用,然后重置当前 Bucket。*/while (true) {WindowWrap<T> old = array.get(idx);if (old == null) {  // 桶不存在,则创建/*** newEmptyBucket(timeMillis) 为抽象方法,* 两子类实现:直接返回 new MetricBucket()*/WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));if (array.compareAndSet(idx, null, window)) {   // CAS 更新return window;  // 更新成功,返回创建的 bucket} else {Thread.yield(); // 争用失败,让出时间片等待可用的桶}} else if (windowStart == old.windowStart()) {  // 桶是最新的// 表明另一线程刚好调用上面或下面的逻辑(创建出桶并 CAS 更新完或重置完旧桶)return old;} else if (windowStart > old.windowStart()) {   // 桶是旧的/*** 使用锁,保证重置和清理是原子操作*/if (updateLock.tryLock()) {try {return resetWindowTo(old, windowStart); // 重置桶(抽象方法),实现参考: sign_m_206} finally {updateLock.unlock();}} else {Thread.yield(); // 争用失败,让出时间片等待可用的桶}} else if (windowStart < old.windowStart()) {// 不应该到这里...return new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));}}}// sign_m_203 计算当前索引,以便将时间戳映射到跳跃 (leap) 数组private int calculateTimeIdx(long timeMillis) {long timeId = timeMillis / windowLengthInMs;    // 除窗口时间跨度,得窗口主索引return (int)(timeId % array.length());          // 用主索引取模,映射到数组索引}// sign_m_204 计算窗口的开始时间 (向前取整)protected long calculateWindowStart(long timeMillis) {return timeMillis - timeMillis % windowLengthInMs;}
  • com.alibaba.csp.sentinel.slots.statistic.metric.BucketLeapArray
    // sign_m_206 重置相关统计@Overrideprotected WindowWrap<MetricBucket> resetWindowTo(WindowWrap<MetricBucket> w, long startTime) {// Update the start time and reset value.w.resetTo(startTime);   // 重置 bucket 封装的开始时间戳 sign_m_207w.value().reset();      // 重置 bucket 各事件计数器 sign_m_208return w;}
  • com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap
    // sign_m_207 重置当前 bucket 的开始时间戳public WindowWrap<T> resetTo(long startTime) {this.windowStart = startTime;return this;}
  • com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket
    // sign_m_208 重置各事件计数器public MetricBucket reset() {for (MetricEvent event : MetricEvent.values()) {counters[event.ordinal()].reset();}initMinRt();return this;}
  • com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket
    // sign_m_210 添加 PASS 计数public void addPass(int n) {add(MetricEvent.PASS, n);   // sign_m_211}// sign_m_211 添加指定事件的计数public MetricBucket add(MetricEvent event, long n) {counters[event.ordinal()].add(n);   // 根据枚举的序数定位计数器,然后进行累加  ref: sign_f_110return this;}
pass()
  • 获取 PASS 计数

  • com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric

    @Overridepublic long pass() {data.currentWindow();   // 设置当前时间对应的桶,ref: sign_m_201long pass = 0;List<MetricBucket> list = data.values();    // 获取当前“有效”桶的集合  ref: sign_m_220for (MetricBucket window : list) {pass += window.pass();  // 对每个度量桶的 PASS 进行累加  ref: sign_m_225}return pass;}
  • com.alibaba.csp.sentinel.slots.statistic.base.LeapArray
    // sign_m_220 获取当前“有效”桶的集合public List<T> values() {return values(TimeUtil.currentTimeMillis()); // sign_m_221}// sign_m_221 获取指定时间戳“有效”桶的集合public List<T> values(long timeMillis) {if (timeMillis < 0) {return new ArrayList<T>();}int size = array.length();List<T> result = new ArrayList<T>(size);for (int i = 0; i < size; i++) {WindowWrap<T> windowWrap = array.get(i);/*** 为空或当前时间大于桶的开始时间 (桶无效),则不添加* ref: sign_m_222*/if (windowWrap == null || isWindowDeprecated(timeMillis, windowWrap)) {continue;}result.add(windowWrap.value()); // 否则添加返回}return result;}// sign_m_222 判断桶是否无效// 桶开始时间必须小于当前时间才算有效,否则算无效 (返回 true)public boolean isWindowDeprecated(long time, WindowWrap<T> windowWrap) {return time - windowWrap.windowStart() > intervalInMs;}
  • com.alibaba.csp.sentinel.slots.statistic.data.MetricBucket
    // sign_m_225 返回 PASS 计数public long pass() {return get(MetricEvent.PASS);   // sign_m_226}// sign_m_226 返回指定事件的计数public long get(MetricEvent event) {return counters[event.ordinal()].sum();}

总结

  • 使用数组 + 时间戳实现滑动窗口,算法简单精妙

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python基础知识(二)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》 《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 1.输入和输出函数1.1输出函数1.2输入函数 2.常见运算符2.1赋值运算符2.2比较运算符2.3逻辑运算符2.4and逻辑与2.5or逻辑或2.6not逻…

nvidia-smi详解

nvidia-smi&#xff1a;控制你的 GPU 大多数用户都知道如何检查他们的 CPU 的状态&#xff0c;查看有多少系统内存可用&#xff0c;或者找出有多少磁盘空间可用。相比之下&#xff0c;从历史上看&#xff0c;密切关注 GPU 的运行状况和状态一直比较困难。如果您不知道去哪里寻…

c++二叉树的进阶--二叉搜索树

1. 二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左…

Swift-27-类的初始化与销毁

Swift的初始化是一个有大量规则的固定过程。初始化是设置类型实例的操作&#xff0c;包括给每个存储属性初始值&#xff0c;以及一些其他准备工作。完成这个过程后&#xff0c;实例就可以使用了。 简单来讲就是类的构造函数&#xff0c;基本语法如下&#xff1a; 注意&#xff…

C语言扫雷游戏完整实现(上)

文章目录 前言一、新建好头文件和源文件二、实现游戏菜单选择功能三、定义游戏函数四、初始化棋盘五、 打印棋盘函数六、布置雷函数七、玩家排雷菜单八、标记功能的菜单九、标记功能菜单的实现总结 前言 C语言从新建文件到游戏菜单&#xff0c;游戏函数&#xff0c;初始化棋盘…

JavaScript-4.正则表达式、BOM

正则表达式 正则表达式包含在"/"&#xff0c;"/"中 开始与结束 ^ 字符串的开始 $ 字符串的结束 例&#xff1a; "^The"&#xff1a;表示所有以"The"开始的字符串&#xff08;"There"、"The cat"等&#x…

数据结构(八)——排序

八、排序 8.1 排序的基本概念 排序(Sort)&#xff0c;就是重新排列表中的元素&#xff0c;使表少的元素满足按关键字有序的过程。 输入∶n个记录R1,R2...., Rn&#xff0c;对应的关键字为k1, k2,... , kn 输出:输入序列的一个重排R1,R2....,Rn&#xff0c;使得有k1≤k2≤...≤…

综合大实验

题目&#xff1a; 1、R4为ISP&#xff0c;其上只配置IP地址&#xff1b;R4与其他所直连设备间均使用公有IP&#xff1b; 2、R3-R5、R6、R7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3、整个OSPF环境IP基于172.16.0.0/16划分&#xff1b;除了R12有两个环回&#xff0c;其…

VUE父组件向子组件传递值

创作灵感 最近在写一个项目时&#xff0c;遇到了这样的一个需求。我封装了一个组件&#xff0c;这个组件需要被以下两个地方使用&#xff0c;一个是搜索用户时用到&#xff0c;一个是修改用户信息时需要用到。其中&#xff0c;在搜索用户时&#xff0c;可以根据姓名或者账号进…

OllyDbg 快捷键及常用法

keywords: debug, ollydbg 快捷键 Ctrl --> C Shift --> S Alt --> M 功能快捷键设置/取消断点F2执行到光标所在行F4步过F8步进F7运行F9暂停F12回到应用层M-F9打开文件F3重新调试C-F2打开应用程序输入表C-n寻找表达式C-g打开断点窗口M-b切换断点状态空格添加备注…

[前端]NVM管理器安装、nodejs、npm、yarn配置

NVM管理器安装、nodejs、npm、yarn配置 NVM管理器安装 nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 1.全部…

Unity面向切面编程

一直说面向AOP&#xff08;切面&#xff09;编程&#xff0c;好久直接专门扒出理论、代码学习过。最近因为某些原因&#x1f62d;还得再学学造火箭的技术。 废话不多说&#xff0c;啥是AOP呢&#xff1f;这里我就不班门弄斧了&#xff0c;网上资料一大堆&#xff0c;解释的肯定…

mybatis中<if>条件判断带数字的字符串失效问题

文章目录 一、项目背景二、真实错误原因说明三、解决方案3.1针对纯数字的字符串值场景3.2针对单个字符的字符串值场景 四、参考文献 一、项目背景 MySQL数据库使用Mybatis查询拼接select语句中进行<if>条件拼接的时候&#xff0c;发现带数字的或者带单个字母的字符串失效…

CPU资源控制

一、CPU资源控制定义 cgroups&#xff08;control groups&#xff09;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 所以cgroups&#xff08;control groups&#xf…

在ubuntu20上编译bcc时遇到:Could NOT find LibDebuginfod

参考&#xff1a;https://github.com/iovisor/bcc/issues/3601 环境 Ubuntu20.04 ARM64 问题 编译bcc时报下面的错误&#xff1a; -- Found BISON: /usr/bin/bison (found version "3.5.1") -- Found FLEX: /usr/bin/flex (found version "2.6.4") …

Netty学习——实战篇5 Netty 心跳监测/WebSocket长连接编程 备份

1 心跳监测 MyServer.java public class MyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup new NioEventLoopGroup(1);NioEventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap serverBootstrap new ServerBootstrap…

leetcode145--二叉树的后序遍历

1. 题意 求后序遍历 2. 题解 2.1 递归 class Solution { public:void addPost(TreeNode *root, vector<int> &res) {if ( nullptr root)return ;addPost(root->left, res);addPost(root->right, res);res.emplace_back( root->val );}vector<int>…

设计前后端系统以处理长时间运行的计算任务并提供缓存支持

后端设计 1. 任务队列 创建一个任务队列来存储提交的计算任务。 Component public class TaskQueue {private final Queue<CalculationTask> queue new LinkedList<>();public synchronized void addTask(CalculationTask task) {queue.add(task);}public sync…

C++ 全量枚举

在C中&#xff0c;全量枚举通常指的是为一个类型的所有可能值创建一个枚举。这样可以使代码更具可读性&#xff0c;特别是当你需要处理有限的、固定的值集合时。 下面是一个简单的例子&#xff0c;展示了如何定义和使用枚举&#xff1a; #include <iostream>// 定义枚举…

lvresize与lvextend扩容逻辑卷的区别

这两条命令都是用来扩展逻辑卷&#xff08;Logical Volume&#xff09;的命令&#xff0c;但是有一些区别&#xff1a; 1. lvresize命令&#xff1a; - lvresize命令是用来调整逻辑卷的大小的&#xff0c;可以缩小或扩大逻辑卷的大小。 - 在使用lvresize命令时&#xff0c;需…