当前位置: 首页 > news >正文

sentinel学习笔记6-限流降级(上)

本文属于sentinel学习笔记系列。网上看到吴就业老师的专栏,写的好值得推荐,我整理的有所删减,推荐看原文。

https://blog.csdn.net/baidu_28523317/category_10400605.html

sentinel 实现限流降级、熔断降级、黑白名单限流降级、系统自适应限流降级以及热点参数限流降级都是由 ProcessorSlot、Checker、Rule、RuleManager 组合完成。ProcessorSlot 作为调用链路的切入点,负责调用 Checker 检查当前请求是否可以放行;Checker 则根据资源名称从 RuleManager 中拿到为该资源配置的 Rule(规则),取 ClusterNode 统计的实时指标数据与规则对比,如果达到规则的阈值则抛出 Block 异常,抛出 Block 异常意味着请求被拒绝,也就实现了限流或熔断。

可以总结为以下三个步骤:

  1. 在 ProcessorSlot#entry 方法中调用 Checker#check 方法,并将 DefaultNode 传递给 Checker。
  2. Checker 从 DefaultNode 拿到 ClusterNode,并根据资源名称从 RuleManager 获取为该资源配置的规则。
  3. Checker 从 ClusterNode 中获取当前时间窗口的某项指标数据(QPS、avgRt 等)与规则的阈值对比,如果达到规则的阈值则抛出 Block 异常(也有可能将 check 交给 Rule 去实现)。

限流规则与规则配置加载器

rule

规则是围绕资源配置的,接口Rule 只定义获取资源。

public interface Rule {/*** Get target resource of this rule.** @return target resource of this rule*/String getResource();}
public abstract class AbstractRule implements Rule {/*** rule id. */private Long id;/*** Resource name. 资源名*/private String resource;/***  流控对应的调用来源*/private String limitApp;

Rule、AbstractRule 与其它实现类的关系如下图所示: 

FlowRule 是限流规则配置类,FlowRule 继承 AbstractRule 并实现 Rule 接口。FlowRule 源码如下 

public class FlowRule extends AbstractRule {public FlowRule() {super();setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);}public FlowRule(String resourceName) {super();setResource(resourceName);setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);}/*** The threshold type of flow control (0: thread count, 1: QPS).* 限流阈值类型*/private int grade = RuleConstant.FLOW_GRADE_QPS;/*** Flow control threshold count. 限流阈值 配置的是qps类型则代表qps的值;配置的是线程数类型则代表线程数*/private double count;/*** Flow control strategy based on invocation chain.* 流控限流策略* {@link RuleConstant#STRATEGY_DIRECT} for direct flow control (by origin);* {@link RuleConstant#STRATEGY_RELATE} for relevant flow control (with relevant resource);* {@link RuleConstant#STRATEGY_CHAIN} for chain flow control (by entrance resource).*/private int strategy = RuleConstant.STRATEGY_DIRECT;/*** Reference resource in flow control with relevant resource or context.* 关联流控的资源*/private String refResource;/*** Rate limiter control behavior.  流控效果控制* 0. default(reject directly), 1. warm up, 2. rate limiter, 3. warm up + rate limiter*/private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;//对应流控效果为Warm Up情况下,冷启动时长(预热时长),单位秒private int warmUpPeriodSec = 10;/*** Max queueing time in rate limiter behavior.* 对应流控效果为排队等待情况下,出现的超时时间*/private int maxQueueingTimeMs = 500;// 对应新增流控规则页面的是否集群private boolean clusterMode;/*** Flow rule config for cluster mode.集群流控的相关配置*/private ClusterFlowConfig clusterConfig;/*** The traffic shaping (throttling) controller.  流量整形的实现,不同流控效果有不同算法*/private TrafficShapingController controller;

字段属性有些多,可以对比sentinel 限流保护-笔记-CSDN博客 跟官网文档来理解

RuleManager

 Sentinel 中用来管理规则配置的类都以规则类的名称+Manger 命名,用来加载限流规则配置以及缓存限流规则配置的类为 FlowRuleManager,其部分源码如下:

public class FlowRuleManager {// 缓存限流规则private static volatile Map<String, List<FlowRule>> flowRules = new HashMap<>();// PropertyListener 监听器private static final FlowPropertyListener LISTENER = new FlowPropertyListener();//SentinelProperty ,默认的 DynamicSentinelPropertyprivate static SentinelProperty<List<FlowRule>> currentProperty = new DynamicSentinelProperty<List<FlowRule>>();/** the corePool size of SCHEDULER must be set at 1, so the two task ({@link #startMetricTimerListener()} can run orderly by the SCHEDULER **/@SuppressWarnings("PMD.ThreadPoolCreationRule")private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1,new NamedThreadFactory("sentinel-metrics-record-task", true));static {//给默认的 SentinelProperty 注册监听器(FlowPropertyListener)currentProperty.addListener(LISTENER);startMetricTimerListener();}。。。public static List<FlowRule> getRules() {List<FlowRule> rules = new ArrayList<FlowRule>();for (Map.Entry<String, List<FlowRule>> entry : flowRules.entrySet()) {rules.addAll(entry.getValue());}return rules;}//更新规则public static void loadRules(List<FlowRule> rules) {currentProperty.updateValue(rules);}

 我们之前demo对用FlowRuleManager.loadRules()来更新规则生效,注意1.8.6版本这里面

SentinelProperty ,SentinelProperty 是 Sentinel 提供的一个接口,可注册到 Sentinel 提供的各种规则的 Manager,例如 FlowRuleManager,并且可以给 SentinelProperty 添加监听器,在配置改变时,你可以调用 SentinelProperty#updateValue 方法,由它负责调用监听器去更新规则,而不需要调用 FlowRuleManager#loadRules 方法。这块先先不展开梳理,后面结合nacos再看。

限流处理器插槽:FlowSlot

FlowSlot 是实现限流功能的切入点,它作为 ProcessorSlot 插入到 ProcessorSlotChain 链表中,在 entry 方法中调用 Checker 去判断是否需要拒绝当前请求,如果需要拒绝请求则抛出 Block 异常。FlowSlot 的源码如下:

@Spi(order = Constants.ORDER_FLOW_SLOT)
public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {private final FlowRuleChecker checker;public FlowSlot() {this(new FlowRuleChecker());}/*** Package-private for test.** @param checker flow rule checker* @since 1.6.1*/FlowSlot(FlowRuleChecker checker) {AssertUtil.notNull(checker, "flow checker should not be null");this.checker = checker;}@Overridepublic void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,boolean prioritized, Object... args) throws Throwable {checkFlow(resourceWrapper, context, node, count, prioritized);fireEntry(context, resourceWrapper, node, count, prioritized, args);}//校验是否限流void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized)throws BlockException {checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);}@Overridepublic void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {fireExit(context, resourceWrapper, count, args);}// 规则生产者private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {@Override  // 参数为资源名称public Collection<FlowRule> apply(String resource) {// Flow rule map should not be null.Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();return flowRules.get(resource);}};
}

限流规则检查器:FlowRuleChecker

FlowRuleChecker 负责判断是否需要拒绝当前请求,方法很多,先看看调用checkFlow

public class FlowRuleChecker {public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {if (ruleProvider == null || resource == null) {return;}// 获取匹配的规则Collection<FlowRule> rules = ruleProvider.apply(resource.getName());if (rules != null) {//遍历规则for (FlowRule rule : rules) { // 检查规则能否通过if (!canPassCheck(rule, context, node, count, prioritized)) {throw new FlowException(rule.getLimitApp(), rule);}}}}

注意:遍历限流规则,只要有一个限流规则达到限流阈值即可抛出 FlowException,使用 FlowException 目的是标志当前请求因为达到限流阈值被拒绝,FlowException 是 BlockException 的子类;

canPassCheck 方法返回 true 说明允许请求通过,反之则不允许通过。canPassCheck 方法源码如下:

    public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,boolean prioritized) {String limitApp = rule.getLimitApp();//当前限流规则只对哪个调用来源生效,一般不为null,默认为“default”(不限定调用来源)if (limitApp == null) {return true;}// 集群模式下的规则检测if (rule.isClusterMode()) {return passClusterCheck(rule, context, node, acquireCount, prioritized);}//单机模式下规则检测return passLocalCheck(rule, context, node, acquireCount, prioritized);}

先不讨论集群限流的情况,看看单机的passLocalCheck

    private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount,boolean prioritized) {//根据调用来源和“调用关系限流策略”选择 DefaultNode;Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);if (selectedNode == null) {return true;}return rule.getRater().canPass(selectedNode, acquireCount, prioritized);}
  • selectNodeByRequesterAndStrategy返回ClusterBuilderSlot阶段生成的ClusterNode
  • getRater 返回TrafficShapingController,在默认模式下返回流控效果策略DefaultController。DefaultController#canPass 完成canPassCheck。

下面分别看看这两个方法。

流控节点选择

selectNodeByRequesterAndStrategy 方法的实现有多种情况。原码如下:

public class FlowRuleChecker {static Node selectNodeByRequesterAndStrategy(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node) {// The limit app should not be empty.限流规则针对哪个来源生效String limitApp = rule.getLimitApp();// 基于调用关系的限流策略int strategy = rule.getStrategy();// 远程来源String origin = context.getOrigin();if (limitApp.equals(origin) && filterOrigin(origin)) {if (strategy == RuleConstant.STRATEGY_DIRECT) {// 1 Matches limit origin, return origin statistic node.return context.getOriginNode();}//2return selectReferenceNode(rule, context, node);} else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {if (strategy == RuleConstant.STRATEGY_DIRECT) {//3 Return the cluster node.return node.getClusterNode();}//4return selectReferenceNode(rule, context, node);} else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)&& FlowRuleManager.isOtherOrigin(origin, rule.getResource())) {if (strategy == RuleConstant.STRATEGY_DIRECT) {// 5return context.getOriginNode();}//6return selectReferenceNode(rule, context, node);}return null;}static Node selectReferenceNode(FlowRule rule, Context context, DefaultNode node) {String refResource = rule.getRefResource();int strategy = rule.getStrategy();if (StringUtil.isEmpty(refResource)) {return null;}if (strategy == RuleConstant.STRATEGY_RELATE) {return ClusterBuilderSlot.getClusterNode(refResource);}if (strategy == RuleConstant.STRATEGY_CHAIN) {if (!refResource.equals(context.getName())) {return null;}return node;}// No node.return null;}

如果当前限流规则的 limitApp 为 default,则说明该限流规则对任何调用来源都生效,针对所有调用来源限流,否则只针对指定调用来源限流。

1 如果调用来源与当前限流规则的 limitApp 相等,且 strategy 为 STRATEGY_DIRECT,则使用调用来源的 StatisticNode,实现针对调用来源限流。

2 前置条件与(1)相同,依然是针对来源限流。selectReferenceNode

  • strategy 为 STRATEGY_RELATE:使用引用资源的 ClusterNode;
  • strategy 为 STRATEGY_CHAIN:使用当前资源的 DefauleNode。

3当 limitApp 为 default 时,针对所有来源限流。如果 strategy 为 STRATEGY_DIRECT,则使用当前资源的 ClusterNode。

4 前置条件与(3)相同,依然是针对所有来源限流。selectReferenceNode

5 如果 limitApp 为 other,且该资源的所有限流规则都没有针对当前的调用来源限流。如果 strategy 为 STRATEGY_DIRECT,则使用 origin 的 StatisticNode。

6  前置条件与(5)一样。selectReferenceNode

从 selectNodeByRequesterAndStrategy 方法可以看出,Sentinel 之所以针对每个资源统计访问来源的指标数据,也是为了实现对丰富的限流策略的支持.比如针对调用来源限流可限制并发量较高的来源服务的请求,而对并发量低的来源服务的请求可不限流,或者是对一些并没有那么重要的来源服务限流。

TrafficShapingController

Sentinel 支持对超出限流阈值的流量采取效果控制器控制这些流量,流量效果控制支持:直接拒绝、Warm Up(冷启动)、匀速排队。对应 FlowRule 中的 controlBehavior 字段。在调用 FlowRuleManager#loadRules 方法时,FlowRuleManager 会将限流规则配置的 controlBehavior 转为对应的 TrafficShapingController。

public interface TrafficShapingController {/*** Check whether given resource entry can pass with provided count.* 判断当前请求是否能通过* @param node resource node* @param acquireCount count to acquire* @param prioritized whether the request is prioritized* @return true if the resource entry can pass; false if it should be blocked*/boolean canPass(Node node, int acquireCount, boolean prioritized);/*** Check whether given resource entry can pass with provided count.* 判断当前请求是否能通过* @param node resource node* @param acquireCount count to acquire* @return true if the resource entry can pass; false if it should be blocked*/boolean canPass(Node node, int acquireCount);
}

DefaultController

DefaultController 是默认使用的流量效果控制器,直接拒绝超出阈值的请求。当 QPS 超过限流规则配置的阈值,新的请求就会被立即拒绝,抛出 FlowException。

  @Overridepublic boolean canPass(Node node, int acquireCount, boolean prioritized) {// 获取当前已使用的token:qps 算每秒被放行的请求数,threads 统计的当前并行占用的线程数int curCount = avgUsedTokens(node);//当前已使用token + 获取的token 大于token数量的场景if (curCount + acquireCount > count) {//qps 且prioritized 参数的值为 true(有优先级的请求可以占用未来时间窗口的统计指标)if (prioritized && grade == RuleConstant.FLOW_GRADE_QPS) {long currentTime;long waitInMs;currentTime = TimeUtil.currentTimeMillis();//当前请求需要等待的时间,单位毫秒waitInMs = node.tryOccupyNext(currentTime, acquireCount, count);if (waitInMs < OccupyTimeoutProperty.getOccupyTimeout()) {//将休眠之后对应的时间窗口的 pass(通过)这项指标数据的值加上 acquireCountnode.addWaitingRequest(currentTime + waitInMs, acquireCount);// 添加占用未来的 pass 指标的数量node.addOccupiedPass(acquireCount);// 休眠等待,当前线程阻塞sleep(waitInMs);// PriorityWaitException indicates that the request will pass after waiting for {@link @waitInMs}.//休眠结束后抛出 PriorityWait 异常,表示当前请求是等待了 waitInMs 之后通过的throw new PriorityWaitException(waitInMs);}}return false;}return true;}private int avgUsedTokens(Node node) {if (node == null) {return DEFAULT_AVG_USED_TOKENS;}return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)(node.passQps());}

 一般情况下,prioritized 参数的值为 false,所以这个 canPass 方法实现的流量效果就是直接拒绝。

限于篇幅,其他限流RateLimiterController、WarmUpController、WarmUpRateLimiterController 待整理。

相关文章:

sentinel学习笔记6-限流降级(上)

本文属于sentinel学习笔记系列。网上看到吴就业老师的专栏&#xff0c;写的好值得推荐&#xff0c;我整理的有所删减&#xff0c;推荐看原文。 https://blog.csdn.net/baidu_28523317/category_10400605.html sentinel 实现限流降级、熔断降级、黑白名单限流降级、系统自适应…...

【Rust自学】6.4. 简单的控制流-if let

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 6.4.1. 什么是if let if let语法允许将if和let组合成一种不太冗长的方式来处理与一种模式匹配的值&#xff0c;同时忽略其余模式。 可以…...

【HarmonyOS】鸿蒙将资源文件夹Resource-RawFile下的文件存放到沙箱目录下

【HarmonyOS】鸿蒙将资源文件夹Resource-RawFile下的文件存放到沙箱目录下 一、问题背景 应用开发中&#xff0c;我们经常会遇到一些文件原先是放在资源文件夹 rawfile下&#xff0c;但是逻辑处理时&#xff0c;需要转移到本地沙箱才能操作。这种情况下&#xff0c;就需要将将…...

Vue项目中env文件的作用和配置

在实际项目的开发中&#xff0c;我们一般会经历项目的开发阶段、测试阶段和最终上线阶段&#xff0c;每一个阶段对于项目代码的要求可能都不尽相同&#xff0c;那么我们如何能够游刃有余的在不同阶段下使我们的项目呈现不同的效果&#xff0c;使用不同的功能呢&#xff1f;这里…...

在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)

一、概述 记录时间 [2024-12-26] 本文讲述如何在 Vue3 项目中使用计时器组件。具体包括开发环境的配置&#xff0c;ViteVue 项目的创建&#xff0c;Element Plus 插件的使用&#xff0c;以及计时器组件的创建和使用。 想要直接实现计时器组件&#xff0c;查看文章的第四部分。…...

机器人C++开源库The Robotics Library (RL)使用手册(三)

进入VS工程,我们先看看这些功能函数及其依赖库的分布关系: rl命名空间下,主要有八大模块。 搞定VS后将逐个拆解。 1、编译运行 根据报错提示,配置相应错误的库(根据每个人安装位置不同而不同,我的路径如下:) 编译所有,Release版本耗时大约10分钟。 以rlPlan运动…...

Photoshop启动错误:找不到MSVCP140.dll的多步骤解决指南

在使用Adobe Photoshop&#xff08;简称PS&#xff09;进行创意设计或图像编辑时&#xff0c;有时会遇到软件启动报错的情况&#xff0c;其中“找不到MSVCP140.dll&#xff0c;无法继续执行代码”是一个常见的错误提示。这个错误通常意味着你的系统缺少了Microsoft Visual C Re…...

mac中idea菜单工具栏没有git图标了

1.右击菜单工具栏 2.选中VCS&#xff0c;点击添加 3.搜索你要的工具&#xff0c;选中点击确定就添加了 4.回到上面一个界面&#xff0c;选中你要放到工具栏的工具&#xff0c;点击应用就好了 5.修改图标&#xff0c;快捷键或者右击选中编辑图标 6.选择你要的图标就好了...

学习threejs,PerspectiveCamera透视相机和OrthographicCamera正交相机对比

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PerspectiveCamera透…...

C#数学相关开发性能优化方法

本文Github地址&#xff1a;CSharp-MathOptimization.md 华为公司的C语言编程规范在开头就强调了&#xff1a; 一般情况下&#xff0c;代码的可阅读性高于性能&#xff0c;只有确定性能是瓶颈时&#xff0c;才应该主动优化。 本文讲述的方法没有经过大项目和大公司的检验&…...

【前沿 热点 顶会】AAAI 2025中与目标检测有关的论文

CP-DETR: Concept Prompt Guide DETR Toward Stronger Universal Object Detection&#xff08;AAAI 2025&#xff09; 最近关于通用物体检测的研究旨在将语言引入最先进的闭集检测器&#xff0c;然后通过构建大规模&#xff08;文本区域&#xff09;数据集进行训练&#xff0…...

APP投放的归因框架设计

一、归因相关概念回顾 在广告归因简介中我们介绍常见的归因模型和归因方法&#xff0c;我们先来回顾一下&#xff1a; 1. 背景 2. 设备标识 3. 归因模型 归因模型的多样性意味着每种模型都有其独特的优势和局限。关键在于选择一个与您的业务场景相匹配的模型&#xff0c;并且…...

职业生涯记录-1

机缘 普通人改命,要学会向上社交,能自然融入的圈子,多数是往下社交,没有多少价值,想要获取更多资源,但是有钱人只跟有钱人交朋友,不会带我们普通人玩,又错了,有钱人身边最不缺的就是有钱人,他们缺的是对他们有利用价值的朋友,往上社交的关键,你必须是个对他有利用价…...

江苏捷科云:可视化平台助力制造企业智能化管理

公司简介 江苏捷科云信息科技有限公司&#xff08;以下简称“捷科”&#xff09;是一家专注于云平台、云储存、云管理等产品领域的创新型企业&#xff0c;集研发、生产和销售于一体&#xff0c;致力于在网络技术领域打造尖端品牌。在推动制造业企业数字化转型的进程中&#xf…...

【ES6复习笔记】Promise对象详解(12)

1. 什么是 Promise&#xff1f; Promise 是 JavaScript 中处理异步操作的一种机制&#xff0c;它可以让异步操作更加容易管理和控制。Promise 对象代表一个异步操作的最终完成或失败&#xff0c;并提供了一种方式来处理操作的结果。 2. Promise 的基本语法 Promise 对象有三…...

01 Oracle 基本操作

Oracle 基本操作 初使用步骤 1.创建表空间 2.创建用户、设置密码、指定表空间 3.给用户授权 4.切换用户登录 5.创建表 注意点&#xff1a;oracle中管理表的基本单位是用户 文章目录 了解Oracle体系结构 1.创建表空间**2.删除表空间**3.创建用户4.给用户授权5.切换用户登录6.表操…...

C语言基础:指针(数组指针与指针数组)

数组指针与指针数组 数组指针 概念&#xff1a;数组指针是指向数组的指针&#xff0c;本质上还是指针 特点&#xff1a; 先有数组&#xff0c;后有指针 它指向的是一个完整的数组 一维数组指针&#xff1a; 语法&#xff1a; 数据类型 (*指针变量名)[行容量][列容量]; 案…...

本地部署 LLaMA-Factory

本地部署 LLaMA-Factory 1. 本地部署 LLaMA-Factory2. 下载模型3. 微调模型3-1. 下载数据集3-2. 配置参数3-3. 启动微调3-4. 模型评估3-5. 模型对话 1. 本地部署 LLaMA-Factory 下载代码&#xff0c; git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Facto…...

Web前端基础知识(三)

表单的应用非常丰富&#xff0c;可以说&#xff0c;每个网站都会用到表单。下面首先介绍表单中的form标签。 --------------------------------------------------------------------------------------------------------------------------------- <form></form&g…...

数据库设计问题记录

唯一性约束和逻辑删除的冲突 问题描述 如果一张表中&#xff0c;存在唯一性约束&#xff0c;比如一些数据中的code&#xff0c;且数据表使用逻辑删除。当删除某行数据的时候&#xff0c;以后再次插入相同code的数据&#xff0c;数据库会报错。 问题分析 在逻辑删除中&#…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

《Offer来了:Java面试核心知识点精讲》大纲

文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...