【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

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

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

相关文章

【Python中while循环】

一、深拷贝、浅拷贝 1、需求 1&#xff09;拷贝原列表产生一个新列表 2&#xff09;想让两个列表完全独立开&#xff08;针对改操作&#xff0c;读的操作不改变&#xff09; 要满足上述的条件&#xff0c;只能使用深拷贝 2、如何拷贝列表 1&#xff09;直接赋值 # 定义一个…

在 Mac(ARM 架构)上安装 JDK 8 环境

文章目录 步骤 1&#xff1a;检查系统版本步骤 2&#xff1a;下载支持 ARM 的 JDK 8步骤 3&#xff1a;安装 JDK步骤 4&#xff1a;配置环境变量步骤 5&#xff1a;验证安装步骤 6&#xff1a;注意事项步骤7&#xff1a;查看Java的安装路径 在 Mac&#xff08;ARM 架构&#xf…

对比C++,Rust在内存安全上做的努力

简介 近年来&#xff0c;越来越多的组织表示&#xff0c;如果新项目在技术选型时需要使用系统级开发语言&#xff0c;那么不要选择使用C/C这种内存不安全的系统语言&#xff0c;推荐使用内存安全的Rust作为替代。 谷歌也声称&#xff0c;Android 的安全漏洞&#xff0c;从 20…

小程序基础:流程。

一、前言 该文章是个人的学习笔记&#xff0c;是学习了黑马程序的微信小程序开发视频后写的笔记&#xff0c;将老师所讲的内容重点汇总起来&#xff0c;目的是为了方便自己日后回顾&#xff0c;同时也方便大家学习和了解小程序的开发 想要入门小程序&#xff0c;那么看这一篇文…

【漏洞复现】CVE-2020-13925

漏洞信息 NVD - CVE-2020-13925 Similar to CVE-2020-1956, Kylin has one more restful API which concatenates the API inputs into OS commands and then executes them on the server; while the reported API misses necessary input validation, which causes the hac…

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…

LLM PPT Translator

LLM PPT Translator 引言Github 地址UI PreviewTranslated Result Samples 引言 周末开发了1个PowerPoint文档翻译工具&#xff0c;上传PowerPoint文档&#xff0c;指定想翻译的目标语言&#xff0c;通过LLM的能力将文档翻译成目标语言的文档。 Github 地址 https://github.…

Python数据分析实例五、US 大选捐款数据分析

美国联邦选举委员会 (FEC) 公布了对政治竞选活动的贡献数据。这包括投稿人姓名、职业和雇主、地址和投款金额。2012 年美国总统大选的贡献数据以单个 150 MB 的 CSV 文件P00000001-ALL.csv形式提供,该文件可以通过以下pandas.read_csv加载: import pandas as pdfec = pd.r…

3.http模块

文章目录 [TOC](文章目录) 1、什么是http模块&#xff1f;1.1.作用1.2.服务器相关概念1.2.创建基本的web服务器-实现的核心步骤和代码1.2.1导入http模块1.2.2.req 请求对象 1.3.根据不同的url地址 响应不同的html内容1.4.案例-clock时钟的web服务器 1、什么是http模块&#xff…

【Nginx】核心概念与安装配置解释

文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是我之前维…

IDEA2024创建一个spingboot项目

以下是创建一个基本的 Spring Boot 项目的步骤和示例&#xff1a; 初始化一个springboot工程其实有许多方法&#xff0c;笔者这里挑了一个最快捷的方式搭建一个项目。我们直接通过官方平台&#xff08;start.spring.io&#xff09;进行配置&#xff0c;然后下载压缩包就可以获取…

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-单…

北京航空航天大学多模态自适应攀岩机器人:突破复杂地形挑战

近年来&#xff0c;地外天体探测任务的需求显著增加&#xff0c;尤其是在月球、火星等崎岖地形的探索中&#xff0c;攀岩机器人凭借其灵活性和稳定性成为重要工具。然而&#xff0c;传统攀爬技术在面对复杂地形时仍面临诸多挑战&#xff0c;如附着装置的适应性不足、柔顺性较低…

【Java】二叉树:数据海洋中灯塔式结构探秘(上)

个人主页 &#x1f339;&#xff1a;喜欢做梦 二叉树中有一个树&#xff0c;我们可以猜到他和树有关&#xff0c;那我们先了解一下什么是树&#xff0c;在来了解一下二叉树 一&#x1f35d;、树型结构 1&#x1f368;.什么是树型结构&#xff1f; 树是一种非线性的数据结构&…

深度学习基础01_深度学习概述参数初始化激活函数

目录 一、深度学习概述 二、神经网络 1、感知神经网络 2、人工神经元 1.构建 2.组成 3.数学表示 3、深入神经网络 1.基本结构 2.网络构建 3.全连接神经网络 三、数据处理 四、参数初始化 1、固定值初始化 1.全零初始化 2.全1初始化 3.任意常数初始化 2、随机…

从Full-Text Search全文检索到RAG检索增强

从Full-Text Search全文检索到RAG检索增强 时光飞逝&#xff0c;转眼间六年过去了&#xff0c;六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目&#xff0c;铁蛋也从最开始做CRUD转行去了大数据平台开发&#xff0c;混迹包装开源的业务&#xff0c;机缘巧合下做了实时…

C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)

目录 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 3. 代码实现 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 题目截图&#xff1a; 此题所说的…

【pyspark学习从入门到精通19】机器学习库_2

目录 估计器 分类 回归 聚类 管道 估计器 估计器可以被看作是需要估算的统计模型&#xff0c;以便对您的观测值进行预测或分类。 如果从抽象的 Estimator 类派生&#xff0c;新模型必须实现 .fit(...) 方法&#xff0c;该方法根据在 DataFrame 中找到的数据以及一些默认或…

JAVA---IO

目录 IO流 一 字节流 1 FileOutStream 1 书写&#xff1a; 2 换行书写与续写&#xff1a; 2 FileInputStream 1 读取数据 2 循环读取&#xff1a; 二 字符流 1 FileReader 1 空参的read()方法读取数据&#xff1a; 2 有参的read()方法读取数据&#xff1a; 3 指定字…