Sentinel限流熔断机制实战

1、核心概念

1.1、流量控制

流量控制是为了 防止系统被过多的请求压垮,确保资源合理分配并保持服务的可用性,比如对请求数量的限制。

流量控制的 3 个主要优势:

  1. 防止过载:当瞬间涌入的请求量超出系统处理能力时,会导致资源枯竭,如 CPU和内存耗尽。流量控制通过限制系统能处理的请求数,确保不会发生过载。
  2. 避免雪崩效应:高负载下某个服务崩溃可能引发其他依赖服务的崩溃,形成连锁反应。流量控制可以有效预防这种连锁故障,避免系统雪崩。
  3. 优化用户体验:即便部分请求被拒绝或延迟处理,流量控制也能确保大部分用户的请求能够正常响应,避免全局响应时间过长的情况。

常见的实现流量控制方法有 2 种:

  1. 限流:通过固定窗口、令牌桶或漏桶等算法限制单位时间内的请求数量。
  2. 排队:当请求量超出处理能力时,部分请求进入等待队列,防止立即超载。

1.2、熔断机制

熔断机制的目的是 避免当下游服务发生异常时,整个系统继续耗费资源重复发起失败请求,从而防止连锁故障。

工作机制:

  1. 监控服务健康状态:系统会实时监控服务的调用情况,例如请求成功率、响应时间等,判断服务的健康状况。
  2. 进入熔断状态:当某个服务的错误率达到设定阈值(如响应时间过长或出错率过高)时,系统会激活熔断器,暂时停止对该服务的调用,避免消耗不必要的资源和让错误进一步扩散。
  3. 快速失败:在熔断状态下,系统不会再等待超时,而是直接返回失败响应,减少系统资源占用,并避免因长时间等待导致用户体验的恶化。(也可以降级处理)
  4. 熔断恢复机制:熔断并非永久状态。在一段时间后,熔断器会进入半开状态,允许少量请求测试服务的健康情况。如果恢复正常,熔断器将关闭,恢复正常服务调用;如果仍有问题,则继续保持熔断。

在这里插入图片描述

1.3、降级策略

降级的目的是在某个服务的响应能力下降、或该服务不可用时,提供简化版的功能或返回默认值作为 兜底,保持系统的部分功能可用,确保用户体验的连续性,避免系统频繁报错。

降级可以是手‏动配置,也可以根据系统负؜载自动触发。系统可能由于​多种原因(如高负载、外部‌依赖不可用等)触发降级,‏返回简化的响应或默认值。

降级机制的好处:

  1. 优雅地处理故障:在降级状态下,系统不会直接返回错误信息,而是提供一个替代方案。例如,某个数据查询服务不可用时,系统可以返回缓存数据,确保用户看到的是有效信息,而非错误页面。
  2. 降低服务压力:降级有助于减轻系统对非核心服务的依赖,确保核心功能的稳定运行。例如,当推荐系统或广告服务出现故障时,降级可以减少对这些服务的调用,保护系统的整体稳定性。

1.4、熔断和降级的区别

具体来说:

  1. 熔断是当服务健康状况恶化时,通过 切断调用 避免系统资源浪费或服务间故障扩散。
  2. 降级是在系统压力过大或某个服务不可用时,通过提供简化的替代方案 ,保持系统的可用性和用户体验。

2、需求分析

2.1、对单个接口整体限流

目的:控制对‏耗时较长的、经常访问的接؜口的请求频率,防止过多请​求导致系过载

限流规则:

  1. 策略:整个接口每秒钟不超过 10 次请求
  2. 阻塞操作:提示“系统压力过大,请耐心等待”

熔断规则:

  1. 熔断条件:如果接口异常率超过 10%,或者慢调用(响应时长 > 3 秒)的比例大于 20%,触发 60 秒熔断。
  2. 熔断操作:直接返回本地数据(缓存或空数据)

2.2、对单个 IP 访问单个接口限流

限流规则:

  1. 策略:每个 IP 地址每分钟允许查看题目列表的次数不能超过 60 次。
  2. 阻塞操作:提示“访问过于频繁,请稍后再试”

熔断规则:

  1. 熔断条件:如果接口异常率超过 10%,或者慢调用(响应时长 > 3 秒)的比例大于 20%,触发 60 秒熔断。
  2. 熔断操作:直接返回本地数据(缓存或空数据)

3、Sentinel 介绍

Sentinel是阿里巴巴开源的限流、熔断、降级组件,旨在为分布式系统提供可靠的保护机制。它设计用于解决高并发流量下的稳定性问题,并且支持与 Dubbo、Spring Cloud 等多种框架集成。

详细内容可查看 -> 官方文档

它的功能:

  1. 限流:支持基于 QPS、并发数量等条件的限流,支持滑动窗口、预热、漏桶等算法。
  2. 熔断降级:支持失败率、慢调用比例等指标触发熔断,并提供自动恢复机制。
  3. 热点参数限流:可以基于特定的参数进行限流,如限制特定用户 ID 的请求频率。
  4. 系统负载保护:可以根据系统的实际负载(如 CPU、内存)动态调整流量。
  5. 丰富的规则配置:通过配置中心或控制台动态调整限流和熔断规则。

优势:功能‏丰富、提供控制台、؜更新较频繁、社区活​跃、文档清晰,能够‌快速入门上手。

3.1、使用方式

使用 Sentinel 来进行资源保护,主要分为几个步骤:

  1. 定义资源
  2. 定义规则
  3. 检验规则是否生效

3.2、架构设计

在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:

3.2.1、NodeSelectorSlot

NodeSelectorSlot 的本质作用:Sentinel 是通过一条一条资源“链路”来判断是否限流/降级的,而 它 就是用来维护这些资源链路的结构树。

具体干这几件事:

1、把资源“挂”到调用上下文树上
比如你访问 nodeA,它就会:

  • 看你当前上下文是哪个入口(entrance1)
  • 在 entrance1 节点下面查:有没有挂过 nodeA
  • 没有就新建一个 DefaultNode(nodeA),挂上去!

2、同一个资源,但不同入口,树结构是独立的!

ContextUtil.enter("entrance1", "appA");
SphU.entry("nodeA"); // 第一次
ContextUtil.exit();ContextUtil.enter("entrance2", "appA");
SphU.entry("nodeA"); // 第二次
ContextUtil.exit();

这相当于你从 两个不同入口玩了同一个关卡,Sentinel 会建立两条路径记录:

machine-root├── EntranceNode(entrance1)│       └── DefaultNode(nodeA)└── EntranceNode(entrance2)└── DefaultNode(nodeA)

为什么这么设计?
因为在真实业务中:

  • 你可能有多个入口(比如首页、搜索页都能访问同一个资源)
  • 你想控制每条链路的 QPS(比如“从搜索页过来的 QPS 限制更严格”)

所以 Sentinel 就必须要分得清:

“你是从哪儿来的,然后才访问的这个资源”

3.2.2、ClusterBuilderSlot

ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;

ClusterBuilderSlot 的作用
1、调用方级别限流!

  • 比如限制 “微信小程序” 每秒最多访问 100 次,其他 origin 不受影响。

2、监控更细粒度!

  • 哪个来源调用最多?
  • 哪个来源的调用最慢、最容易出错?

比如:是不是 Web 前端的调用出异常多,是不是他们传参老有问题?

配合热点参数限流、来源限流做更精细的控制。

3.3.3、StatisticSlot

StatisticSlot 是 Sentinel 的核心功能插槽之一,用于统计实时的调用数据。

  • clusterNode:资源唯一标识的 ClusterNode 的 runtime 统计
  • origin:根据来自不同调用者的统计信息
  • defaultnode: 根据上下文条目名称和资源 ID 的 runtime 统计入口的统计

Sentinel 底层采用高性能的滑动窗口数据结构 LeapArray 来统计实时的秒级指标数据,可以很好地支撑写多于读的高并发场景。

3.3.4、LeapArray底层原理

LeapArray 底层是一个固定长度的环形数组,每个元素是一个带有时间戳的窗口格子 WindowWrap。
它支持在高并发场景下以时间为索引安全读写,保证统计的是“最近一段时间”的窗口数据,用于 Sentinel 的实时监控与限流、降级判断。

结构总览:

public class LeapArray<T> {protected final int sampleCount; // 窗口格子数,比如10protected final int intervalInMs; // 窗口总时长,比如1000ms(1s)private final WindowWrap<T>[] array; // 固定长度数组,环形复用
}

每个窗口格子是这样一个类:

public class WindowWrap<T> {private final long windowStart; // 窗口开始时间private final long windowLength; // 每个格子的长度(interval / sampleCount)private final T value; // 存放统计信息的对象,比如 MetricBucket
}

它是怎么定位时间属于哪个窗口的?

比如:

总窗口时间是 1000ms,格子数是 10

每个格子负责 100ms

现在时间是 10:00:01.450(即 1450ms)

① 算出这个时间属于哪个格子:

int idx = (timestamp / windowLength) % sampleCount;
// 1450 / 100 = 14 -> 14 % 10 = 4,落在索引为4的格子

② 再判断这个格子的起始时间是不是还有效:

//当前时间戳 ➜ 除以窗口长度 ➜ 计算出当前时间该落在哪个格子 ➜ 比较该格子的起始时间 
//➜ 如果不同 ➜ 就滑窗、清理、重建!
window.windowStart == timestamp - (timestamp % windowLength)

如果有效:直接返回当前格子

如果无效(已经过期了):用 CAS 创建一个新的 WindowWrap(复用原来的槽位)

3.3.4.1、它是怎么滑动更新的?

核心点:每次请求到来时,才会“懒更新”窗口格子

流程如下:

1、当前时间戳算出对应窗口索引(如上)

2、取出格子对象,检查是否是当前时间的窗口

  • 是:直接用
  • 否:CAS 替换为新窗口 + 清空旧统计值(滑动来了)

3、更新格子里的统计数据

它并不需要定时器或后台线程维护窗口,而是靠访问触发滑动,非常节省资源。

3.3.4.2、并发怎么处理?

多线程访问时可能并发写同一个窗口:

  • 用的是 AtomicReferenceArray + Compare-And-Swap (CAS)
  • 每个格子内部统计信息用 LongAdder 等并发友好结构
3.3.4.3、总结:

LeapArray 是一个时间轮+懒更新+CAS构建的滑动窗口数组,专为高并发下限流降级而生。

3.3.5、FlowSlot

这个 slot 主要根据预设的资源的统计信息,按照固定的次序,依次生效。如果一个资源对应两条或者多条流控规则,则会根据如下次序依次检验,直到全部通过或者有一个规则生效为止:

  1. 指定应用生效的规则,即针对调用方限流的;
  2. 调用方为 other 的规则;
  3. 调用方为 default 的规则。

3.3.6、DegradeSlot

这个 slot 主要针对资源的平均响应时间(RT)以及异常比率,来决定资源是否在接下来的时间被自动熔断掉。
在这里插入图片描述

4、代码实战

4.1、查看题库列表接口限流熔断

 /*** 分页获取题库列表(封装类)** @param questionBankQueryRequest* @param request* @return*/@PostMapping("/list/page/vo")@SentinelResource(value = "listQuestionBankVOByPage",blockHandler = "handleBlockException",fallback = "handleFallback")public BaseResponse<Page<QuestionBankVO>> listQuestionBankVOByPage(@RequestBody QuestionBankQueryRequest questionBankQueryRequest,HttpServletRequest request) {long current = questionBankQueryRequest.getCurrent();long size = questionBankQueryRequest.getPageSize();// 限制爬虫ThrowUtils.throwIf(size > 200, ErrorCode.PARAMS_ERROR);// 查询数据库Page<QuestionBank> questionBankPage = questionBankService.page(new Page<>(current, size),questionBankService.getQueryWrapper(questionBankQueryRequest));// 获取封装类return ResultUtils.success(questionBankService.getQuestionBankVOPage(questionBankPage, request));}

熔断降级操作,处理 异常 / 熔断场景下的兜底逻辑,避免用户看到系统崩溃。

 /*** listQuestionBankVOByPage 降级操作:直接返回本地数据*/public BaseResponse<Page<QuestionBankVO>> handleFallback(@RequestBody QuestionBankQueryRequest questionBankQueryRequest,HttpServletRequest request, Throwable ex) {// 可以返回本地数据或空数据return ResultUtils.success(null);}

限流操作

/*** listQuestionBankVOByPage 流控操作* 限流:提示“系统压力过大,请耐心等待”* 熔断:执行降级操作*/public BaseResponse<Page<QuestionBankVO>> handleBlockException(@RequestBody QuestionBankQueryRequest questionBankQueryRequest,HttpServletRequest request, BlockException ex) {// 降级操作if (ex instanceof DegradeException) {return handleFallback(questionBankQueryRequest, request, ex);}// 限流操作return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统压力过大,请耐心等待");}

小Tips💡:为什么需要专门写降级操作判断?

// 降级操作if (ex instanceof DegradeException) {return handleFallback(questionBankQueryRequest, request, ex);}

Sentinel 中“熔断触发”其实本质上也是一种“被限流”行为,会先走 blockHandler,而不是直接走 fallback。

具体来说

情况触发逻辑进入哪个方法?
QPS 超限Sentinel 流控规则blockHandler()
异常率 > 50% 熔断开启Sentinel 熔断规则也进入 blockHandler()
方法内空指针等异常Java 抛异常fallback()

这时候你在 blockHandler() 里接收到的是 BlockException,它可能是:

  • FlowException(QPS 控制)
  • DegradeException(熔断控制)
  • ParamFlowException(热点参数)
  • AuthorityException(授权规则)
  • SystemBlockException(系统保护)

你得根据 ex instanceof DegradeException 去区分熔断的 case。

总结: 虽然 Sentinel 有 fallback 专门处理 异常 / 熔断,但 在触发熔断时默认走的是 blockHandler,你必须自己判断 ex 类型来决定要不要转交给 fallback 处理。也可以理解为:只有业务‏异常(比如请求参数错误、或؜者数据库操作失败等问题),​才会算到熔断条件中,限流熔‌断本身的异常 BlockE‏xception 是不计算的

4.2、单 IP 查看题目列表限流熔断

对于这个需求,需要对每个用户进一步精细化限流,而不是整体接口限流,可以采用 热点参数限流机制,允许根据参数控制限流触发条件,例如:将 IP 地址作为热点参数。
在这里插入图片描述
代码如下:

/*** 分页获取题目列表(封装类) - 限流版** @param questionQueryRequest* @param request* @return*/@PostMapping("/list/page/vo/sentinel")public BaseResponse<Page<QuestionVO>> listQuestionVOByPageSentinel(@RequestBody QuestionQueryRequest questionQueryRequest,HttpServletRequest request) {long current = questionQueryRequest.getCurrent();long size = questionQueryRequest.getPageSize();// 限制爬虫ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);// 基于 IP 限流String remoteAddr = request.getRemoteAddr();Entry entry = null;try  {entry = SphU.entry("listQuestionVOByPage", EntryType.IN, 1, remoteAddr);// 被保护的业务逻辑// 查询数据库Page<Question> questionPage = questionService.listQuestionByPage(questionQueryRequest);// 获取封装类return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));} catch (Throwable t) {// 自定义业务异常if (!BlockException.isBlockException(t)) {Tracer.trace(t);return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统异常");}// 资源访问阻止,被限流或被降级if (t instanceof DegradeException) {return handleFallback(questionQueryRequest, request, t);}// 限流操作return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "访问过于频繁,请稍后再试");} finally {if (entry != null) {entry.exit(1, remoteAddr);}}}/*** listQuestionVOByPageSentinel 降级操作:直接返回本地数据*/public BaseResponse<Page<QuestionVO>> handleFallback(@RequestBody QuestionQueryRequest questionQueryRequest,HttpServletRequest request, Throwable ex) {// 可以返回本地数据或空数据return ResultUtils.success(null);}

String remoteAddr = request.getRemoteAddr() 参数 remoteAddr 的作用是获取用户 IP,作为限流参数维度,防止一个 IP 乱刷。

entry = SphU.entry("listQuestionVOByPage", EntryType.IN, 1, remoteAddr) 作用是将 listQuestionVOByPage 作为资源注册到 Sentinel 的上下文中,开始对该资源进行限流、熔断、热点参数等规则的监控与统计。

异常处理判断逻辑:

情况处理方式
不是 Sentinel 异常(业务异常、系统异常)打点上报(Tracer.trace(t)),提示“系统异常”
是 Sentinel 熔断异常(DegradeException走自定义的降级处理逻辑:handleFallback
是 Sentinel 限流异常(FlowException 等)返回:“访问过于频繁,请稍后再试”

重点💡

1、若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)),否则可能会有统计错误。

2、SphU.entry(xxx) 需要与 entry.exit() 方法成对出现,匹配调用,否则会导致调用链记录异常,抛出 ErrorEntryFreeException 异常。

3、注意 Sentinel 的降级仅针对业务异常,对 Sentinel 限流降级本身的异常 BlockException 不生效。为了统计异常比例或异常数,需要手动通过 Tracer.trace(ex) 记录业务异常。

4.3、定义规则

新建 sentinel 包并定义一个单独的 Manager 作为 Bean,利用 @PostConstruct 注解,在 Bean 加载后创建规则。

@Component
public class SentinelRulesManager {@PostConstructpublic void initRules() throws Exception {initFlowRules();initDegradeRules();}// 限流规则public void initFlowRules() {// 单 IP 查看题目列表限流规则ParamFlowRule rule = new ParamFlowRule("listQuestionVOByPage").setParamIdx(0) // 对第 0 个参数限流,即 IP 地址.setCount(60) // 每分钟最多 60 次.setDurationInSec(60); // 规则的统计周期为 60 秒ParamFlowRuleManager.loadRules(Collections.singletonList(rule));}// 降级规则public void initDegradeRules() {// 单 IP 查看题目列表熔断规则DegradeRule slowCallRule = new DegradeRule("listQuestionVOByPage").setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()).setCount(0.2) // 慢调用比例大于 20%.setTimeWindow(60) // 熔断持续时间 60 秒.setStatIntervalMs(30 * 1000) // 统计时长 30 秒.setMinRequestAmount(10) // 最小请求数.setSlowRatioThreshold(3); // 响应时间超过 3 秒DegradeRule errorRateRule = new DegradeRule("listQuestionVOByPage").setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()).setCount(0.1) // 异常率大于 10%.setTimeWindow(60) // 熔断持续时间 60 秒.setStatIntervalMs(30 * 1000) // 统计时长 30 秒.setMinRequestAmount(10); // 最小请求数// 加载规则DegradeRuleManager.loadRules(Arrays.asList(slowCallRule, errorRateRule));}
}

本地化配置,让 Sentinel 的限流和降级规则支持本地文件持久化(可读可写)

/*** 持久化配置为本地文件*/
public void listenRules() throws Exception {//获取项目根目录并创建 sentinel/ 文件夹String rootPath = System.getProperty("user.dir");File sentinelDir = new File(rootPath, "sentinel");if (!FileUtil.exist(sentinelDir)) {FileUtil.mkdir(sentinelDir);}// 设置规则文件路径String flowRulePath = new File(sentinelDir, "FlowRule.json").getAbsolutePath();String degradeRulePath = new File(sentinelDir, "DegradeRule.json").getAbsolutePath();// 初始化 限流规则读取器(拉模式)ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);FlowRuleManager.register2Property(flowRuleDataSource.getProperty());//注册 限流规则写入器WritableDataSource<List<FlowRule>> flowWds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);WritableDataSourceRegistry.registerFlowDataSource(flowWds);// 降级规则读取器FileRefreshableDataSource<List<DegradeRule>> degradeRuleDataSource= new FileRefreshableDataSource<>(degradeRulePath, degradeRuleListParser);DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());WritableDataSource<List<DegradeRule>> degradeWds = new FileWritableDataSource<>(degradeRulePath, this::encodeJson);// Register to writable data source registry so that rules can be updated to fileWritableDataSourceRegistry.registerDegradeDataSource(degradeWds);
}//JSON字符串 -> 规则对象
private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<FlowRule>>() {});
private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<DegradeRule>>() {});// 规则对象 -> JSON字符串
private <T> String encodeJson(T t) {return JSON.toJSONString(t);
}

注意:在初始化时加入 listenRules()方法

 @PostConstructpublic void initRules() throws Exception {initFlowRules();initDegradeRules();listenRules();}

5、总结

Sentinel 的规则配置 + 接口中的限流/熔断操作 的联动协同

5.1、规则配置部分(限流 & 熔断)

①在内存中加载规则(程序启动时)

如对 listQuestionVOByPage 添加:

  • 限流:每个 IP 每分钟访问不超 60 次
  • 熔断:慢调用比例超 20%,触发熔断;异常率超 10%,也触发熔断

②文件持久化监听

调用 listenRules() 做两件事:监听本地文件变化,自动刷新配置

将规则写回文件(支持动态修改)

5.2、接口限流/熔断的具体操作(怎么用规则)

①注解方式(简洁明了)

具体来说:

应规则名就是 value 指定的 “listQuestionBankVOByPage”:

  • 如果被限流了 ➜ 走 handleBlockException()
  • 如果被熔断了 ➜ 也会走 handleBlockException(),但你可以判断异常类型 DegradeException
  • 如果业务异常了(比如系统异常)➜ 走 handleFallback()

②编程方式(可扩展性强)

entry = SphU.entry("listQuestionVOByPage", EntryType.IN, 1, remoteAddr);
  1. 参数 remoteAddr 作为限流 key(这是为了实现 ParamFlowRule)
  2. try-catch 中写核心业务逻辑
  3. catch 中判断是否是限流/熔断异常:

对于 对单个接口整体限流 我们使用 @SentinelResource 注解方式 做限流操作,这时注解会监控所有参数。

对于 单个IP查看题目列表限流熔断 用 编程式 做限流操作,是因为我们只需要对 用户IP 这一个参数监控,不需要对传入的所有参数做监控。

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

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

相关文章

深度解析 torch.mean 的替代方案

torch.mean 是什么意思 代码效果解释 segment_vector = torch.mean(segment_embedding, dim=1) # [1, hidden_dim] 这行代码的作用是在指定维度上对张量 segment_embedding 求平均值,实现类似平均池化的效果。 具体来说,dim=1 表示沿着索引为1的维度进行操作。假设 segment…

Paraformer语音模型:一种语音模型加速方法

随着智能语音技术的普及&#xff0c;语音识别&#xff08;ASR&#xff09;、语音合成&#xff08;TTS&#xff09;、声纹识别等应用场景对模型推理效率提出了极高要求&#xff0c;本文介绍将Paraformer语音模型从预训练模型导出为ONNX格式&#xff0c;并使用ONNX Runtime进行推…

本地部署FreeGPT+内网穿透公网远程访问,搞定ChatGPT外网访问难题

‌FreeGPT‌是一个基于GPT 3.5/4的ChatGPT聊天网页用户界面&#xff0c;提供了一个开放的聊天界面&#xff0c;开箱即用‌。ChatGPT是非常热门的&#xff0c;但访问体验一直不太理想。为了解决这一问题&#xff0c;出现了各类方法和工具&#xff0c;其中FreeGPT是一款非常实用的…

ElasticSearch迁移至openGauss

Elasticsearch 作为一种高效的全文搜索引擎&#xff0c;广泛应用于实时搜索、日志分析等场景。而 openGauss&#xff0c;作为一款企业级关系型数据库&#xff0c;强调事务处理与数据一致性。那么&#xff0c;当这两者的应用场景和技术架构发生交集时&#xff0c;如何实现它们之…

品优购项目(HTML\CSS)

项目效果可访问 http://zhousunyu.3vdo.club 查看 主页 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

因泰立科技:镭眸T51激光雷达,打造智能门控新生态

在高端门控行业&#xff0c;安全与效率是永恒的追求。如今&#xff0c;随着科技的飞速发展&#xff0c;激光雷达与TOF相机技术的融合&#xff0c;为门控系统带来了前所未有的智能感知能力&#xff0c;开启了精准守护的新时代。因泰立科技的镭眸T51激光雷达&#xff0c;作为这一…

MyBatisPlus--快速入门

MyBatisPlus介绍 从名字中就可以感觉到MybatisPlus与MyBatis之间的渊源&#xff0c;而MyBatis是一个非常流行的持久层框架&#xff0c;主要来做数据库的增删改查&#xff0c;而MyBatisPlus这种命名方式让人不得不往MyBatis的升级版去联想&#xff0c;事实也确实如此&#xff0…

redis持久化策略

RDB 是通过生成数据快照来实现持久化的&#xff0c;相当于给内存中的数据拍一张"照片"保存到磁盘上。AOF 记录所有写操作命令&#xff0c;以Redis协议格式追加到文件末尾。 RDB 在满足特定条件时触发内存快照&#xff0c;生成新的RDB文件替换旧文件 AOF 先写入内…

Spring Boot中使用@JsonAnyGetter和@JsonAnySetter处理动态JSON属性

Spring Boot 中使用 @JsonAnyGetter 和 @JsonAnySetter 处理动态 JSON 属性 在实际的后端开发中,尤其是使用 Spring Boot 构建 API 时,我们经常会遇到需要处理动态 JSON 属性的场景。例如,前端传递过来的 JSON 数据结构不固定,或者业务需求变更频繁,导致实体类无法预先定…

拉取gitlab项目

一、下载nvm管理node 先下载配置好nvm,再用nvm下载node 下载链接&#xff1a;开始 下载nvm - nvm中文官网 情况&#xff1a;npm i 下载依赖缓慢&#xff0c;可能是node版本不对&#xff0c;可能node版本太高 可能得问题&#xff1a;使用nvm 下载低版本的node时&#xff0c;…

【解决办法】ubuntu重启不起来,输入用户名和密码进不去,又重新返回登录页。

项目场景&#xff1a; ubuntu重启不起来&#xff0c;输入用户名和密码进不去&#xff0c;又重新返回登录页。 问题描述 在华硕天选一代笔记本上面安装了ubuntu22.04.5桌面版&#xff0c;但是重启以后出现&#xff0c;输入了用户名和密码&#xff0c;等待一会还让输入用户名和…

# 云端大模型:智能时代的新引擎

云端大模型&#xff1a;智能时代的新引擎 在人工智能技术的迅猛发展中&#xff0c;云端大模型扮演着至关重要的角色。它们不仅推动了技术的边界&#xff0c;也为各行各业带来了前所未有的机遇。本文将结合一系列图片和代码示例&#xff0c;深入探讨云端大模型的功能、应用及其…

(1)pytest简介和环境准备

1. pytest简介 pytest是python的一种单元测试框架&#xff0c;与python自带的unittest测试框架类似&#xff0c;但是比unittest框架使用起来更简洁&#xff0c;效率更高。根据pytest的官方网站介绍&#xff0c;它具有如下特点&#xff1a; 非常容易上手&#xff0c;入门简单&a…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.5 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.5 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用图。 dataframe <-data.frame( wrapc(17,20,12,9,…

线程池的详细知识(含有工厂模式)

前言 下午学习了线程池的知识。重点探究了ThreadPoolExecutor里面的各种参数的含义。我详细了解了这部分的知识。其中有一个参数涉及工厂模式&#xff0c;我将这一部分知识分享给大家~ 线程池的详细介绍(含工厂模式) 结语 分享到此结束啦。byebye~

嵌入式开发学习(第二阶段 C语言笔记)

内存操作 我们对于内存操作需要依赖于string.h头文件中相关的函数库。 内存操作函数 内存填充 头文件&#xff1a;#include <string.h> 函数原型&#xff1a; void* memset(void *s,int c,size_t n)函数功能&#xff1a;将内存块s的前n个字节填充为c&#xff0c;一般…

C++学习-入门到精通【9】面向对象编程:继承

C学习-入门到精通【9】面向对象编程&#xff1a;继承 目录 C学习-入门到精通【9】面向对象编程&#xff1a;继承一、基类与派生类CommunityMember类的继承层次结构如何定义一个派生类呢 二、基类和派生类间的关系1.创建并使用类CommissionEmployee2.不使用继承创建类BasePlusCo…

黑马k8s(十七)

一&#xff1a;高级存储 1.高级存储-pv和pvc介绍 2.高级存储-pv 3.高级存储-pvc 最后一个改成5gi pvc3是没有来绑定成功的 pv3没有绑定 删除pod、和pvc&#xff0c;观察状态&#xff1a; 4.高级存储-pc和pvc的生命周期 二&#xff1a;配置存储 1.配置存储-ConfigMap 2.配…

cf每日刷题c++

目录 Simple Repetition&#xff08;1000&#xff09; Fashionable Array&#xff08;800&#xff09; Kevin and Arithmetic(800) Permutation Warm-Up(800) Game of Mathletes(900) LRC and VIP(800) Simple Repetition&#xff08;1000&#xff09; https://codeforc…

历年中国科学技术大学计算机保研上机真题

2025中国科学技术大学计算机保研上机真题 2024中国科学技术大学计算机保研上机真题 2023中国科学技术大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school?classification1 拆分数字 题目描述 给定一个数字&#xff0c;拆分成若干个数字之和&#xff…