Sentinel熔断与限流

一、服务雪崩与解决方案

1.1、服务雪崩问题

一句话:微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。

微服务中,服务间调用关系错综复杂,一个微服务往往依赖于多个其它微服务。

image-20240827204943349

如图,如果服务提供者I发生了故障,当前的应用的部分业务因为依赖于服务I,因此也会被阻塞。此时,其它不依赖于服务I的业务似乎不受影响。

image-20240827205002590

但是,依赖服务I的业务请求被阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞:

image-20240827205244584

服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,那么当前服务也就不可用了。

那么,依赖于当前服务的其它服务随着时间的推移,最终也都会变的不可用,形成级联失败,雪崩就发生了:

image-20240827205256638

解决雪崩问题的常见方式有四种:

1.2、超时处理

超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待

image-20240827205650618

1.3、仓壁模式

仓壁模式来源于船舱的设计:

船舱都会被隔板分离为多个独立空间,当船体破损时,只会导致部分空间进入,将故障控制在一定范围内,避免整个船体都被淹没。

于此类似,我们可以限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。

image-20240827205714458

1.4、断路器

断路器模式:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。

断路器会统计访问某个服务的请求数量,异常比例:

image-20240827205519805

当发现访问服务D的请求异常比例过高时,认为服务D有导致雪崩的风险,会拦截访问服务D的一切请求,形成熔断:

image-20240827205540092

1.5、限流

流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

image-20240827205625160

1.6、总结

什么是雪崩问题?

  • 微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。

可以认为:

限流是对服务的保护,避免因瞬间高并发流量而导致服务故障,进而避免雪崩。是一种预防措施。

超时处理、线程隔离、降级熔断是在部分服务故障时,将故障控制在一定范围,避免雪崩。是一种补救措施。

解决雪崩问题的常见方式有四种:

  • 超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待

  • 舱壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。

  • 熔断降级:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。

  • 流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

二、初识Sentinel

在SpringCloud当中支持多种服务保护技术:

  • Netfix Hystrix
  • Sentinel
  • Resilience4J

早期比较流行的是Hystrix框架,但目前国内实用最广泛的还是阿里巴巴的Sentinel框架,这里我们做下对比:

SentinelHystrix
隔离策略信号量隔离线程池隔离/信号量隔离
熔断降级策略基于慢调用比例或异常比例基于失败比率
实时指标实现滑动窗口滑动窗口(基于 RxJava)
规则配置支持多种数据源支持多种数据源
扩展性多个扩展点插件的形式
基于注解的支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持
流量整形支持慢启动、匀速排队模式不支持
系统自适应保护支持不支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix
https://sentinelguard.io/zh-cn/index.html
https://github.com/alibaba/Sentinel

Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:https://sentinelguard.io/zh-cn/index.html

Sentinel 具有以下特征:

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

image-20240827210841757

三、微服务整合Sentinel

3.1、改POM

 <dependencies><!--sentinel--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>

image-20240827214826617

3.2、写YAML

server:port: 9001spring:application:name: sentinelservicecloud:nacos:discovery:server-addr: 192.168.200.129:8848 #配置Nacos地址sentinel:transport:dashboard: 192.168.200.129:8858 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

image-20240827215202688

3.3、主启动

package com.sentinel.service;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** @Author: 史小创* @Time: 2024/8/27 下午9:43* @Description:*/@SpringBootApplication
@EnableDiscoveryClient
public class SentinelServiceApplication {public static void main(String[] args) {SpringApplication.run(SentinelServiceApplication.class, args);}
}

image-20240827215302783

3.4、测试

image-20240827215421736

image-20240827215459305

原因:Sentinel采用的为懒加载的模式。想使用Sentinel对某个接口进行限流和降级等操作,一定要先访问下接口,使Sentinel检测出相应的接口

http://localhost:9001/testA
http://localhost:9001/testB

image-20240827215846359

四、实战:流控规则

4.1、概述

image-20240827220426995

Sentinel能够对流量进行控制,主要是监控应用的QPS流量或者并发线程数等指标,如果达到指定的阈值时,就会被流量进行控制,以避免服务被瞬时的高并发流量击垮,保证服务的高可靠性。参数见最下方:

序号名称含义
1资源名资源的唯一名称,默认就是请求的接口路径,可以自行修改,但是要保证唯一。
2针对来源具体针对某个微服务进行限流,默认值为default,表示不区分来源,全部限流。
3阈值类型QPS表示通过QPS进行限流,并发线程数表示通过并发线程数限流。
4单机阈值与阈值类型组合使用。如果阈值类型选择的是QPS,表示当调用接口的QPS达到阈值时,进行限流操作。如果阈值类型选择的是并发线程数,则表示当调用接口的并发线程数达到阈值时,进行限流操作。
5是否集群选中则表示集群环境,不选中则表示非集群环境。

4.2、流控模式

image-20240827220951390

在添加限流规则时,点击高级选项,可以选择三种流控模式

  • 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
  • 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
  • 链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

4.2.1、直连

默认的流控模式,当接口达到限流条件时,直接开启限流功能。

image-20240827221313582

image-20240827221330218

表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

http://localhost:9001/testA

1

Blocked by Sentinel (flow limiting) 这样的方式貌似太丑,能否有美观一点呢

4.2.2、关联

关联模式:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流

使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是优先支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流。

简单讲:当关联的资源达到阈值时,就限流自己。当与A关联的资源B达到阀值后,就限流A自己B惹事,A挂了。

image-20240827222328595

image-20240827222442555

当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名,B惹事,A挂了

http://localhost:9001/testB
http://localhost:9001/testA

2

小结:

满足下面条件可以使用关联模式:

  • 两个有竞争关系的资源
  • 一个优先级较高,一个优先级较低

4.2.3、链路

链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。

来自不同链路的请求对同一个目标访问时,实施针对性的不同限流措施,比如C请求来访问就限流,D请求来访问就是OK

web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路

image-20240827223822595

package com.sentinel.service.service;import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;/*** @Author: 史小创* @Time: 2024/8/27 下午10:43* @Description:*/@Service
public class FlowLimitService {@SentinelResource(value = "common")public void common() {System.out.println("------FlowLimitService come in");}
}

image-20240827224459534

 /*** 流控-链路演示demo* C和D两个请求都访问flowLimitService.common()方法,阈值到达后对C限流,对D不管*/@Resourceprivate FlowLimitService flowLimitService;@GetMapping("/testC")public String testC() {flowLimitService.common();return "------testC";}@GetMapping("/testD")public String testD() {flowLimitService.common();return "------testD";}

image-20240827224607692

image-20240827224717762

image-20240827224837210

http://localhost:9001/testC
http://localhost:9001/testD

5

4.3、流控效果

在流控的高级选项中,还有一个流控效果选项:

image-20240827225952576

流控效果是指请求达到流控阈值时应该采取的措施,包括三种:

  • 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。

  • warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。

  • 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

4.3.1、快速失败

4.3.2、预热Warm up

https://github.com/alibaba/Sentinel/wiki/Flow-Control:-Warm-Up
https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8

image-20240828080826894

阈值一般是一个微服务能承担的最大QPS,但是一个服务刚刚启动时,一切资源尚未初始化(冷启动),如果直接将QPS跑到最大值,可能导致服务瞬间宕机。

warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是 maxThreshold / coldFactor,持续指定时长后,逐渐提高到maxThreshold值。而coldFactor的默认值是3.

例如,我设置QPS的maxThreshold为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,也就是3,然后在5秒后逐渐增长到10.

image-20240828080911618

如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

image-20240828081044514

https://github.com/alibaba/Sentinel/blob/1.8/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/WarmUpController.java

image-20240828081219370

默认 coldFactor 为 3,即请求QPS从(threshold / 3) 开始,经多少预热时长才逐渐升至设定的 QPS 阈值。
案例,单机阈值为10,预热时长设置5秒。
系统初始化的阈值为10 / 3 约等于3,即单机阈值刚开始为3(我们人工设定单机阈值是10,sentinel计算后QPS判定为3开始);
然后过了5秒后阀值才慢慢升高恢复到设置的单机阈值10,也就是说5秒钟内QPS为3,过了保护期5秒后QPS为10

image-20240828081428677

image-20240828081601147

http://localhost:9001/testB

3

image-20240828082156779

4.3.3、排队等待

当请求超过QPS阈值时,快速失败和warm up 会拒绝新的请求并抛出异常。

而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

工作原理

例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待时长超过2000ms的请求会被拒绝并抛出异常。

那什么叫做预期等待时长呢?

比如现在一下子来了12 个请求,因为每200ms执行一个请求,那么:

  • 第6个请求的预期等待时长 = 200 * (6 - 1) = 1000ms
  • 第12个请求的预期等待时长 = 200 * (12-1) = 2200ms

现在,第1秒同时接收到10个请求,但第2秒只有1个请求,此时QPS的曲线这样的:

image-20240828082324502

如果使用队列模式做流控,所有进入的请求都要排队,以固定的200ms的间隔执行,QPS会变的很平滑:

image-20240828082358536

平滑的QPS曲线,对于服务器来说是更友好的。

@GetMapping("/testE")public String testE() {System.out.println(System.currentTimeMillis() + "      testE,排队等待");return "------testE";}

image-20240828082554438

http://localhost:9001/testE

image-20240828083318096

4

image-20240828083731619

4.4.4、总结

流控效果有哪些?

  • 快速失败:QPS超过阈值时,拒绝新的请求

  • warm up: QPS超过阈值时,拒绝新的请求;QPS阈值是逐渐提升的,可以避免冷启动时高并发导致服务宕机。

  • 排队等待:请求会进入队列,按照阈值允许的时间间隔依次执行请求;如果请求预期等待时长大于超时时间,直接拒绝

4.4、线程隔离(舱壁模式)

线程隔离有两种方式实现:

  • 线程池隔离

  • 信号量隔离(Sentinel默认采用)

如图:

image-20240828232857421

线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果

信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。

两者的优缺点:

image-20240828232923471

用法说明

在添加限流规则时,可以选择两种阈值类型:

image-20240828232953989

  • QPS:就是每秒的请求数,在快速入门中已经演示过

  • 线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现线程隔离(舱壁模式)。

实操

image-20240828233245078

image-20240828233952370

Jmeter给它打满了,大部分我们自己访问都不好使,偶尔Jmeter线程切换系统判定没访问,我们自己的点击才有点机会

五、实战:熔断规则

熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

断路器控制熔断和放行是通过状态机来完成的:

image-20240828090457975

状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
  • open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
    • 请求成功:则切换到closed状态
    • 请求失败:则切换到open状态

断路器熔断策略有三种:慢调用、异常比例、异常数

https://sentinelguard.io/zh-cn/docs/circuit-breaking.html
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

image-20240828090248426

5.1、慢调用

慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

/*** 新增熔断规则-慢调用比例** @return*/@GetMapping("/testF")public String testF() {// 暂停几秒钟线程try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("----测试:新增熔断规则-慢调用比例 ");return "------testF 新增熔断规则-慢调用比例";}

image-20240828091326594

image-20240828091640919

名词解释:

进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数 且 实际慢调用比例>比例阈值 ,进入熔断状态。

1.调用:一个请求发送到服务器,服务器给与响应,一个响应就是一个调用。

2.最大RT:即最大的响应时间,指系统对请求作出响应的业务处理时间。

3.慢调用:处理业务逻辑的实际时间>设置的最大RT时间,这个调用叫做慢调用。

4.慢调用比例:在所以调用中,慢调用占有实际的比例=慢调用次数➗总调用次数

5.比例阈值:自己设定的 , 比例阈值=慢调用次数➗调用次数

6.统计时长:时间的判断依据

7.最小请求数:设置的调用最小请求数,上图比如1秒钟打进来10个线程(大于我们配置的5个了)调用被触发

触发条件+熔断状态:

1熔断状态(保险丝跳闸断电,不可访问):在接下来的熔断时长内请求会自动被熔断

2探测恢复状态(探路先锋):熔断时长结束后进入探测恢复状态

3结束熔断(保险丝闭合恢复,可以访问):在探测恢复状态,如果接下来的一个请求响应时间小于设置的慢调用 RT,则结束熔断,否则继续熔断。

5.2、异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

 /*** 新增熔断规则-异常比例** @return*/@GetMapping("/testG")public String testG() {System.out.println("----测试:新增熔断规则-异常比例 ");int age = 10 / 0;return "------testG,新增熔断规则-异常比例 ";}

image-20240828230336091

不配置Sentinel,对于int age=10/0,调一次错一次报错error,页面报【Whitelabel Error Page】或全局异常

配置Sentinel,对于int age=10/0,如符合如下异常比例启动熔断,页面报【Blocked by Sentinel (flow limiting)】

image-20240828230656770

image-20240828234558108

5.3、异常数

  /*** 新增熔断规则-异常数** @return*/@GetMapping("/testH")public String testH() {System.out.println("----测试:新增熔断规则-异常数 ");int age = 10 / 0;return "------testH,新增熔断规则-异常数 ";}

image-20240828232402712

image-20240828232525919

image-20240828234817139

六、SentinelResource注解

6.1、概述

SentinelResource是一个流量防卫防护组件注解,用于指定防护资源,对配置的资源进行流量控制、熔断降级等功能。

https://github.com/alibaba/Sentinel/blob/1.8/sentinel-core/src/main/java/com/alibaba/csp/sentinel/annotation/SentinelResource.java
package com.alibaba.csp.sentinel.annotation;import com.alibaba.csp.sentinel.EntryType;import java.lang.annotation.*;/*** 该注解用于定义 Sentinel 资源。*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {/*** @return Sentinel 资源的名称*/String value() default "";/*** @return 进入类型(入站或出站),默认为出站*/EntryType entryType() default EntryType.OUT;/*** @return 资源的分类(类型)* @自 1.7.0*/int resourceType() default 0;/*** @return 阻塞异常处理函数的名称,默认为空*/String blockHandler() default "";/*** 默认情况下,{@code blockHandler} 位于与原方法相同的类中。* 但是,如果某些方法具有相同的签名并且打算设置相同的阻塞处理程序,* 则用户可以设置阻塞处理程序所在的类。注意,阻塞处理程序方法必须是静态的。** @return 阻塞处理程序所在的类,不应提供多个类*/Class<?>[] blockHandlerClass() default {};/*** @return 回退函数的名称,默认为空*/String fallback() default "";/*** {@code defaultFallback} 用作默认的通用回退方法。* 它不应接受任何参数,并且返回类型应与原方法兼容。** @return 默认回退方法的名称,默认为空* @自 1.6.0*/String defaultFallback() default "";/*** 默认情况下,{@code fallback} 位于与原方法相同的类中。* 但是,如果某些方法具有相同的签名并且打算设置相同的回退,* 则用户可以设置回退函数所在的类。注意,共享的回退方法必须是静态的。** @return 回退方法所在的类(仅单个类)* @自 1.6.0*/Class<?>[] fallbackClass() default {};/*** @return 要跟踪的异常类列表,默认是 {@link Throwable}* @自 1.5.1*/Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};/*** 指示要忽略的异常。注意,{@code exceptionsToTrace} 和 {@code exceptionsToIgnore}* 不应同时出现,否则 {@code exceptionsToIgnore} 将具有更高优先级。** @return 要忽略的异常类列表,默认为空* @自 1.6.0*/Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

当请求进入微服务时,首先会访问DispatcherServlet,然后进入Controller、Service、Mapper,这样的一个调用链就叫做簇点链路。簇点链路中被监控的每一个接口就是一个资源

默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint,也就是controller中的方法),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。

image-20240828141700276

流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则:

  • 流控:流量控制
  • 降级:降级熔断
  • 热点:热点参数限流,是限流的一种
  • 授权:请求的权限控制

6.2、按照rest地址限流+默认限流返回

通过访问res地址来限流,会返回Sentinel自带默认的限流处理信息。

package com.sentinel.service.web;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @Author: 史小创* @Time: 2024/8/28 下午2:20* @Description:*/@RestController
public class RateLimitController {@GetMapping("/rateLimit/byUrl")public String byUrl() {return "按rest地址限流测试OK";}
}

image-20240828142422182

先访问一下:

http://localhost:9001/rateLimit/byUrl

image-20240828142614726

image-20240828142921795

image-20240828142752072

http://localhost:9001/rateLimit/byUrl

6

6.3、按SentinelResource资源名称限流+自定义限流返回

不想用默认的限流提示(Blocked by Sentinel (flow limiting)),想返回自定义限流的提示

@GetMapping("/rateLimit/byResource")@SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleException")public String byResource() {return "按资源名称SentinelResource限流测试OK";}public String handleException(BlockException exception) {return "服务不可用@SentinelResource启动" + "\t" + "o(╥﹏╥)o";}

image-20240828143408207

http://localhost:9001/rateLimit/byResource

image-20240828143837999

image-20240828143943693

http://localhost:9001/rateLimit/byResource

7

6.4、按SentinelResource资源名称限流+自定义限流返回+服务降级处理

按SentinelResource配置,点击超过限流配置返回自定义限流提示+程序异常返回fallback服务降级

 @GetMapping("/rateLimit/doAction/{p1}")@SentinelResource(value = "doActionSentinelResource",blockHandler = "doActionBlockHandler", fallback = "doActionFallback")public String doAction(@PathVariable("p1") Integer p1) {if (p1 == 0) {throw new RuntimeException("p1等于零直接异常");}return "doAction";}public String doActionBlockHandler(@PathVariable("p1") Integer p1, BlockException e) {System.err.printf("sentinel配置自定义限流了:{}", e);return "sentinel配置自定义限流了";}public String doActionFallback(@PathVariable("p1") Integer p1, Throwable e) {System.err.printf("程序逻辑异常了:{}", e);return "程序逻辑异常了" + "\t" + e.getMessage();}

image-20240828144947872

http://localhost:9001/rateLimit/doAction/99

image-20240828145241809

image-20240828145424387

image-20240828145538861

image-20240828145554556

http://localhost:9001/rateLimit/doAction/99
http://localhost:9001/rateLimit/doAction/0

8

七、实战:热点规则

7.1、概述

热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

image-20240828151135470

7.2、全局参数限流

方法testHotKey里面第一个参数P1只要QPS超过每秒1次,马上降级处理

 @GetMapping("/testHotKey")@SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey")public String testHotKey(@RequestParam(value = "p1", required = false) String p1,@RequestParam(value = "p2", required = false) String p2) {return "------testHotKey";}public String dealHandler_testHotKey(String p1, String p2, BlockException exception) {return "-----dealHandler_testHotKey";}

image-20240828152207986

http://localhost:9001/testHotkey

image-20240828152622745

image-20240828152657339

image-20240828152741465

限流模式只支持QPS模式,固定写死了。(这才叫热点)

@SentinelResource注解的方法参数索引,0代表第一个参数,1代表第二个参数,以此类推

单机阀值以及统计窗口时长表示在此窗口时间超过阀值就限流。

上面的抓图就是第一个参数有值的话,1秒的QPS为1,超过就限流,限流后调用dealHandler_testHotKey支持方法。

http://localhost:9001/testHotkey?p1=abc
http://localhost:9001/testHotkey?p1=abc
http://localhost:9001/testHotKey?p2=99

9

7.3、测试例外项(热点参数限流)

上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流

我们期望p1参数当它是某个特殊值时,到达某个约定值后【普通正常限流】规则突然例外、失效了,它的限流值和平时不一样,假如当p1的值等于5时,它的阈值可以达到200或其它值

image-20240828173838436

image-20240828173941007

http://localhost:9001/testHotKey?p1=abc
http://localhost:9001/testHotKey?p1=5

10

注意:热点参数的注意点,参数必须是基本类型或者String

image-20240828174347473

八、实战:授权规则

8.1、概述

https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6%E8%A7%84%E5%88%99-authorityrule

image-20240828181035196

在Sentinel的授权规则中,提供了 白名单与黑名单 两种授权类型。白放行、黑禁止

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。

  • 白名单:来源(origin)在白名单内的调用者允许访问

  • 黑名单:来源(origin)在黑名单内的调用者不允许访问

点击左侧菜单的授权,可以看到授权规则:

image-20240828181207484

  • 资源名:就是受保护的资源,例如/order/{orderId}

  • 流控应用:是来源者的名单,

    • 如果是勾选白名单,则名单中的来源被许可访问。
    • 如果是勾选黑名单,则名单中的来源被禁止访问。

比如:

image-20240828181229237

我们允许请求从gateway到order-service,不允许浏览器访问order-service,那么白名单中就要填写网关的来源名称(origin)

8.2、代码

package com.sentinel.service.web;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @Author: 史小创* @Time: 2024/8/28 下午6:13* @Description: Empower授权规则,用来处理请求的来源*/@RestController
public class EmpowerController {@GetMapping(value = "/empower")public String requestSentinel4() {System.err.println("测试Sentinel授权规则empower");return "Sentinel授权规则";}
}
package com.sentinel.service.handler;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;/*** @Author: 史小创* @Time: 2024/8/28 下午6:15* @Description:*/@Component
public class MyRequestOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {return request.getParameter("serverName");}
}

image-20240828181928270

8.3、测试

http://localhost:9001/empower

image-20240828182750123

http://localhost:9001/empower?serverName=abc
http://localhost:9001/empower?serverName=test2
http://localhost:9001/empower?serverName=test

11

九、规则持久化

image-20240828192641430

现在,sentinel的所有规则都是内存存储,重启后所有规则都会丢失。在生产环境下,我们必须确保这些规则的持久化,避免丢失。

9.1、规则管理模式

规则是否能持久化,取决于规则管理模式,sentinel支持三种规则管理模式:

  • 原始模式:Sentinel的默认模式,将规则保存在内存,重启服务会丢失。

  • pull模式

  • push模式

9.2、pull模式

pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。

image-20240828183231650

9.3、push模式

push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。

image-20240828183306153

9.4、改POM

 <!--SpringCloud ailibaba sentinel-datasource-nacos --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>

image-20240828185546463

9.5、写Yaml

      datasource:ds1:nacos:server-addr: 192.168.200.129:8848dataId: ${spring.application.name}groupId: DEFAULT_GROUPdata-type: jsonrule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType

image-20240828190858764

跟踪rule-type: flow

image-20240828193458457

image-20240828193516164

image-20240828193953165

public enum RuleType {FLOW("flow", FlowRule.class),DEGRADE("degrade", DegradeRule.class),PARAM_FLOW("param-flow", ParamFlowRule.class),SYSTEM("system", SystemRule.class),AUTHORITY("authority", AuthorityRule.class),GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
}
枚举常量含义作用
FLOW限流规则控制应用的QPS(每秒查询率),限制系统流量以避免过载。
DEGRADE熔断降级规则当响应时间过长或错误率过高时,触发降级,临时阻断流量以保护系统。
PARAM_FLOW热点参数限流规则针对特定参数值进行限流,例如限制某个用户或IP的访问频率。
SYSTEM系统规则根据CPU使用率、内存等指标调整流控策略,保护系统整体稳定性。
AUTHORITY授权规则基于黑白名单控制访问权限,限制特定来源的流量。
GW_FLOW网关流控规则针对API网关的流量控制规则,细粒度控制通过网关的流量。
GW_API_GROUP网关API分组规则将API进行分组管理,定义一组API的流量控制策略。

image-20240828194134734

我想多数据源配置呢??

spring:application:name: sentinel-projectcloud:nacos:discovery:# Nacos服务注册中心地址server-addr: 10.20.30.227:9999sentinel:transport:# 配置Sentinel dashboard地址dashboard: 10.20.30.94:8080# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口port: 8719datasource:# sentinel持久化配置ds1:# 你是自定义key, 也可以做限流类型等nacos:server-addr: 10.20.30.227:9999  # nacos地址dataId: flow # 你是nacos配置里面的groupId: DEFAULT_GROUP # 就是nacos配置里面的data-type: json # 你是nacos配置里面的rule-type: flow # 也以为流量规则, 具体类型见com.alibaba.cloud.sentinel.datasource.RuleTypeds2:# 你是自定义key, 也可以做限流类型等nacos:server-addr: 10.20.30.227:9999  # nacos地址dataId: degrade # 你是nacos配置里面的groupId: DEFAULT_GROUP # 就是nacos配置里面的data-type: json # 你是nacos配置里面的rule-type: degrade # 也以为熔断降级规则, 具体类型见com.alibaba.cloud.sentinel.datasource.RuleType

9.6、Nacos配置

[{"resource": "/rateLimit/byUrl","limitApp": "default","grade": 1,"count": 1,"strategy": 0,"controlBehavior": 0,"clusterMode": false}
]
字段名称含义
resource资源名称
limitApp来源应用
grade阈值类型,0表示线程数,1表示QPS
count单机阈值
strategy流控模式,0表示直接,1表示关联,2表示链路
controlBehavior流控效果,0表示快速失败,1表示Warm Up,2表示排队等待
clusterMode是否集群

image-20240828191100628

image-20240828191349365

9.7、测试

重启服务后一定要多刷几次就出来了哈:

http://localhost:9001/rateLimit/byUrl

12

十、OpenFeign和Sentinel集成实现fallback服务降级

SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。

先降低版本:

image-20240828215517583

 <spring.boot.version>3.0.9</spring.boot.version><spring.cloud.version>2022.0.2</spring.cloud.version>

image-20240828215605331

10.1、服务的提供者

image-20240828220055880

101.1、YAML

server:port: 9001spring:application:name: sentinelprovidercloud:nacos:discovery:server-addr: 192.168.200.129:8848 #配置Nacos地址sentinel:transport:dashboard: 192.168.200.129:8858 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

10.1.2、主启动

package com.sentinel.provider;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** @Author: 史小创* @Time: 2024/8/28 下午7:56* @Description:*/@SpringBootApplication
@EnableDiscoveryClient
public class SentinelProviderApplication {public static void main(String[] args) {SpringApplication.run(SentinelProviderApplication.class, args);}
}

10.1.3、业务类

package com.sentinel.provider.web;import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** @Author: 史小创* @Time: 2024/8/28 下午8:12* @Description:*/@RestController
public class SentinelProviderController {@GetMapping("/rateLimit/doAction/{p1}")@SentinelResource(value = "doActionSentinelResource", blockHandler = "doActionBlockHandler")public String doAction(@PathVariable("p1") Integer p1) {if (p1 == 0) {throw new RuntimeException("p1等于零直接异常");}return "doAction";}public String doActionBlockHandler(@PathVariable("p1") Integer p1, BlockException e) {System.err.printf("sentinel配置自定义限流了:{}", e);return "sentinel配置自定义限流了";}
}

10.1.4、测试

http://localhost:9001/rateLimit/doAction/1

image-20240828215929074

10.2、OpenFeign

image-20240828220328978

 <dependencies><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>
package com.sentinel.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "sentinelprovider", fallback = FeignSentinelApiFallBack.class)
public interface SentinelApi {@GetMapping("/rateLimit/doAction/{p1}")public String doAction(@PathVariable("p1") Integer p1);}
package com.sentinel.feign;import org.springframework.stereotype.Component;/*** @Author: 史小创* @Time: 2024/8/28 下午8:26* @Description: 统一服务降级类*/@Component
public class FeignSentinelApiFallBack implements SentinelApi {@Overridepublic String doAction(Integer p1) {return "对方服务宕机或不可用,FallBack服务降级o(╥﹏╥)o";}
}

10.3、服务消费者

10.3.1、POM

<dependencies><!-- 引入自己定义的api通用包 --><dependency><groupId>com.sentinel</groupId><artifactId>sentinel-feign</artifactId><version>1.0-SNAPSHOT</version></dependency><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>

10.3.2、YAML

server:port: 9002spring:application:name: sentinelconsumercloud:nacos:discovery:server-addr: 192.168.200.129:8848 #配置Nacos地址# 激活Sentinel对Feign的支持
feign:sentinel:enabled: true

10.3.3、主启动

package com.sentinel.consumer;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;/*** @Author: 史小创* @Time: 2024/8/28 下午7:56* @Description:*/@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.sentinel.feign")
@ComponentScan("com.sentinel")
public class SentinelConsumerApplication {public static void main(String[] args) {SpringApplication.run(SentinelConsumerApplication.class, args);}
}

10.3.4、业务类

package com.sentinel.consumer.web;import com.sentinel.feign.SentinelApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;/*** @Author: 史小创* @Time: 2024/8/28 下午8:33* @Description:*/@RestController
public class SentinelConsumerController {@Autowiredprivate SentinelApi sentinelApi;@GetMapping("/rateLimit/doAction/{p1}")public String doAction(@PathVariable("p1") Integer p1) {return sentinelApi.doAction(p1);}
}

10.3.5、测试

http://localhost:9002/rateLimit/doAction/1
http://localhost:9002/rateLimit/doAction/0

image-20240828220727389

image-20240828220738700

10.4、整合Sentinel

image-20240828220913600

image-20240828220931509

image-20240828220940379

http://localhost:9002/rateLimit/doAction/1
http://localhost:9002/rateLimit/doAction/0

13

10.5、版本复原

image-20240828224525489

十一、GateWay和Sentinel集成实现服务限流

image-20240828224653700

11.1、POM

Spring Cloud Gateway确实是基于Spring WebFlux的反应式框架构建的。因此,通常情况下,不需要也不应该同时包含spring-boot-starter-web依赖,因为spring-boot-starter-web是基于Servlet API的,而Spring WebFlux是基于反应式堆栈的。这两者使用不同的底层模型,不适合一起使用。

  <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

image-20240828224734361

<dependencies><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.6</version></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>1.8.6</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency></dependencies>

image-20240828224845723

11.2、YAML

server:port: 8888spring:application:name: sentinelgateway     # sentinel+gataway整合Casecloud:nacos:discovery:server-addr: 192.168.200.129:8848gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: lb://sentinelprovider            #匹配后提供服务的路由地址predicates:- Path=/rateLimit/doAction/**                      # 断言,路径相匹配的进行路由

11.3、启动

package com.sentinel.gateway;import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** @Author: 史小创* @Time: 2024/8/28 下午10:19* @Description:*/@SpringBootApplication
@EnableDiscoveryClient
public class SentinelGatewayApplication {public static void main(String[] args) {org.springframework.boot.SpringApplication.run(SentinelGatewayApplication.class, args);}
}

11.4、配置类

https://sentinelguard.io/zh-cn/docs/api-gateway-flow-control.html

image-20240828225407856

package com.sentinel.gateway.config;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.*;/*** @Author: 史小创* @Time: 2024/8/28 下午10:24* @Description:*/@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {// Register the block exception handler for Spring Cloud Gateway.return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}@Bean@Order(-1)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}@PostConstructpublic void doInit() {// 自己动手,丰衣足食// initGatewayRules();initBlockHandler();}// 处理+自定义返回的例外信息内容,类似我们的调用触发了流控规则保护private void initBlockHandler() {Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("pay_routh1").setCount(2).setIntervalSec(1));GatewayRuleManager.loadRules(rules);BlockRequestHandler handler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {Map<String, String> map = new HashMap<>();map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)");return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));}};GatewayCallbackManager.setBlockHandler(handler);}
}

11.5、测试

http://localhost:8888/rateLimit/doAction/1

14

十二、环境搭建

SpringBoot+SpringCloud

   <spring.boot.version>3.2.0</spring.boot.version><spring.cloud.version>2023.0.0</spring.cloud.version><spring.cloud.alibaba.version>2022.0.0.0</spring.cloud.alibaba.version>

docker

image-20240827194204811

Nacos

docker pull nacos/nacos-server:v2.0.3
docker run --env MODE=standalone --name nacos --restart=always -d -p 8848:8848 -p 9848:9848 -p 9849:9849 -e JVM_XMS=512m -e JVM_XMX=512m -v /opt/nacos:/home/nacos/nacos-server-2.0.3/nacos/standalone/data nacos/nacos-server:v2.0.3
http://192.168.200.129:8848/nacos/#/login

sentinel

docker pull bladex/sentinel-dashboard:1.8.6
docker run --name sentinel-dashboard --restart=always -p 8858:8858 -v /opt/sentinel:/opt/sentinel -d bladex/sentinel-dashboard:1.8.6
http://192.168.200.129:8858/#/login

jdk:

image-20240824171950942

Maven

image-20240823181810973

IDEA

image-20240823181906302

代码汇总:

https://github.com/shixiaochuangjob/markdownfile/tree/main/20240828

image-20240829000412781

https://mp.weixin.qq.com/s?__biz=MzkwOTczNzUxMQ==&mid=2247485129&idx=1&sn=6ff255ba38842473c025ada5ccd72182&chksm=c1376d81f640e49770514d2af99b21e9893c606c31fa9eefbd9483a9af3053901635d43a8c0e#rd

在这里插入图片描述

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

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

相关文章

RabbitMQ 集群与高可用性

目录 单节点与集群部署 1.1. 单节点部署 1.2. 集群部署 镜像队列 1.定义与工作原理 2. 配置镜像队列 3.应用场景 4. 优缺点 5. Java 示例 分布式部署 1. 分布式部署的主要目标 2. 典型架构设计 3. RabbitMQ 分布式部署的关键技术 4. 部署策略和实践 5. 分布式部署…

前端开发学习Docker记录01镜像操作

Docker相关命令 Demo安装nginx 先搜索然后拉取&#xff0c;然后查看images列表是不是拉取成功 docker search nginxdocker pull nginx特定某个版本&#xff0c;镜像名&#xff1a;版本号 docker images

layui2.9 树组件默认无法修改节点图标,修改过程记录下

官方文档树组件 data 参数值&#xff0c;未提供icon属性配置 需要修改源码 layui.js, 搜索图片中标记部分 查找到之后&#xff0c;修改为 <i class“‘(i.icon || “layui-icon layui-icon-file”)’”> 如图&#xff1a; 修改完成后&#xff0c;即可在data中添加icon…

redis学习笔记 ——redis中的四大特殊数据结构

一.前言 在之前的学习中&#xff0c;我们已经介绍了Redis中常见的五种基本的数据结构&#xff0c;而今天我们就要开始介绍Redis的四种特殊的数据结构&#xff0c;它们分别是bitmap(位图)&#xff0c; HyperLogLog(基数统计),Geospatial(地理信息),Stream。 二.位图(Bitmap) …

Windows安装PostgreSQL数据库,保姆级教程

PostgreSQL 是客户端/服务器关系数据库管理系统 (RDMS)。PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统&#xff08;RDBMS&#xff09;。PostgreSQL 也有自己的查询语言&#xff0c;称为 pgsql。 此外&#xff0c;PostgreSQL 还支持过程语言&a…

CS224W—07 Machine Learning with Heterogeneous Graphs

CS224W—07 Machine Learning with Heterogeneous Graphs 本节中&#xff0c;我们将学习如何在异构图中进行图神经网络学习。 Heterogeneous Graphs 图中的节点类型/边类型不同&#xff0c;就会形成一个异构图&#xff08;Heterogeneous Graph&#xff09;&#xff0c;例如下…

基于SpringBoot的在线答疑管理系统

基于SpringBootVue的在线答疑管理系统【附源码文档】、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 摘要 基于SpringBoot的在线答疑管理系…

如何使用IDEA搭建Mybatis框架环境(详细教程)

文章目录 ☕前言为什么学习框架技术Mybatis框架简介 &#x1f379;一、如何配置Mybatis框架环境1.1下载需要MyBatis的jar文件1.2部署jar文件1.3创建MyBatis核心配置文件configuration.xml1.4.创建持久类(POJO)和SQL映射文件1.5.创建测试类 &#x1f9cb;二、 MyBatis框架的优缺…

Linux下UDP编程

一.概念介绍 1.socket 是什么&#xff1f; socket&#xff08;套接字&#xff09;本质上是一个抽象的概念&#xff0c;它是一组用于网络通信的 API&#xff0c;提供了一种统一的接口&#xff0c;使得应用程序可以通过网络进行通信。在不同的操作系统中&#xff0c;socket 的实…

【Python系列】Jinja2 模板引擎

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【软件测试】软件测试生命周期与Bug

目录 &#x1f4d5; 前言 &#x1f334;软件测试的生命周期 ​编辑&#x1f332;BUG &#x1f6a9; 概念 &#x1f6a9;描述bug的要素 &#x1f6a9;bug的级别 &#x1f6a9;bug的生命周期 &#x1f3c0;先检查自身&#xff0c;是否bug描述不清楚 &#x1f3c0;站在用…

Docker 安装 SqlServer

摘要&#xff1a;我们工作当中经常需要拉取多个数据库实例出来做集群&#xff0c;做测试也好&#xff0c;通过 Docker 拉取 SqlServer 镜像&#xff0c;再通过镜像运行多个容器&#xff0c;几分钟就可以创建多个实例&#xff0c;效率是相当的高。 1. docker 拉取镜像 注意&am…

[mysql]mysql的演示使用

mysql的演示使用 几个常见操作 1&#xff1a;show databases 这里第一个information_schema代表的是数据库的基本系统信息&#xff0c;数据库名称&#xff0c;表的名称&#xff0c;存储权限 第二个是mysql&#xff0c;保存的是我们数据库运行的时候需要的系统信息&#xff0…

数据中台即将消亡,数智基建取而代之?

数据中台即将消亡&#xff0c;数智基建取而代之&#xff1f; 前言数智基建 前言 在当今数字化浪潮汹涌澎湃的时代&#xff0c;企业的发展如同在浩瀚海洋中航行的巨轮&#xff0c;而数据则是推动这艘巨轮前行的强大动力。然而&#xff0c;如何有效地管理和利用数据&#xff0c;…

Kafka3.x 使用 KRaft 模式部署 不依赖 ZooKeeper

前言 Kafka 从 2.8.0 版本开始引入了 Kafka Raft Metadata Mode&#xff08;KRaft 模式&#xff09;&#xff0c;这个模式允许 Kafka 在不依赖 ZooKeeper 的情况下进行元数据管理。KRaft 模式在 Kafka 3.0.0 中进入了稳定版本,本文部署的 Kafka_2.12-3.6.0 单机模式 环境 Ce…

工厂andon暗灯系统数字化应用案例

在当今数字化浪潮席卷制造业的时代&#xff0c;工厂的高效运作和精益管理离不开先进的技术手段。Andon 暗灯系统作为精益制造执行中的核心工具和 MES 制造执行系统的重要组成部分&#xff0c;正以其强大的功能为工厂带来全新的变革。 某汽车零部件制造工厂&#xff0c;拥有多条…

Java设计模式之策略模式详细讲解和案例示范

Java设计模式之策略模式详细讲解和案例示范 在软件开发中&#xff0c;策略模式是一种常见且非常有用的设计模式。它允许定义一系列算法&#xff0c;将它们一个个封装起来&#xff0c;并且使它们可以互相替换。策略模式让算法可以独立于使用它们的客户端而变化。本篇文章将详细…

[MySql]保姆级上手教程

介绍 通过数据库管理系统, 编写执行SQL语句, 实现对数据库数据的管理 数据库(DataBase): 储存和管理数据的仓库数据库管理系统(DBMS): 操作和管理数据库的软件SQL语言: 操作关系型数据库的通用语言数据库可以分为关系型数据库和非关系型数据库 相关产品 常见的关系型数据库产…

【golang-入门】环境配置、VSCode开发环境配置

golang介绍基础信息 windows环境配置安装包下载安装环境变量设置检查 VSCode开发配置插件配置在 Visual Studio Code 中安装通义灵码go hello word 参考资料 golang介绍 基础信息 golang官网&#xff1a;https://go.dev/golang学习网&#xff1a;https://studygolang.com/使用…

android使用YOLOV8数据返回到JAVA方法(JAVA)

一、下载扩展文件(最耗时,所以放第一步) 1.opencv下载 1)官网:Releases - OpenCV 2)下载最新版本的android包 2.NCNN下载 1)NCNN下载地址(20220420版本):https://github.com/Tencent/ncnn/releases/download/20220420/ncnn-20220420-android-vulkan.zip 3.在你的…