sentinel系统负载自适应流控

news2024/11/15 2:08:07

系统负载自适应流控

规则配置

规则创建

public class SystemRule extends AbstractRule {
    private double highestSystemLoad = -1;
    private double highestCpuUsage = -1;
    private double qps = -1;
    private long avgRt = -1;
    private long maxThread = -1;
}

SystemRule类包含了以下几个指标。

  • highestSystemLoad:对应 Dashboard 上的 LOAD 菜单,代表系统最高负载值,默认为 -1,只有大于等于 0.0 才生效。
  • avgRt:对应 Dashboard 上的 RT菜单,代表系统平均响应时间,默认为 -1,只有大于0才生效。
  • maxThread:对应 Dashboard 上的线程数菜单,代表系统允许的最大线程数,默认为 -1,只有大于 0 才生效。
  • qps:对应 Dashboard 上的入口 QPS 菜单,代表限流的阈值,默认为 -1,只有大于 0 才生效。
  • highestCpuUsage:对应 Dashboard 上的 CPU 使用率菜单,代表最高CPU 使用率,取值是 [0,1] 之间,默认为 -1,只有大于等于0.0才生效
监听器实例化和管理

这部分和之前的黑白名单差不多

系统负载自适应规则的核心类是 SystemRuleManager,它负责管理系统负载自适应规则的加载、更新和监听。当系统负载自适应规则发生变化时,SystemRuleManager 通过观察者模式通知相应的 RulePropertyListener 进行更新

创建监听器的代码位置

public final class SystemRuleManager {
    // 省略其它代码...

    private static AtomicBoolean checkSystemStatus = new AtomicBoolean(false);

    private static SystemStatusListener statusListener = null;
    private final static SystemPropertyListener listener = new SystemPropertyListener();
    private static SentinelProperty<List<SystemRule>> currentProperty = new DynamicSentinelProperty<List<SystemRule>>();

    // 创建单核线程池
    private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
                                                                                               new NamedThreadFactory("sentinel-system-status-record-task", true));

    static {

        checkSystemStatus.set(false);
        // 初始化系统状态监听器
        statusListener = new SystemStatusListener();
        // 任务调度, 一秒执行一次statusListener的任务, 即监听系统的负载状态
        scheduler.scheduleAtFixedRate(statusListener, 0, 1, TimeUnit.SECONDS);
        // 初始化SystemRule监听器
        currentProperty.addListener(listener);
    }

    // 省略其它代码...
}

规则初始化

当调用SystemRuleManagerloadRules()

public static void loadRules(List<SystemRule> rules) {
    currentProperty.updateValue(rules);
}


@Override
public boolean updateValue(T newValue) {
    if (isEqual(value, newValue)) {
        return false;
    }
    RecordLog.info("[DynamicSentinelProperty] Config will be updated to: {}", newValue);
	
    // 注意看这里, 和之前的黑白名单规则一样, 也是初始化了
    value = newValue;
    for (PropertyListener<T> listener : listeners) {
        // 遍历通知监听器
        listener.configUpdate(newValue);
    }
    return true;
}


@Override
public synchronized void configUpdate(List<SystemRule> rules) {
    // 为了恢复这些系统设置到初始状态,以便重新进行监控和设置
    restoreSetting();
    // systemRules = rules;
    // 如果配置SystemRule, 那么遍历规则, 并加载规则
    if (rules != null && rules.size() >= 1) {
        for (SystemRule rule : rules) {
            // 加载系统配置,根据传入的SystemRule对象中的参数设置系统最高负载、CPU使用率、平均响应时间、最大线程数和QPS
            loadSystemConf(rule);
        }
    } else { // 如果没有配置SystemRule, 那么关闭系统自适应检查
        checkSystemStatus.set(false);
    }
    
    // 省略其它代码...
}

核心loadSystemConf()

此方法会判断是否配置了 LOAD、RT、THREAD、QPS、CPU,如果配置这些规则中的某一个,那么就将 checkSystemStatus 置为 true,也就是打开系统自适应功能

也就是说, 系统自适应功能是否开启就看这个方法

public static void loadSystemConf(SystemRule rule) {
    boolean checkStatus = false;
    // Check if it's valid.

    // highestSystemLoad参数大于等于0且小于当前最高系统负载,则更新最高系统负载,并标记为已设置
    if (rule.getHighestSystemLoad() >= 0) {
        highestSystemLoad = Math.min(highestSystemLoad, rule.getHighestSystemLoad());
        highestSystemLoadIsSet = true;
        checkStatus = true;
    }

    // 如果highestCpuUsage参数大于0且小于等于1,则更新CPU使用率的最高限制,并标记为已设置,如果大于1则记录警告日志
    if (rule.getHighestCpuUsage() >= 0) {
        if (rule.getHighestCpuUsage() > 1) {
            RecordLog.warn(String.format("[SystemRuleManager] Ignoring invalid SystemRule: "
                                         + "highestCpuUsage %.3f > 1", rule.getHighestCpuUsage()));
        } else {
            highestCpuUsage = Math.min(highestCpuUsage, rule.getHighestCpuUsage());
            highestCpuUsageIsSet = true;
            checkStatus = true;
        }
    }

    // 如果果avgRt参数大于等于0,则更新平均响应时间的最高限制,并标记为已设置
    if (rule.getAvgRt() >= 0) {
        maxRt = Math.min(maxRt, rule.getAvgRt());
        maxRtIsSet = true;
        checkStatus = true;
    }
    
    // 如果maxThread参数大于等于0,则更新最大线程数的最高限制,并标记为已设置
    if (rule.getMaxThread() >= 0) {
        maxThread = Math.min(maxThread, rule.getMaxThread());
        maxThreadIsSet = true;
        checkStatus = true;
    }

    // 如果qps参数大于等于0,则更新QPS的最高限制,并标记为已设置
    if (rule.getQps() >= 0) {
        qps = Math.min(qps, rule.getQps());
        qpsIsSet = true;
        checkStatus = true;
    }

    // 根据上述值决定是否开启系统自适应检查
    checkSystemStatus.set(checkStatus);

}

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

规则验证

SystemSlot是第六个执行的slot

public class SystemSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {
        // 检查系统规则
        SystemRuleManager.checkSystem(resourceWrapper, count);

        // 如果检查通过,继续执行后续的处理链
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }

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

核心方法就是checkSystem()

public static void checkSystem(ResourceWrapper resourceWrapper, int count) throws BlockException {
    // 参数验证,资源为空直接放行
    if (resourceWrapper == null) {
        return;
    }
    // 判断系统自适应功能是否开启,如果没开启则直接放行。
    if (!checkSystemStatus.get()) {
        return;
    }

    // 判断资源的流量是否为入口流量,如果不是IN,则直接放行,也就是说Sentinel系统自适应限流只对入口流量生效,如果类型为OUT则直接放行
    if (resourceWrapper.getEntryType() != EntryType.IN) {
        return;
    }

    // 获取当前qps,如果当前qps大于SystemRule规则配置的阈值,则直接抛BlockException异常
    double currentQps = Constants.ENTRY_NODE.passQps();
    if (currentQps + count > qps) {
        throw new SystemBlockException(resourceWrapper.getName(), "qps");
    }

    // 获取当前线程,如果当前线程大于SystemRule规则配置的阈值,则直接抛BlockException 异常
    int currentThread = Constants.ENTRY_NODE.curThreadNum();
    if (currentThread > maxThread) {
        throw new SystemBlockException(resourceWrapper.getName(), "thread");
    }

    // 获取当前平均响应时间指标,如果当前平均响应时间大于SystemRule规则配置的阈值,则直接抛BlockException异常
    double rt = Constants.ENTRY_NODE.avgRt();
    if (rt > maxRt) {
        throw new SystemBlockException(resourceWrapper.getName(), "rt");
    }

    // 如果当前系统负载大于规则配置的系统负载,则采取bbr算法验证
    if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
        // bbr算法
        if (!checkBbr(currentThread)) {
            throw new SystemBlockException(resourceWrapper.getName(), "load");
        }
    }

    // 判断当前CPU使用率是否大于SystemRule规则配置的阈值,如果大于,则抛出BlockException异常
    if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
        throw new SystemBlockException(resourceWrapper.getName(), "cpu");
    }
}

// 使用BBR对负载进行校验
private static boolean checkBbr(int currentThread) {
    if (currentThread > 1 &&
        currentThread > Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) {
        return false;
    }
    return true;
}

上述有几个点需要说明

  1. BBR是什么?负载怎么获取的?
  2. Constants.ENTRY_NODE中的指标是什么存储进去的?
  3. CPU又是怎么获取的
BBR算法

BBR (Bottleneck Bandwidth and Round-trip propagation time) 是 Google 开发的一种拥塞控制算法,主要用于解决网络拥塞问题。下面我们将上面的代码进行拆解下:

  • 首先检查当前线程数是否大于 1,如果不是,则直接返回 true,表示通过 BBR 检查。
  • 如果当前线程数大于 1,那么检查当前线程数是否大于 (Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000)
    • maxSuccessQps() 是每秒最大成功请求数
    • minRt() 是最小响应时间
    • 如果当前线程数大于这个计算值,那么返回 false,表示未通过 BBR 检查。否则,返回 true

用通俗的语言解释:检查当前线程数是否大于(每秒最大成功请求数 * 最小响应时间 / 1000),如果大于这个值,说明系统可能出现拥塞,返回 false,否则返回 true

举个例子,假设 currentThread 为 5,maxSuccessQps() 为 10,minRt() 为 200。那么计算值为 (10 * 200) / 1000 = 2。因为 currentThread 大于计算值,所以返回 false,表示未通过 BBR 检查。

checkBbr 方法的目的是在系统负载较高的情况下,通过限制并行线程数来防止系统过载

Constants.ENTRY_NODE相关说明

其实Constants.ENTRY_NODE的指标其实就是在ClusterNode中统计的, 这个ClusterNode专门用户统计某资源在全部Context内的指标

public final static ClusterNode ENTRY_NODE = new ClusterNode(TOTAL_IN_RESOURCE_NAME, ResourceTypeConstants.COMMON);

ClusterNode最终也是通过StatisticSlot统计QPS、Thread、avgRt 这三个指标, 可以看到下边类图的继承关系
在这里插入图片描述

观察一下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 {
            // 其它代码...
            if (resourceWrapper.getEntryType() == EntryType.IN) {
                // 通过线程数
                Constants.ENTRY_NODE.increaseThreadNum();
                // QPS通过数
                Constants.ENTRY_NODE.addPassRequest(count);
            }
        } catch (PriorityWaitException ex) {
            // 其它代码...
            if (resourceWrapper.getEntryType() == EntryType.IN) {
                // 拒绝线程数
                Constants.ENTRY_NODE.increaseThreadNum();
            }

            if (resourceWrapper.getEntryType() == EntryType.IN) {
                // 拒绝QPS数
                Constants.ENTRY_NODE.increaseBlockQps(count);
            }
        }
    }


    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        // // 获取当前时间作为响应时间
        long completeStatTime = TimeUtil.currentTimeMillis();
        // rt(此次请求所耗费 的时间)= 响应时间 - 开始时间
        long rt = completeStatTime - context.getCurEntry().getCreateTimestamp();

        // 如果是请求类型是 IN
        if (resourceWrapper.getEntryType() == EntryType.IN) {
            // 则记录 rt 到 ClusterNode
            recordCompleteFor(Constants.ENTRY_NODE, count, rt, error);
        }
    }
}

可以看到上边代码判断流量类型为 EntryType.IN, 才调用 Constants.ENTRY_NODE相关的方法统计QPS、Thread、avgRt

补充说明, 记录的开始时间并不是在StatisticSlot的入口方法entry(), 而是初始化资源的时

因为StatisticSlot已经是责任链的第三个 Slot 了,前面已经经过一些Slot和其他逻辑

public Entry(ResourceWrapper resourceWrapper, int count, Object[] args) {
    this.resourceWrapper = resourceWrapper;
    // 记录开始时间
    this.createTimestamp = TimeUtil.currentTimeMillis();
    this.count = count;
    this.args = args;
}
CPU相关指标
获取

Java提供了与之对应的API供我们获取CPU指标, sentinel直接在这个基础上进行了封装, 代码位于com.alibaba.csp.sentinel.slots.system.SystemStatusListener#run, 这个工具类可以改造为我们所用

public class SystemStatusListener implements Runnable {

    volatile double currentLoad = -1;
    volatile double currentCpuUsage = -1;


    volatile long processCpuTime = 0;
    volatile long processUpTime = 0;

    /*
    通过JMX获取操作系统的系统负载、CPU使用率等指标信息,并计算当前进程的CPU使用率。如果系统负载超过预设阈值,则记录系统状态日志
    */
    @Override
    public void run() {
        try {
            // 获取操作系统的MXBean实例
            OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
            // 获取系统平均负载值
            currentLoad = osBean.getSystemLoadAverage();

          	// 获取系统CPU使用率, 0.0代表所有CPU完全空闲,1.0代表所有CPU一直在满负荷运行
            double systemCpuUsage = osBean.getSystemCpuLoad();

            
            RuntimeMXBean runtimeBean = ManagementFactory.getPlatformMXBean(RuntimeMXBean.class);
            // 获取当前进程的CPU时间(以纳秒为单位)
            long newProcessCpuTime = osBean.getProcessCpuTime();
            // 获取当前Java虚拟机的运行时间(以毫秒为单位)
            long newProcessUpTime = runtimeBean.getUptime();
            // 获取可用的CPU核心数量
            int cpuCores = osBean.getAvailableProcessors();
            
            // 计算前后两次采集之间进程CPU时间的差值,并转换成毫秒
            long processCpuTimeDiffInMs = TimeUnit.NANOSECONDS
                    .toMillis(newProcessCpuTime - processCpuTime);
            // 计算运行时间的差值
            long processUpTimeDiffInMs = newProcessUpTime - processUpTime;
            // 将CPU时间差除以运行时间差,然后除以可用CPU核心数。这样得到的结果是每个CPU核心上的平均进程CPU使用率
            double processCpuUsage = (double) processCpuTimeDiffInMs / processUpTimeDiffInMs / cpuCores;
            
            // 更新全局变量存储最新的进程CPU时间和运行时间,以便下一次循环计算时使用
            processCpuTime = newProcessCpuTime;
            processUpTime = newProcessUpTime;
			
            // 将计算得到的进程CPU使用率与系统CPU使用率进行比较,取较大者作为当前CPU使用率
            currentCpuUsage = Math.max(processCpuUsage, systemCpuUsage);
            // 如果当前系统负载(currentLoad)大于预先设定的阈值(SystemRuleManager
            if (currentLoad > SystemRuleManager.getSystemLoadThreshold()) {
                // 调用writeSystemStatusLog()方法,将系统过载信息写入日志中
                writeSystemStatusLog();
            }
        } catch (Throwable e) {
            RecordLog.warn("[SystemStatusListener] Failed to get system metrics from JMX", e);
        }
    }
}
获取频率
public final class SystemRuleManager {
    
    // 这种线程池的创建方式值的学习,因为使用了NamedThreadFactory,将线程池里的线程做到见名知意
    private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("sentinel-system-status-record-task", true));
    
    static {
        // 1s 执行一次
        scheduler.scheduleAtFixedRate(new SystemStatusListener(), 0, 1, TimeUnit.SECONDS);
    }
}

参考资料

通关 Sentinel 流量治理框架 - 编程界的小學生

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

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

相关文章

设计模式学习笔记 - 设计原则与思想总结:2.运用学过的设计原则和思想完善之前性能计数器项目

概述 在 《设计原则 - 10.实战&#xff1a;针对非业务的通用框架开发&#xff0c;如何做需求分析和设计及如何实现一个支持各种统计规则的性能计数器》中&#xff0c;我们讲解了如何对一个性能计数器框架进行分析、设计与实现&#xff0c;并且实践了一些设计原则和设计思想。当…

如何使用 ArcGIS Pro 生成TIN

三角网是一种常用于表示地表地形的数字地球模型&#xff08;DEM&#xff09;方式&#xff0c;我们可以通过 ArcGIS Pro 将等高线和高程点转换为TIN&#xff0c;这里为大家介绍一下转换方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的高…

vue2使用webSocket双向通讯

基于webSocket实现双向通信&#xff0c;使用webworker保持心跳。 由于浏览器的资源管理策略会暂停或限制某些资源的消耗&#xff0c;导致前端心跳包任务时效&#xff0c;后端接收不到webSocket心跳主动断开&#xff0c;因此需要使用webworker保持心跳 引入webworker npm insta…

CSDN 停更通知

CSDN 不再更新&#xff0c;欢迎关注我的微信公众号&#xff0c;分享更多有趣的技术内容。 如果大家有任何疑问&#xff0c;或者感兴趣的话题&#xff0c;都可以通过微信公众号与我交流&#xff0c;相互学习&#xff0c;相互成长。

Trent电源设计那些事儿教学

本课程将深入探讨Trent电源设计的关键概念与技术。学生将学习功率电子器件和拓扑、电路保护、稳压技术以及EMI滤波等内容。通过理论和实践相结合的教学方式&#xff0c;帮助学员掌握Trent电源设计的原理与应用。 课程大小&#xff1a;12.5G 课程下载&#xff1a;https://down…

2024年发布jar到国外maven中央仓库最新教程

2024年发布jar到国外maven中央仓库最新教程 文章目录 1.国外sonatype仓库的版本1.1老OSSHR账号注册说明1.2新账号注册说明 2.新账号注册(必选)3.新账号登录创建Namespace3.1创建Namespace的名字的格式要求&#xff08;必选&#xff09;3.2发布一个静态网站&#xff08;可选&…

科技云报道:第五次工业革命,中国AI企业如何打造新质生产力?

科技云报道原创。 人类历史的叙述与技术进步的影响深深交织在一起。 迄今为止&#xff0c;每一次工业革命都彻底改变了我们社会的轮廓&#xff0c;引入了机械化、大规模生产和数字化&#xff0c;并重新定义了人类生存的规范。 自2022年11月30日OpenAI发布ChatGPT以来&#x…

webpack5零基础入门-11处理html资源

1.目的 主要是为了自动引入打包后的js与css资源&#xff0c;避免手动引入 2.安装相关包 npm install --save-dev html-webpack-plugin 3.引入插件 const HtmlWebpackPlugin require(html-webpack-plugin); 4.添加插件&#xff08;通过new方法调用&#xff09; /**插件 *…

c语言,联合体

一.什么是联合体&#xff1a; 像结构体一样&#xff0c;联合体也是由一个或多个成员变量组成的这些成员变量可以是不同的类型&#xff0c;但编译器只给最大成员分配足够的内存&#xff0c;联合体体内的成员都是公用一块空间的&#xff0c;因此联合体也叫做共同体 二.联合体类…

聚类分析 | Matlab实现基于PCA+DBO+K-means的数据聚类可视化

聚类分析 | Matlab实现基于PCADBOK-means的数据聚类可视化 目录 聚类分析 | Matlab实现基于PCADBOK-means的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 PCA&#xff08;主成分分析&#xff09;、DBO&#xff08;蜣螂优化算法&#xff09;和K-means聚类…

【观察】紫光云:紫鸾5.0云平台“再升级”,为政企客户提供新质生产力

毫无疑问&#xff0c;数字化既是这个时代前进所趋&#xff0c;也是国家战略所指&#xff0c;更是所有企业在未来发展中已达成的高度共识。 在此过程中&#xff0c;千姿百态、复杂多样的应用场景&#xff0c;可以看做是遍布数字中国的“点”&#xff1b;百行百业、各种类型的行业…

阿里云发布 AI 编程助手 “通义灵码”——VSCode更强了 !!

文章目录 什么是 通义灵码&#xff08;TONGYI Lingma&#xff09; 快速体验“通义灵码” 什么是“通义灵码”&#xff08;TONGYI Lingma&#xff09; 通义灵码&#xff08;TONGYI Lingma&#xff09;&#xff0c;是阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff…

idea 开发serlvet班级通讯录管理系统idea开发mysql数据库web结构计算机java编程layUI框架开发

一、源码特点 idea开发 java servlet 班级通讯录管理系统是一套完善的web设计系统mysql数据库 系统采用serlvetdaobean mvc 模式开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 servlet 班…

【linux】Debian访问Debian上的共享目录

要在Debian系统上访问共享目录&#xff0c;通常意味着要访问通过网络共享的文件夹&#xff0c;比如通过SMB/CIFS&#xff08;Server Message Block/Common Internet File System&#xff09;协议共享的Windows共享文件夹。以下是访问共享目录的步骤&#xff1a; 1. 安装必要的…

边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 边缘设备图像识别及部署(二)

专栏目录 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 – 整体介绍&#xff08;一&#xff09; 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 -- 边缘图像识别及部署&#xff08;二&#xff09; 前言边缘图像识别与推流整体思路原始…

蓝桥杯刷题总结(Python组)

1、蛇形矩阵 解题思路&#xff1a;每次赋值后都对方向进行改变&#xff0c;一般上下左右就是&#xff08;-1&#xff0c;0&#xff09;&#xff0c;&#xff08;0&#xff0c;1&#xff09;&#xff0c;&#xff08;1&#xff0c;0&#xff09;&#xff0c;&#xff08;0&…

分布式事务的解决方案--Seata架构

一、Seata的XA模式 二、AT模式原理 三、TCC模式原理 四、MQ分布式事务 异步&#xff0c;非实时&#xff0c;实现最终的一致性。 四、分布式事务的解决方案

【MLLM+轻量多模态模型】24.02.Bunny-v1.0-2B-zh: 轻量级多模态语言模型 (效果一般)

24.02 北京人工智能研究院&#xff08;BAAI&#xff09;提出以数据为中心的轻量级多模态模型 arxiv论文&#xff1a;2402.Efficient Multimodal Learning from Data-centric Perspective 代码&#xff1a;https://github.com/BAAI-DCAI/Bunny 在线运行&#xff1a;https://wis…

CSS元素定位(学习笔记)

一、 z-index 1.1 作用 规定元素的堆叠顺序,取值越大&#xff0c;层级越往上 1.2 属性值 属性值为数字&#xff0c;可以取负值&#xff0c;不推荐 默认值&#xff1a;auto(跟父元素同一层级) 1.3 注意 必须配合定位(static除外)使用&#xff0c;默认情况下&#xff0c;后面的元…

openssl3.2 - exp - openssl speed test

文章目录 openssl3.2 - exp - openssl speed test概述笔记表面上能列出的算法集合没列出的算法, 有的也支持不支持的算法的例子直接提示算法不支持算法的属性找不到到底哪些算法才是可以测试的算法?那看看哪些算法是支持的?包含支持的算法的名称数组在算法失败的提示处, 将支…