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

【SpringCloud详细教程】-04-服务容错--Sentinel

 精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482

02. 《SpringBoot详细教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482

03.《SpringBoot电脑商城项目》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482

04.《VUE3.0 核心教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482

05. 《SSM详细教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12806942.html?spm=1001.2014.3001.5482

================================

||        持续分享系列教程,关注一下不迷路     ||

||                B站视频教程:墨轩大楼               ||

||                知识星球:墨轩编程自习室           ||

================================

🌲 4.1 高并发带来的问题

在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。

接下来,我们来模拟一个高并发的场景

新增一个OrderController2,在这个Controller中模拟一个网络延时的情况

package com.moxuan.shoporder.controller;import com.alibaba.fastjson.JSON;
import com.moxuan.shopcommon.entity.Order;
import com.moxuan.shopcommon.entity.Product;
import com.moxuan.shopcommon.util.Result;
import com.moxuan.shoporder.service.OrderService;
import com.moxuan.shoporder.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class OrderController2 {Logger log = LoggerFactory.getLogger(OrderController2.class);@Autowiredprivate OrderService orderService;@Autowiredprivate ProductService productService;@GetMapping("/order/prod1/{pid}")public Result order(@PathVariable("pid")Integer pid){log.info(">> 客户下单,这时候要调用商品微服务查询商品信息");//2.使用了Ribbon+Fegin 负载均衡访问Result result = productService.findProductByPid(pid);//通过restTemplate调用尚敏的微服务log.info("商品信息>> 查询结果"+result.getData());// 模拟网络延时try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}Product pro = JSON.parseObject(result.getData().toString(),Product.class);System.out.println(pro);Order order = new Order();order.setUid(1);order.setUsername("墨轩");order.setPid(pro.getPid());order.setPname(pro.getPname());order.setPprice(pro.getPprice());order.setNum(1);result = orderService.saveOrder(order);return result;}@RequestMapping("/order/message")public String message() {return "高并发下的问题测试";}}

接着修改配置文件中的tomcat的并发数,tomcat的默认并发数是200,我们调小一点:

# 并发数调整成10,默认是200
server.tomcat.threads.max=10

接下来用压力测试工具进行压力测试:

下载地址:https://jmeter.apache.org/

  • 第一步:修改配置,并启动软件

进入bin目录,修改jemeter.properties文件中的语言支持为language=zh-CN,修改好后点击jemeter.bat运行程序。

  • 第二步:添加线程组

  • 第三步:配置线程并发数

  • 第四步:添加Http取样

  • 第五步:配置取样,启动测试

启动后访问order/message ,此时会发现,由于Order方法囤积了大量的请求,导致message此时访问出现了问题,这就是雪崩的雏形。

🌲 4.2 服务雪崩效应

在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。

由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应”

雪崩发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问题,不会影响到其它服务的正常运行。也就是"雪落而不雪崩"。

🌲 4.3 常见容错方案

要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。

常见的容错思路

常见的容错思路有隔离、超时、限流、熔断、降级这几种,下面分别介绍一下。

🌿 4.3.1 隔离

它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。常见的隔离方式有:线程池隔离和信号量隔离.

  • 模块与模块之间没有强依赖
  • 当C出现问题时,问题隔离在了C,不会扩散

🌿 4.3.2 超时

在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程.

🌿 4.3.3 限流

限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

限流比较好理解,比如:医院放号挂号,每个医生只处理对应数量的病人。

🌲 4.3.4 熔断

在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断一般有三种状态:

  • 熔断关闭状态(Closed)

服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制

  • 熔断开启状态(Open)

后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法

  • 半熔断状态(Half-Open)

尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态.

🌿 4.3.5 降级

降级其实就是为服务提供一个托底方案,一旦服务无法正常调用,就使用托底方案。

🌲 4.4 常见容错软件

🌿 4.4.1 软件介绍

🍁 Hystrix

Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。

🍁 Resilience4J

Resilicence4J一款非常轻量、简单,并且文档非常清晰、丰富的熔断工具,这也是Hystrix官方推荐的替代产品。不仅如此,Resilicence4j还原生支持Spring Boot 1.x/2.x,而且监控也支持和prometheus等多款主流产品进行整合。

🍁 Sentinel

Sentinel 是阿里巴巴开源的一款断路器实现,本身在阿里内部已经被大规模采用,非常稳定。下面是三个组件在各方面的对比:

Sentinel

Hystrix

Resilience4J

隔离策略

信号量隔离(并发线程数限流)

线程池隔离/信号量隔离

信号量隔离

熔断降级策略

基于响应时间、异常比率、异常数

基于异常比率

基于异常比率、响应时间

实时统计实现

滑动窗口(LeapArray)

滑动窗口(基于 RxJava)

Ring Bit Buffer

动态规则配置

支持多种数据源

支持多种数据源

有限支持

扩展性

多个扩展点

插件的形式

接口的形式

基于注解的支持

支持

支持

支持

限流

基于 QPS,支持基于调用关系的限流

有限的支持

Rate Limiter

流量整形

支持预热模式、匀速器模式、预热排队模式

不支持

简单的 Rate Limiter 模式

系统自适应保护

支持

不支持

不支持

控制台

提供开箱即用的控制台,可配置规则、 查看秒级监控、机器发现等

简单的监控查看

不提供控制台,可对接其它监控系统

🌲 4.5 Sentinel入门

🌿 4.5.1 什么是Sentiel

Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等 应用容器。

🌿 4.5.2 Sentinel 控制台安装

Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。

  • 下载jar包

官方下载地址:https://github.com/alibaba/Sentinel/releases

  • 启动控制台

因为sentinel本身是一个SpringBoot项目,所以我们可以直接按照启动jar的方式启动这个项目,但是需要注意的是,sentinel这个SpringBoot项目是基于SpringBoot2.0X版本的,所以需要注意jdk版本太高了会有冲突。可以按照如下指令取执行jar文件:

先CMD进入到sentinel的jar包所在的目录,然后执行下面指令

java  -Dserver.port=8888 
-Dcsp.sentinel.dashboard.server=localhost:8888 
-Dproject.name=sentinel-dashboard  
-jar sentinel-dashboard-1.8.5.jar

为了避免每次启动,都需要输入指令,我们可以在sentinel的jar包同级目录中新建一个sentinel.bat启动文件,将上面指令放入其中,这样后续只需要点击这个执行文件即可启动。

sentinel启动之后如下图所示:

  • 访问sentinel后台

因为前面我们启动sentinel项目的时候将端口号设置成了8888,因此现在访问的话可以通过

http://localhost:8888来进入到控制台(默认的用户名和密码均是sentinel)

🌿 4.5.3 集成Sentinel

为微服务集成Sentinel非常简单, 只需要加入Sentinel的依赖即可

  • 在pom文件中添加相关依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2021.0.5.0</version>
</dependency>
  • 编写一个Controller测试使用
package com.moxuan.shoporder.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
public class OrderController3 {@RequestMapping("/order/message1")public String message1() {return "message1";}@RequestMapping("/order/message2")public String message2() {return "message2";}
}
  • 在shop-order的配置文件中添加有关sentinel控制台的配置
# sentinel 控制台配置
# 指定控制台服务器的地址
spring.cloud.sentinel.transport.dashboard=192.168.101.18:8888
spring.cloud.sentinel.eager=true

启动项目,观察此时项目已经加入到sentinel哨兵监控了。

我们选择左侧的流控规则,针对/order/message1 请求资源设置一个流控规则。如图所示:

设置完毕后,通过浏览器快速频繁的访问请求,观察效果:

🌿 4.5.4 Sentinel的概念和功能

🍁 基本概念
  • 资源

资源就是Sentinel要保护的东西

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,可以是一个服务,也可以是一个方法,甚至可以是一段代码

我们入门案例中的message1方法就可以认为是一个资源

  • 规则

规则就是用来定义如何进行保护资源的

作用在资源之上, 定义以什么样的方式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。

我们入门案例中就是为message1资源设置了一种流控规则, 限制了进入message1的流量

🍁 重要功能

Sentinel的主要功能就是容错,主要体现为下面这三个:

  • 流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的数据。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。

Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。

  • 熔断降级

当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

Sentinel 对这个问题采取了两种手段:

通过并发线程数进行限制

Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

通过响应时间对资源进行降级

除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复

🛎️ 面试突击

Sentinel Hystrix 的区别

两者的原则是一致的, 都是当一个资源出现问题时, 让其快速失败, 不要波及到其它服务但是在限制的手段上, 确采取了完全不一样的方法:

  • Hystrix 采用的是线程池隔离的方式, 优点是做到了资源之间的隔离, 缺点是增加了线程切换的成本。
  • Sentinel 采用的是通过并发线程的数量和响应时间来对资源做限制

  • 系统负载保护

Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候,如果还持续让请求进入可能会导致系统崩溃,无法响应。在集群环境下,会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求

总之一句话: 我们需要做的事情,就是在Sentinel的资源上配置各种各样的规则,来实现各种容错的功能。

🌲 4.6 Sentinel 规则

🌿 4.6.1 流控规则

流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

第1步: 点击簇点链路,我们就可以看到访问过的接口地址,然后点击对应的流控按钮,进入流控规则配置页面。新增流控规则界面如下:

资源名:唯一名称,默认是请求路径,可自定义

针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制

阈值类型/单机阈值

  • QPS(每秒请求数量): 当调用该接口的QPS达到阈值的时候,进行限流
  • 线程数:当调用该接口的线程数达到阈值的时候,进行限流

是否集群:暂不需要集群

接下来我们以QPS为例来研究限流规则的配置

🍁 简单的配置

我们先做一个简单配置,设置阈值类型为QPS,单机阈值为3。即每秒请求量大于3的时候开始限流。

接下来,在流控规则页面就可以看到这个配置。

然后快速访问 /order/message1 接口,观察效果。此时发现,当QPS > 3的时候,服务就不能正常响应,而是返回Blocked by Sentinel (flow limiting)结果。

🍁 配置流控模式

点击上面设置流控规则的编辑按钮,然后在编辑页面点击高级选项,会看到有流控模式一栏.

sentinel共有三种流控模式,分别是:

  • 直接(默认):接口达到限流条件时,开启限流
  • 关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]
  • 链路:当从某个接口过来的资源达到限流条件时,开启限流

直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。上面案例使用的就是直接流控模式,这里不再演示。

关联流控模式

关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。

第1步:配置限流规则, 将流控模式设置为关联,关联资源设置为的 /order/message2

第二步:通过jemeter设置线程组,注意QPS一定要大于3,也就是1秒钟至少要发出去3次请求

第三步:添加HTTP请求,发送/order/message2

第四步:启动jemeter,然后访问/order/message1,就会发现直接访问失败了

注意:如果没达到预期效果,检查一下jemeter中添加线程组和HTTP取样器中是否写错了。

链路流控模式

链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。

  • 第1步: 编写一个service,在里面添加一个方法message
package com.moxuan.shoporder.service.impl;import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;@Service
public class OrderServiceImpl3 {//表示是sentinel资源@SentinelResource("message")public void message() {System.out.println("message");}
}

@SentinelResource注解可以让业务层方方法变成 sentinel可以监控的资源。

  • 第二步:编写两个接口,都去访问这个message资源
package com.moxuan.shoporder.controller;import com.moxuan.shoporder.service.impl.OrderServiceImpl3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
public class OrderController3 {@Autowiredprivate OrderServiceImpl3 orderServiceImpl3;@RequestMapping("/order/message1")public String message1() {orderServiceImpl3.message();return "message1";}@RequestMapping("/order/message2")public String message2() {orderServiceImpl3.message();return "message2";}}
  • 第三步:在配置文件中禁止收敛URL的入口 context
# sentinel 控制台配置
# 指定控制台服务器的地址
spring.cloud.sentinel.transport.dashboard=192.168.5.224:8888
spring.cloud.sentinel.eager=true#spring.cloud.sentinel.filter.enabled=false
# 禁止收敛URL的入口
# Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。
spring.cloud.sentinel.web-context-unify=false
  • 第4步: 控制台配置限流规则

  • 第5步: 分别通过 /order/message1 和 /order/message2 访问, 发现1没问题, 2的被限流了

🍁 配置控流效果
  • 快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果
  • Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
  • 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

🌿 4.6.2 降级规则

降级规则就是设置当满足什么条件的时候,对服务进行降级。Sentinel提供了三个衡量条件:

🍁 慢调用比例

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。

  • 首先我们先添加一个控制器方法:
@GetMapping("/order/testC")
public String testC(){try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}return "----testC";
}
  • 设置熔断策略,1s 的 QPS>5 并且这些请求的RT>300(即最大的响应时间) 并且大于比例阈值0.1(10%)触发熔断。

  • 使用Jemeter进行压力测试,1秒钟创建10个线程发送请求

通过JMeter测试,1秒钟发起10个线程请求/testC,此时就会触发熔断效果,停止测试以后,10秒钟以后恢复正常

熔断效果:

流程图如下:

🍁 异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

  • 添加接口测试
  @GetMapping("/testD")public String testD(Integer id){if(id != null && id > 1){throw new RuntimeException("异常比例测试");}return "------------testD";}

  • 设置异常比例熔断策略

  • JMeter设置,发送请求的时候携带一个参数id,让它大于1,使其满足发生异常的条件

启动测试:观察熔断效果,同样结束测试,10秒后可以正常访问

🍁 异常数

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。

注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。

  • 新增接口代码
@GetMapping("/testE")
public String testE(Integer id){if(id != null && id > 1){throw new RuntimeException("异常数测试");}return "------------testE";
}
  • 设置异常数策略,当1秒钟内请求超过5并且异常数大于5个的时候触发熔断

  • Jemeter做压力测试

  • 观察熔断效果

经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

🌿 4.6.3 热点规则

热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。

🍁 热点规则简单使用

第1步: 编写代码

/*** 热点规则* @param name* @param age* @return*/
@RequestMapping("/order/message3")
@SentinelResource("message3")//注意这里必须使用这个注解标识,否则热点规则不生效
public String message3(String name, Integer age) {return name + age;
}

第2步:配置热点规则

  • 参数索引:方法中的参数位置,从0开始

上面的配置含义是1秒内访问位置为0的参数(name参数)超过1次就会被限流

第3步:分别测试,快速刷新

http://localhost:8031/order/message3?name=moxuan

http://localhost:8031/order/message3?age=12

会发现name参数被限流了,而age参数没有被限流

🍁 热点规则增强使用

参数列外项允许针对某个具体值不进行流控

编辑刚才定义的规则,增加参数的例外项

测试:http://localhost:8031/order/message3?name=moxuan

当传输name值为moxuan的时候,就不会进行流控

测试:http://localhost:8031/order/message3?name=hhh

当传输其他name值的时候,就会被流控

🌿 4.6.4 授权规则

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源

访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:

  • 若配置白名单,则只有请求来源位于白名单内时才可通过;
  • 若配置黑名单,则请求来源位于黑名单时不通过,其余的请求通过

上面的资源名和授权类型不难理解,但是流控应用怎么填写呢?

其实这个位置要填写的是来源标识,Sentinel提供了 RequestOriginParser 接口来处理来源。

只要Sentinel保护的接口资源被访问,Sentinel就会调用 RequestOriginParser 的实现类去解析访问来源。

自定义来源处理规则:

package com.moxuan.shoporder.config;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Component
@Slf4j
public class RequestOriginParserDefinition implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {String serviceName = request.getParameter("serviceName"); //接收请求参数if (serviceName == null || "".equals("serviceName")){ //如果参数内容为空serviceName = request.getHeader("serviceName");}log.info("授权信息serviceName--->" + serviceName);if (StringUtils.isEmpty(serviceName)){return request.getRemoteAddr(); //根据ip地址处理}return serviceName;}
}

配置授权规则:

这个配置的意思是只有serviceName=pc 不能访问(黑名单)

访问:http://localhost:8031/order/message1?serviceName=pc

再将serviceName替换成任意值,可以发现都可以正常访问

🌿 4.6.5 系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 、CPU 使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般 是 CPU cores * 2.5。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
  • CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护。

🌿 4.6.6 自定义异常返回

我们可以自定义一些当触发sentinel异常时,返回的信息

package com.moxuan.shoporder.config;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {/*** BlockException  异常接口,包含sentinel的五个异常* FlowException 限流异常* DegradeException 降级异常* ParamFlowException 参数限流异常* SystemBlockException 系统负载异常* AuthorityException 授权异常*/@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {ErrorMsg msg = null;if (e instanceof FlowException) {msg = ErrorMsg.builder().msg("呀,我被限流了!").status(101).build();} else if (e instanceof DegradeException) {msg = ErrorMsg.builder().msg("呀,我被降级了!").status(102).build();} else if (e instanceof ParamFlowException) {msg = ErrorMsg.builder().msg("呀,我被热点参数限流了!").status(103).build();} else if (e instanceof SystemBlockException) {msg = ErrorMsg.builder().msg("呀,系统规则(负载/...不满足要求)!").status(104).build();} else if (e instanceof AuthorityException) {msg = ErrorMsg.builder().msg("呀,授权规则不通过!").status(105).build();}// http状态码httpServletResponse.setStatus(500);httpServletResponse.setCharacterEncoding("utf-8");httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");httpServletResponse.setContentType("application/json;charset=utf-8");// spring mvc自带的json操作工具jacksonnew ObjectMapper().writeValue(httpServletResponse.getWriter(),msg);}
}@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
class ErrorMsg {private Integer status;private String msg;
}

继续使用授权规则设置:

再次访问:http://localhost:8031/order/message1?serviceName=pc

🌲 4.7 @SentinelResource的使用

在定义了资源点之后,我们可以通过Dashboard来设置限流和降级策略来对资源点进行保护。同时还能通过@SentinelResource来指定出现异常时的处理策略。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。其主要参数如下:

🌿 定义限流和降级后的处理方法

🍁 方法中指定限流和降级方法

方式一:直接将限流和降级方法定义在方法中

package com.moxuan.shoporder.service.impl;import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.moxuan.shopcommon.entity.Order;
import com.moxuan.shopcommon.util.Result;
import com.moxuan.shoporder.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class OrderServiceImpl3  {int i=0;//表示是sentine资源@SentinelResource(value = "message", // 指定资源名称blockHandler = "blockHandler", // 指定发生blockException时进入的方法fallback = "fallback" // 指定发生Throwable时进入的方法)public String message() {i++;if(i%3==0){throw  new RuntimeException();}return "message";}/*** 被限流或者降级时进入的方法* @param ex* @return*/public String blockHandler(BlockException ex){log.error("{}",ex);System.out.println("test...............");return "接口被限流或者降级了....";}public String fallback(Throwable throwable){log.error("{}",throwable);return "接口发生异常了....";}}

第二步:在资源名称为message上设置流控

第三步:快速访问http://localhost:8031/order/message1

当1秒钟超过1次请求时,就会出现:

当执行三次发生异常时,就会出现:

🍁 类中指定限流和降级方法
package com.moxuan.shoporder.config;import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class OrderServiceBlockHandlerClass {// 注意这里必须使用static修饰方法public static String blockHandler1(BlockException ex){log.error("{}",ex);return "接口被限流或者降级了";}
}
package com.moxuan.shoporder.config;import lombok.extern.slf4j.Slf4j;@Slf4j
public class OrderServiceFallbackClass {public static String fallback1(Throwable throwable){log.error("{}",throwable);return "接口发生异常了...";}
}
  @SentinelResource(value = "message",blockHandlerClass = OrderServiceBlockHandlerClass.class, // 指定限流异常类blockHandler = "blockHandler1", // 指定限流或者降级后执行的方法fallbackClass = OrderServiceFallbackClass.class,fallback = "fallback1")public String message() {i++;if(i%3==0){throw  new RuntimeException();}return "message";}

🌲 4.8 Feign 整合sentinel

第1步: 引入sentinel的依赖和openFeign依赖

注意:openFeign依赖要升到3.1.8

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2021.0.5.0</version>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>3.1.8</version>
</dependency>

第2步:在配置文件中开启Feign对Sentinel的支持

# 开启feign对sentinel的支持
feign.sentinel.enabled=true

第3步:创建容错类

package com.moxuan.shoporder.sentinel;import com.moxuan.shopcommon.entity.Product;
import com.moxuan.shopcommon.util.Result;
import com.moxuan.shopcommon.util.ReturnCode;
import com.moxuan.shoporder.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** 容错类必须要求实现被容错的接口,并为每个方法提供容错方案*/
@Component
@Slf4j
public class ProductServiceFallBack implements ProductService {@Overridepublic Result findProductByPid(int pid) {// 假如查询不到数据,这里的容错方案就是给一个product对象Product product = new Product();product.setPid(-1);return Result.sendResult(ReturnCode.NO_RESULT,product);}
}

第4步:为被容错的接口指定容错类

package com.moxuan.shoporder.service;import com.moxuan.shopcommon.util.Result;
import com.moxuan.shoporder.sentinel.ProductServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;// 声明调用的提供者的name,以及容错的类
@FeignClient(value = "service-product",fallback = ProductServiceFallBack.class)  
public interface ProductService {/*** 指定调用服务提供者的那个接口方法* @FeignClient+@GetMapping 就是一个完整的请求路径* http://service-product/product/{pid}* @param pid* @return*/@GetMapping(value="/product/{pid}")Result findProductByPid(@PathVariable("pid") int pid);
}

第5步:修改controller

package com.moxuan.shoporder.controller;import com.alibaba.fastjson.JSON;
import com.moxuan.shopcommon.entity.Order;
import com.moxuan.shopcommon.entity.Product;
import com.moxuan.shopcommon.util.Result;
import com.moxuan.shopcommon.util.ReturnCode;
import com.moxuan.shoporder.service.OrderService;
import com.moxuan.shoporder.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;@RestController
@Slf4j
public class OrderController {@Autowiredprivate OrderService orderService;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate ProductService productService;@GetMapping("/order/prod/{pid}")public Result order(@PathVariable("pid")Integer pid){log.info(">> 客户下单,这时候要调用商品微服务查询商品信息");//2.使用了Ribbon+Fegin 负载均衡访问Result result = productService.findProductByPid(pid);//通过restTemplate调用尚敏的微服务log.info("商品信息>> 查询结果"+result.getData());Product pro = JSON.parseObject(result.getData().toString(),Product.class);// 如果返回的pro是-1,就是pro没有查到数据if(pro.getPid()==-1){Order order = new Order();order.setPname("下单失败");return Result.sendResult(ReturnCode.NO_RESULT,order);}System.out.println(pro);Order order = new Order();order.setUid(1);order.setUsername("墨轩");order.setPid(pro.getPid());order.setPname(pro.getPname());order.setPprice(pro.getPprice());order.setNum(1);result = orderService.saveOrder(order);log.info("创建订单成功,订单信息为{}",JSON.toJSONString(order));return result;}}

第6步:停止所有的shop-product服务,模拟熔断情况,找不到product商品,重启shop-order服务,观察容错结果。

🌲 4.9 sentinel 持久化

通过前面的讲解,我们已经知道,可以通过Dashboard来为每个Sentinel客户端设置各种各样的规 则,但是这里有一个问题,就是这些规则默认是存放在内存中,极不稳定,所以需要将其持久化。

本地文件数据源会定时轮询文件的变更,读取规则。这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。以本地文件数据源为例,推送过程如下图所示:

首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的

规则保存到本地的文件中。

  1. 添加配置类:配置规则保存的路径
package com.moxuan.shoporder.config;import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;import java.io.File;
import java.io.IOException;
import java.util.List;//规则持久化
public class FilePersistence implements InitFunc {@Overridepublic void init() throws Exception {String ruleDir = System.getProperty("user.home") + "/sentinel-rules/shop-order/" ;String flowRulePath = ruleDir + "/flow-rule.json";String degradeRulePath = ruleDir + "/degrade-rule.json";String systemRulePath = ruleDir + "/system-rule.json";String authorityRulePath = ruleDir + "/authority-rule.json";String paramFlowRulePath = ruleDir + "/param-flow-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);this.createFileIfNotExits(paramFlowRulePath);// 流控规则ReadableDataSource<String, List<FlowRule>> flowRuleRDS = newFileRefreshableDataSource<>(flowRulePath,flowRuleListParser);FlowRuleManager.register2Property(flowRuleRDS.getProperty());WritableDataSource<List<FlowRule>> flowRuleWDS = newFileWritableDataSource<>(flowRulePath,this::encodeJson);WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);// 降级规则ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = newFileRefreshableDataSource<>(degradeRulePath,degradeRuleListParser);DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());WritableDataSource<List<DegradeRule>> degradeRuleWDS = newFileWritableDataSource<>(degradeRulePath,this::encodeJson);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);// 系统规则ReadableDataSource<String, List<SystemRule>> systemRuleRDS = newFileRefreshableDataSource<>(systemRulePath,systemRuleListParser);SystemRuleManager.register2Property(systemRuleRDS.getProperty());WritableDataSource<List<SystemRule>> systemRuleWDS = newFileWritableDataSource<>(systemRulePath,this::encodeJson);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);// 授权规则ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = newFileRefreshableDataSource<>(authorityRulePath,authorityRuleListParser);AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());WritableDataSource<List<AuthorityRule>> authorityRuleWDS = newFileWritableDataSource<>(authorityRulePath,this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);// 热点参数规则ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = newFileRefreshableDataSource<>(paramFlowRulePath,paramFlowRuleListParser);ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = newFileWritableDataSource<>(paramFlowRulePath,this::encodeJson);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);}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>>() {});private Converter<String, List<SystemRule>> systemRuleListParser = source ->JSON.parseObject(source,new TypeReference<List<SystemRule>>() {});private Converter<String, List<AuthorityRule>> authorityRuleListParser =source -> JSON.parseObject(source,new TypeReference<List<AuthorityRule>>() {});private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser =source -> JSON.parseObject(source,new TypeReference<List<ParamFlowRule>>() {});private void mkdirIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.mkdirs();}}private void createFileIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.createNewFile();}}private <T> String encodeJson(T t) {return JSON.toJSONString(t);}
}
  1. 添加配置

在 resources 下创建配置目录,META-INF/services,然后添加文件

com.alibaba.csp.sentinel.init.InitFunc

在文件中添加配置类的全路径

com.moxuan.shoporder.config.FilePersistence

相关文章:

【SpringCloud详细教程】-04-服务容错--Sentinel

精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. 《SpringBoot详细教程》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12789841.html?spm1001.20…...

计算机学习

不要只盯着计算机语言学习&#xff0c;你现在已经学习了C语言和Java&#xff0c;暑假又规划学习Python&#xff0c;最后你掌握的就是计算机语言包而已。 2. 建议你找一门想要深挖的语言&#xff0c;沿着这个方向继续往后学习知识就行。计算机语言是学不完的&#xff0c;而未来就…...

CSS - CSS One-Line

1. aspect-ratio 描述: 用于定义元素的宽高比&#xff0c;简化了以往使用“填充黑客”的方法。只需指定一个比率&#xff0c;浏览器会自动调整元素的尺寸 案例: .aspect-ratio-hd {aspect-ratio: 16/9; } .aspect-ratio-square {aspect-ratio: 1; /* 正方形 */ }2. object-…...

【AIGC】如何准确引导ChatGPT,实现精细化GPTs指令生成

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | 提示词Prompt应用实例 文章目录 &#x1f4af;前言&#x1f4af;准确引导ChatGPT创建爆款小红书文案GPTs指令案例&#x1f4af; 高效开发GPTs应用的核心原则明确应用场景和目标受众构建多样化风格模板提问与引…...

Redis主从架构

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的键值对存储系统&#xff0c;广泛应用于缓存、消息队列、实时分析等场景。为了提高系统的可用性、可靠性和读写性能&#xff0c;Redis提供了主从复制&#xff08;Master-Slave Replication&#xf…...

无人机探测:光电侦测核心技术算法详解!

核心技术 双光谱探测跟踪&#xff1a; 可见光成像技术&#xff1a;利用无人机表面反射的自然光或主动光源照射下的反射光&#xff0c;通过高灵敏度相机捕捉图像。该技术适用于日间晴朗天气下的无人机探测&#xff0c;具有直观、易于识别目标的特点。 红外成像技术&#xff1…...

34 基于单片机的指纹打卡系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52RC&#xff0c;采用两个按键替代指纹&#xff0c;一个按键按下&#xff0c;LCD12864显示比对成功&#xff0c;则 采用ULN2003驱动步进电机转动&#xff0c;表示开门&#xff0c;另一个…...

Day 26

进入贪心算法 基础理论 1、什么是贪心&#xff1f; 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 Eg&#xff1a;一堆钞票&#xff0c;你可以拿走 10 张&#xff0c;想达到最大金额&#xff0c;要怎么拿&#xff1f; –》指定每一次拿最大的&#xff0…...

11.25c++继承、多态

练习&#xff1a; 编写一个 武器类 class Weapon{int atk; }编写3个武器派生类&#xff1a;短剑&#xff0c;斧头&#xff0c;长剑 class knife{int spd; }class axe{int hp; }class sword{int def; }编写一个英雄类 class Hero{int atk;int def;int spd;int hp; public:所有的…...

ThinkPad t61p 作SMB服务器,打印服务器,pc ,android ,ipad利用此服务器互传文件

1.在t61p上安装win7 2,配置好smb 服务 3.再安装好打印驱动程序 4.pc与win7利用系统的网络互相发现,映射为硬盘使用。 5.android&#xff0c;ipad安装ES文件浏览器访问win7 共享文件夹&#xff0c;互传文件。 6.android手机安装FE文件浏览器&#xff0c;可以利用花生壳外网…...

数据结构单链表,顺序表,广义表,多重链表,堆栈的学习

单链表 比如一个多项式&#xff0c;主要包括x的系数&#xff0c;x的指数&#xff0c;那么可以创建一个一维数组来存储它的系数和指数&#xff0c;用数组下标来表示。它的系数可以用数组下标对应的数组元素来储存。 可是这样储存会浪费空间所以采用单链表形式来存储。 即创建一…...

uniapp内嵌的webview H5与应用通信

H5端&#xff1a; 1、找到index.html引入依赖 <script type"text/javascript" src"https://unpkg.com/dcloudio/uni-webview-js0.0.3/index.js"></script> 2、在需要通讯处发送消息 uni.postMessage({data:{code:200,msg:"处理完成&q…...

黄仁勋:人形机器人在内,仅有三种机器人有望实现大规模生产

11月23日&#xff0c;芯片巨头、AI时代“卖铲人”和最大受益者、全球市值最高【英伟达】创始人兼CEO黄仁勋在香港科技大学被授予工程学荣誉博士学位&#xff1b;并与香港科技大学校董会主席沈向洋展开深刻对话&#xff0c;涉及人工智能&#xff08;AI&#xff09;、计算力、领导…...

Docker--harbor私有仓库部署与管理

目录 一、Harbor 简介 1.1 什么是Harbor 1.2 Harbor的特性 1.3 Harbor的构成 二、Harbor 部署 2.1 部署 Docker-Compose 服务 2.2 部署 Harbor 服务 &#xff08;1&#xff09;下载或上传 Harbor 安装程序 &#xff08;2&#xff09;修改harbor安装的配置文件 2.3 启…...

35 基于单片机的精确电压表DA-AD转换

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DAC0832和ADC0832检测电压&#xff0c;0到8.5V&#xff0c;设计复位电路 LED管显示实际稳压值&#xff0c;初始电压0 二、硬件资源 基于KEIL5编写C代码&#xff0c…...

Windows系统下安装Triton 3.0.0预编译Triton 2.1.0

Triton是一个用于编写高效自定义深度学习原语的语言和编译器。它旨在提供一个开源环境&#xff0c;使得编写代码的速度比CUDA更快&#xff0c;同时比其他现有的DSLs&#xff08;领域特定语言&#xff09;更灵活。 在开始安装之前&#xff0c;请确保您的系统满足以下要求&#x…...

Easyexcel(7-自定义样式)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09;Easyexcel&#xff08;6-单…...

ubuntu搭建k8s环境详细教程

在Ubuntu上搭建Kubernetes&#xff08;K8s&#xff09;环境可以通过多种方式实现&#xff0c;下面是一个详细的教程&#xff0c;使用kubeadm工具来搭建Kubernetes集群。这个教程将涵盖从准备工作到安装和配置Kubernetes的所有步骤。 环境准备 操作系统&#xff1a;确保你使用的…...

spark 写入mysql 中文数据 显示?? 或者 乱码

目录 前言 Spark报错&#xff1a; 解决办法&#xff1a; 总结一下&#xff1a; 报错&#xff1a; 解决&#xff1a; 前言 用spark写入mysql中&#xff0c;查看中文数据 显示?? 或者 乱码 Spark报错&#xff1a; Sat Nov 23 19:15:59 CST 2024 WARN: Establishing SSL…...

Python中的简单爬虫

文章目录 一. 基于FastAPI之Web站点开发1. 基于FastAPI搭建Web服务器2. Web服务器和浏览器的通讯流程3. 浏览器访问Web服务器的通讯流程4. 加载图片资源代码 二. 基于Web请求的FastAPI通用配置1. 目前Web服务器存在问题2. 基于Web请求的FastAPI通用配置 三. Python爬虫介绍1. 什…...

网络安全原理与技术思考题/简答题

作业1&#xff08;第1章、第2章、第8章&#xff09; 1. 网络安全的基本属性有哪些&#xff1f;简单解释每个基本属性的含义。网络安全的扩展属性包括哪些&#xff1f; 基本属性&#xff1a; 1.机密性(Confidentiality)&#xff1a; 含义&#xff1a;确保信息不被未授权的用户…...

技术周刊 | 前端真的凉了吗?2024 前端趋势解读

大家好&#xff0c;我是童欧巴。见字如面&#xff0c;万事胜意。 小雪已过&#xff0c;大家勿忘添衣御寒&#xff0c;欢迎来到第 135 期周刊。 大厨推荐 2024 前端趋势 The Software House 公司发布的前端状态调查报告&#xff0c;本版是迄今为止最全面的调查&#xff0c;共…...

Qt常用控件之按钮类控件

目录 QPushButton 添加图标 添加快捷键 QRadioButton 关于toggled 模拟点餐功能 QCheckBox 刚刚 QWidget 中涉及到的各种 属性/函数/使用方法&#xff0c;针对接下来要介绍的 Qt 的各种控件都是有效的&#xff0c;因为各种控件都是继承自 QWidget 的 接下来本篇博客就学…...

Wonder3D本地部署到算家云搭建详细教程

Wonder3D简介 Wonder3D仅需2至3分钟即可从单视图图像中重建出高度详细的纹理网格。Wonder3D首先通过跨域扩散模型生成一致的多视图法线图与相应的彩色图像&#xff0c;然后利用一种新颖的法线融合方法实现快速且高质量的重建。 本文详细介绍了在算家云搭建Wonder3D的流程以及…...

景联文科技:高质量数据采集标注服务引领AI革新

在当今这个数字化时代&#xff0c;数据已经成为推动社会进步和产业升级的关键资源。特别是在人工智能领域&#xff0c;高质量的数据是训练出高效、精准的AI模型的基础。景联文科技是一家专业的数据采集与标注公司&#xff0c;致力于为客户提供高质量的数据处理服务&#xff0c;…...

企业面试真题----阿里巴巴

1.HashMap为什么不是线程安全的&#xff1f; 首先hashmap就是为单线程设计的&#xff0c;并不适合于多线程环境&#xff0c;而hashmap的线程不安全原因主主要是以下两个原因&#xff1a; 死循环 死循环问题发生在jdk1.8之前&#xff08;不包含1.8&#xff09;&#xff0c;造…...

极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【四】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…...

【C++知识总结2】C++里面的小配角cout和cin

一、引入 第一个关于输入输出的C代码 #include<iostream> // std是C标准库的命名空间名&#xff0c;C将标准库的定义实现都放到这个命名空间中 using namespace std; int main() {cout<<"Hello world!!!"<<endl;return 0; } 1. 使用cout标准输出…...

门控循环单元(GRU)与时间序列预测应用

一、GRU简介 门控循环单元&#xff08;Gated Recurrent Unit&#xff0c;简称GRU&#xff09;是一种简化版的LSTM&#xff08;长短期记忆网络&#xff09;&#xff0c;专门用于解决长序列中的梯度消失问题。与LSTM相比&#xff0c;GRU具有更简单的结构和较少的参数&#xff0c…...

Spring Boot 3 集成 Spring Security(2)授权

文章目录 授权配置 SecurityFilterChain基于注解的授权控制自定义权限决策 在《Spring Boot 3 集成 Spring Security&#xff08;1&#xff09;》中&#xff0c;我们简单实现了 Spring Security 的认证功能&#xff0c;通过实现用户身份验证来确保系统的安全性。Spring Securit…...

互联网摸鱼日报(2024-11-22)

互联网摸鱼日报(2024-11-22) 36氪新闻 学习马斯克不丢人&#xff0c;脸书也开始改造自己了 旅游行业趋势变了&#xff0c;增长还能从哪里寻找&#xff1f; 大厂入局后&#xff0c;小型小游戏团队能否继续喝一口汤&#xff1f; 一拥而上的“跨界咖啡”&#xff0c;是“走心”…...

RNN并行化——《Were RNNs All We Needed?》论文解读

InfoPaperhttps://arxiv.org/abs/2410.01201GitHubhttps://github.com/lucidrains/minGRU-pytorch个人博客地址http://myhz0606.com/article/mini_rnn 最近在看并行RNN相关的paper&#xff0c;发现很多都利用了Parallel Scanning算法。本文将从Parallel Scanning算法开始&…...

机器学习周志华学习笔记-第6章<支持向量机>

机器学习周志华学习笔记-第6章<支持向量机> 卷王&#xff0c;请看目录 6支持向量机6.1 函数间隔与几何间隔6.1.1 函数间隔6.1.2 几何间隔 6.2 最大间隔与支持向量6.3 对偶问题6.4 核函数6.5 软间隔支持向量机6.6 支持向量机6.7核方法 6支持向量机 支持向量机是一种经典…...

IP反向追踪技术,了解一下?

DOSS&#xff08;拒绝服务&#xff09;攻击是现在比较常见的网络攻击手段。想象一下&#xff0c;有某个恶意分子想要搞垮某个网站&#xff0c;他就会使用DOSS攻击。这种攻击常常使用的方式是IP欺骗。他会伪装成正常的IP地址&#xff0c;让网络服务器以为有很多平常的请求&#…...

2025蓝桥杯(单片机)备赛--扩展外设之UART1的原理与应用(十二)

一、串口1的实现原理 a.查看STC15F2K60S2数据手册: 串口一在590页&#xff0c;此款单片机有两个串口。 串口1相关寄存器&#xff1a; SCON:串行控制寄存器&#xff08;可位寻址&#xff09; SCON寄存器说明&#xff1a; 需要PCON寄存器的SMOD0/PCON.6为0&#xff0c;使SM0和SM…...

Linux 使用gdb调试core文件

core文件和gdb调试 什么是 core 文件&#xff1f;产生core文件的原因&#xff1f;core 文件的控制和生成路径gdb 调试core 文件引用和拓展 什么是 core 文件&#xff1f; 当程序运行过程中出现Segmentation fault (core dumped)错误时&#xff0c;程序停止运行&#xff0c;并产…...

Python后端flask框架接收zip压缩包方法

一、用base64编码发送&#xff0c;以及接收 import base64 import io import zipfile from flask import request, jsonifydef unzip_and_find_png(zip_data):# 使用 BytesIO 在内存中处理 zip 数据with zipfile.ZipFile(io.BytesIO(zip_data), r) as zip_ref:extracted_paths…...

【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 文章题目&#xff1a;Java技术深度剖析&#xff1a;从分库分表到微服务的核心问题解析 摘要&#xff1a; 本…...

Linux 中 find 命令使用详解

目录 一&#xff1a;基本语法二&#xff1a;搜索路径1、限制递归层级2、排除指定路径 三&#xff1a;匹配条件1、按照文件名搜索2、按文件类型搜索3、按文件大小搜索4、按文件权限搜索5、按文件所有者或所属组搜索6、按文件修改时间搜索 四&#xff1a;执行操作1、输出满足条件…...

云服务器部署WebSocket项目

WebSocket是一种在单个TCP连接上进行全双工通信的协议&#xff0c;其设计的目的是在Web浏览器和Web服务器之间进行实时通信&#xff08;实时Web&#xff09; WebSocket协议的优点包括&#xff1a; 1. 更高效的网络利用率&#xff1a;与HTTP相比&#xff0c;WebSocket的握手只…...

林业产品智能推荐引擎:Spring Boot篇

1 绪论 1.1 选题背景 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。计算机软件可以针对不同行业的营业特点以及管理需求&#xff0c;设置不同的功能&…...

【C++】LeetCode:LCR 077. 排序链表

题干 LCR 077. 排序链表 给定链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 解法&#xff1a;归并排序 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(null…...

git教程

文章目录 简介&#xff1a;使用教程&#xff1a;&#xff08;1&#xff09;安装git&#xff1a;&#xff08;2&#xff09;设置用户名和邮箱作为标识符&#xff1a;&#xff08;3&#xff09;建立本地仓库&#xff1a;本地仓库作用&#xff1a;&#xff08;1&#xff09;将文件…...

报表工具功能对比:免费易上手的山海鲸报表 vs 庞大用户群体的Tableau

在数据报表与分析领域&#xff0c;随着大数据技术的不断发展和企业数字化转型的深入&#xff0c;市面上涌现出了众多报表工具&#xff0c;为用户提供多元化的选择。对于企业数据分析师、IT人员及管理层来说&#xff0c;选择一款适合自己的报表工具至关重要。本文将从多个角度对…...

鸿蒙原生应用开发及部署:首选华为云,开启HarmonyOS NEXT App新纪元

目录 前言 HarmonyOS NEXT&#xff1a;下一代操作系统的愿景 1、核心特性和优势 2、如何推动应用生态的发展 3、对开发者和用户的影响 华为云服务在鸿蒙原生应用开发中的作用 1、华为云ECS C系列实例 &#xff08;1&#xff09;全维度性能升级 &#xff08;2&#xff…...

CSS之3D转换

三维坐标系 三维坐标系其实就是指立体空间&#xff0c;立体空间是由3个轴共同组成的。 x轴:水平向右注意:x右边是正值&#xff0c;左边是负值 y轴:垂直向下注意:y下面是正值&#xff0c;上面是负值 z轴:垂直屏幕注意:往外面是正值&#xff0c;往里面是负值 3D移动 translat…...

uni-app初学笔记:文件路径与作用

components:可复用的组件pages:页面&#xff08;可见/不可见&#xff09;static:静态资源&#xff0c;存放图片视频等 &#xff08;相当于vue项目的 assets&#xff09;mainjs:Vue初始化入口文件App.vue:应用配置&#xff0c;用来配置App全局样式以及监听pages.json :配置页面路…...

子组件中$emit和update更新传递变量

vue2.6之后才可以使用update更新&#xff0c;vue2.6以下版本使用input和v-model 需求描述&#xff1a;蒙层上展示弹窗&#xff0c;弹窗点击关闭&#xff0c;需要向父传递关闭的信息 方法1&#xff0c;简便直接传递变量visible&#xff08;或者不改名isModalVisible也是可以的…...

浅谈Python库之lxml

一、基本介绍 lxml 是一个用 Python 编写的库&#xff0c;它提供了对 XML 和 HTML 文档的解析和操作功能。它使用 C 语言编写的 libxml2 和 libxslt 库作为后端&#xff0c;因此解析速度非常快&#xff0c;并且能够处理大型文档。lxml 支持 XPath 和 XSLT&#xff0c;这使得它在…...

spring boot框架漏洞复现

spring - java开源框架有五种 Spring MVC、SpringBoot、SpringFramework、SpringSecurity、SpringCloud spring boot版本 版本1: 直接就在根下 / 版本2:根下的必须目录 /actuator/ 端口:9093 spring boot搭建 1:直接下载源码打包 2:运行编译好的jar包:actuator-testb…...