SpringCloud-11_Alibaba Sentinel

news2024/12/24 15:20:34

SpringCloud系列

SpringCloud-10_Alibaba Nacos

SpringCloud-9、Sleuth+Zipkin
SpringCloud-8、Gateway网关服务
SpringCloud-7_OpenFeign服务调用
SpringCloud-6_Ribbon负载均衡
SpringCloud-5_模块集群化

求帮助

  • 富文本编辑器用着真伤心TT。。不知道编辑器发生了什么。。---  用不了, ``` 也用不了
  • 看了之前的格式,发现原先用的,既不属于富文本编辑器,也不属于MarkDown编辑器,但是是什么找不到了。。

Sentinel基础

官网

Github:https://github.com/alibaba/Sentinel
中文-快速开始:
https://sentinelguard.io/zh-cn/docs/quick-start.html

中文-alibaba手册介绍:
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
英文-使用手册(Spring Cloud Alibaba Reference Documentation):
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel


Sentinel是什么?

        中文翻译:哨兵

        作用:Sentinel:分布式系统的流量防卫兵,保护你的微服务

        随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。

        Sentinel特征(绿色方框部分):

 开源生态:


Sentinel核心功能

流量控制


熔断降级

        在调用系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积
系统负载保护
        解读:
        熔断降级可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障


消息削峰填谷

        根据系统能够处理的请求,和允许进来的请求,来做平衡,追求的目标是在系统不被拖垮的情况下,提高系统的吞吐率

- 某瞬时来了大流量的请求,而如果此时要处理所有请求,很可能会导致系统负载过高,影响稳定性。但其实可能后面几秒之内都没有消息投递,若直接把多余的消息丢掉则没有充分利用系统处理消息的能力

- Sentinel的Rate Limiter模式能在某一段时间间隔内以匀速方式处理这样的请求,充分利用系统
的处理能力,也就是削峰填谷,保证资源的稳定性


Sentinel两个组成部分

核心库:
(Java客户端)不依赖任何框架/库,能够运行在所有Java运行时环境,对Spring Cloud有较好的支持

控制台:
(Dashboard)基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器


Sentinel控制台

需求分析/图解
        1.需求:搭建Sentinel控制台,用于显示各个微服务的使用情况
下载
        地址:https://github.com/alibaba/Sentinel/releases/tag/v1.8.0
运行
        放到待安装的位置,如:D:\Program Files\sentinel
        通过该位置的cmd指令:java -jar sentinel-dashboard-1.8.0.jar 。可以按Tab键补全文件名
        注意:Sentinel控制台默认端口是8080
访问
        浏览器:http://localhost:8080 ,访问控制台页面
        用户名和密码都是:sentinel
注意事项和细节
        如果8080端口被占用,可以使用--server.port=9999命令修改端口,格式如下:
        java -jar sentinel-dashboard-1.8.0.jar --server.port=9999
        9999可以替换成其他任意可用端口,最大不超过65535
        也可以使用cmd命令:netstat -anb | more 查看端口监听(Listening)状态。


Sentinel监控微服务

需求分析
        1. 需求:使用Sentinel控制台对member-service-nacos-provider-10004微服务进行实时监控
        2. 当调用了member-service-nacos-provider-10004微服务时,可以监控到请求的url/QPS/响应时间/流量

代码/配置实现
        找到member-service-nacos-provider-10004的pom.xml文件,引入sentinel客户端

        <!--引入alibaba-Sentinel-starter-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

配置application.yml

  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 #指定sentinel Dashboard控制台地址
        port: 8719 #默认端口就是8719

老师解读transport.port
1. transport.port端口配置会在被监控的微服务对应主机上启动Http Server
2. http Server会Sentinel控制台进行交互
3. 比如sentinel控制台添加了一个限流规则,会把规则数据push给这Http Server接收
Http Server再将这个规则注册到Sentinel中
4. 简单的讲:transport.port指定被监控的微服务应用于sentinel控制台交互的端口。
5. 默认端口是8719,假如被占用了,就会自动的从8719开始依次+1扫描,直到找到一个没有被占用的

测试步骤

启动Nacos Server8848。是cmd中启动的nacos Dashboard的端口
(Nacos不是必备选项。如不启动,需在pom.xml把它的端口地址等取消,避免一直报错)
启动Sentinel8080控制台/Sentinel dashboard
启a动member-service-nacos-provider-10004
浏览器:localhost:10004/member/get/1
Sentinel控制台监控页面

注意事项和细节

QPS:Queries Per Second(每秒查询率),是服务器每秒响应的查询次数
Sentinel采用的是懒加载,只有调用了某个接口/服务,才能看到监控数据


Sentinel流量控制

规则

 

对上图的解读
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentineli可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
        QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
        线程数:当调用该api的线程数达到阀值的时候,进行限流

        解读QPS和线程数的区别,注意听,比如QPS和线程我们都设置阈值为1
(1)对QPS而言,如果在1秒内,客户端发出了2次请求,就达到阈值,从而限流
(2)对线程数而言,如果在1秒内,客户端发出了2次请求,不一定达到线程限制的阈值,为什么呢?假设我们1次请求后台会创建一个线程,但是这个请求完成时间是0.1秒(可以视为该请求对应的线程存活0.1秒),所以当客户端第2次请求时(比如客户端是在0.3秒发出的),这时第1个请求的线程就己经结束

是否集群:不需要集群
流控模式:
        直接:api达到限流条件时,直接限流
        关联:当关联的资源达到阈值时,就限流自己
        链路:当从某个接口过来的资源达到限流条件时,开启限流
·流控效果:
        快速失败:直接失败,抛异常
        Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值
        排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

流量控制实例-QPS

需求分析/图解

1.需求:通过Sentinel实现流量控制
2.当调用member-service-nacos-provider-10004的/member/get/接口/API时,
限制1秒内最多访问1次,否则直接失败,抛异常。


配置实现步骤

需要先访问资源,sentinel里面才有内容显示:http://localhost:10004/member/query/1

 选“簇点链路”,再在对应的资源里面,找到操作“+流控”

 设置阈值,新增。

高级:

        流控模式:直接

        流控效果:快速失败


测试

启动Nacos Server 8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
浏览器:localhost:10004/member/get/1 。此时请求频率不超过1秒/次,则页面正常显示
Sentinel控制台监控页面


注意事项和细节

1.流量规则改动,实时生效,不需重启微服务,Sentine控制台
2.在sentinel配置流量规则时,如何配置通配符问题,比如/member/get/1与/member/get/2
统一使用一个规则
- 方案1:在sentinel中/member/get?id=1和/member/get?id=2被统一认为是
/member/get ,所以只要对/member/get限流就OK了。

//    @GetMapping("/member/query/{id}")
//    public Result selectById(@PathVariable("id")Long id){

//    修改为传递参数的方式,这样就可以在query一级整体限流。

    @GetMapping(value="/member/query",params="id")
    public Result selectById(Long id){

- 方案2:URL资源清洗
        可以通过UrlCleaner接口来实现资源清洗,也就是对于/member,/get尔id这个URL,我们可以统一归集到/member/get/*资源下,具体配置代码如下,实现UrlCleaner接口,并重写clean方法即可
        先恢复之前的@GetMapping("/member/query/{id}")访问方式

        创建controller/CustomUrlClean.java
 

@Component //作为组件注入到容器中。注意,没有不生效
public class CustomUrlClean implements UrlCleaner {
    @Override
    public String clean(String originUrl) {//参数获取url,比如/member/query/1
        //其实里面的算法都是为了返回一个在Sentinel_DashBoard里面的资源名
        //直接在Sentinel_DashBoard里面是不能修改的
        if(StringUtils.isBlank(originUrl)){
            return originUrl; //为空则返回
        }
        if(originUrl.startsWith("/member/query")){
            return "/member/query/*"; //此处加上通配符。最重要的功能就是这句
        }
        return originUrl;
    }
}

3.如果sentinel流控规则没有持久化,当我们重启调用API所在微服务模块后,规则会丢失,需要重新加入


流量控制实例-线程数

需求分析

1.需求:通过Sentinel实现流量控制
2.当调用member-service-nacos-provider-10004的/member/get/*接口/API时,限制只有一个工作线程,否则直接失败,抛异常。
(题外话:视频中出现打卡名字)

配置实现步骤

        同“流量控制实例-QPS”,把其中的“QPS”改为“线程数”即可

        “流控模式”选择“直接”。       
测试

1. 浏览器输入:http://localhost:10004/member/query/1,快速刷新,页面显示正常(原因是服务执行时间很短,刷新下一次的时候,启动的工作线程,己经完成)

2. 因为线程执行时间太短,为了看到效果,我们修改下com/stein/springcloud/controller/MemberController.java

@GetMapping(value ="/member/get/id)")
public Result getMemberByld(@PathVariable("id")Long id){
//让线程休眠1s,模拟执行时间
try{
    TimeUnit.MILLISECONDS.sleep(1000);
}catch(InterruptedException e){
    e.printStackTrace();
}
System.out.println("enter getMemberByld当前线程id="
+Thread.currentThread().getId()+"时间="+new Date());

3. 注意重启10004之后,限流规则又没有了,需要重新配置


注意事项和细节

1.当我们请求一次微服务的API接口时,后台会启动一个线程

代码:

2.阈值类型QPS和线程数的区别讨论
·如果一个线程平均执行时间为0.05秒,就说明在1秒钟,可以执行20次(相当于QPS为20)
·如果一个线程平均执行时间为1秒,说明1秒钟,可以执行1次数(相当于QPS为1) 
·如果一个线程平均执行时间为2秒,说明2秒钟内,才能执行1次请求。        

 
流量控制实例-关联

关联的含义

        当关联的资源达到阈值时,就限流自己

需求分析/图解

1.需求:通过Sentinel实现流量控制
2.当调用member-service-nacos-provider-10004的/t2 API接口时,如果QPS超过1,这时调用/t1 API接口直接接失败,抛异常。
        /t2是关联的资源,限流的资源是/t1


配置实现步骤

10004的memeber/Controller.java添加关联方法t1()和t2()

    @GetMapping("/t1")
    public Result t1(){
        return Result.success("t1()被执行。。。");
    }

    @GetMapping("/t2")
    public Result t2(){
        return Result.success("t2()被执行。。。");
    }

先访问t1和t2,才有“簇点链路”

新增限流规则


测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
Postman模拟高并发访问/t2

        1. 创建一个新的Request:File->New->Http Request

        2.填写要访问的地址:http://localhost:10004/t2,然后点save保存到collection

        3. 左下角,new Collection创建名为"sentinel"的集合,create->save

 

 create:

        4. 需要在集合sentinel后面的三个点,才能找到Run collection

         5.设置Iterations循环次数50次,延时Delay 200ms毫秒,然后Run sentinel运行

 在Run运行尚未结束前,用浏览器访问http://localhost:10004/t1,即可发现被限流了。

“Blocked by Sentinel (flow limiting)”

注意事项和细节

在postman执行高并发访问/t2没有结束时,去访问/代1才能看到流控异常出现


流量控制实例-Warm up

1.概述

当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

2. 示意图

梳理:
通常冷启动的过程系统允许通过的QPS曲线图(上图)
默认coldFactor为3,即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值
这里的threshold就是最终要达到的QPS阈值。

文档:
限流 冷启动 · alibaba/Sentinel Wiki · GitHub

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

Warm up称为冷启动/预热

应用场景:
秒杀在开启瞬间,大流量很容易造成冲垮系统,Warm up可慢慢的把流量放入,最终将阀值增长到设置阀值 

需求分析/图解

1. 需求:通过Sentinel实现流量控制,演示Warm up
2. 调用member-service-nacos-provider-10004的/t2API接口,将QPS设置为9,设置Warm
up值为3
3. 含义为请求/t2的QPS从threshold/3(9/3=3)开始,经预热时长(3秒)逐渐升至设定的QPS
阈值(9)
4. 为什么是9/3,这个是3就是默认冷启动启动加载因子coldFactor=3
5. 测试预期效果:在前3秒,如果访问/t2的QPS超过3,会直接报错,在3秒后访问/t2的QPS超过3,小于等于9,是正常访问


配置实现步骤

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
浏览器:localhost:10004/t2

注意事项和细节

1. 测试Warm up效果不是很好测,如果出不来可以尝试,调整流控规则:比如QPS为11,Warm up预热时间6秒
2. 如果请求停止(即:一段时间没有达到阈值),Warm up过程将重复,小伙伴可以理解是一个弹性过程


流量控制实例排队

排队介绍

1.排队方式:这种方式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法
2.一张图
3. 这种方式主要用于处理间隔性突发的流量,例如消息队列。比如这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。类似于之前的“削峰填谷”。

4.匀速排队,阈值必须设置为QPS


需求分析

1.需求:通过Sentinel实现流量控制
2.调用member-service-nacos-provider-10004的/t2 API接口,将QPS设置为1
3.当调用/t2的QPS超过1时,不拒绝请求,而是排队等待,依次执行
4.当等待时间超过10秒,则为等待超时。


修改业务类

修改t2()

    @GetMapping("/t2")
    public Result t2(){
        try {
            //执行1s的时间,便于测试排队
//            Thread.sleep(1000);//试一试这个应该也可以
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("T2()的当前线程id={}",Thread.currentThread().getId());
        return Result.success("t2()被执行。。。");
    }


配置实现步骤

1.为/t2增加流控规则

 

 注意这儿设计的逻辑:排队超时时间10s,阈值为1,每个线程执行时间>1s,那么第1-9个线程就会排队,第10个开始就会超时。

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
浏览器:localhost:10004/t2

        1.浏览器访问http://localhost:10004/t2快速刷新页面9次,观察前台/后台输出的情况
输出结果分析:
        没有报错误
        后台请求排队机行,每隔1s匀速执行

        2.浏览器访问http://localhost:10004/t2快速刷新页面20次,当请求等待时间超过10S,仍然出现流控异常:“Blocked by Sentinel (flow limiting)”

        小问题:可能是我的浏览器反应比较慢。没有出现因超时而被限流的情况,但是在IDEA后台,以及sentinel的DashBoard看到了消息队列是被匀速处理了的。


Sentinel熔断降级 

线程堆积引出熔断降级

1.除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。
2.例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
3.这时,我们对不稳定的服务进行熔断降级,让其快速返回结果,不要造成线程堆积

文档地址:circuit-breaking | Sentinel

基本介绍

功能解读:
    1. 现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
    2. 熔断,降级,限流三者的关系
-熔断强调的是服务之间的调用能实现自我恢复的状态
-限流是从系统的流量入口考虑,从进入的流量上进行限制,达到保护系统的作用
-降级,是从系统业务的维度考虑,流量大了或者频繁异常,可以牺牲一些非核心业务,保护核心流程正常使用
    梳理:
- 熔断是降级方式的一种
- 降级又是限流的一种方式
- 三者都是为了通过一定的方式在流量过大或者出现异常时,保护系统的手段

熔断策略

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。


熔断降级实例-慢调用比例

需求分析

1.需求:通过Sentinel实现熔断降级控制-慢调用比
2.当调用member-.service-nacos-provider-10004的/t3 API接口时,如果在1s内持续进入子5个
请求,并且请求的平均响应时间超过200s,那么就在未来10秒钟内,断路器打开,让/t3API接口微服务不可用
3.后面对/t3API接口访问降到1S内1个请求,降低访问量了,断路器关闭,微服务恢复


修改业务类:增加t3()方法

    @GetMapping("/t3")
    public Result t3(){
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Result.success("t3()被执行");
    }


配置实现步骤:

        注意是“降级”
        熔断时长的单位是:s 秒

RT最大响应时间的单位是ms毫秒,熔断时长的单位是s秒

新增后可以看到降级规则:
        

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
        浏览器访问:http://localhost:10004/t3
        快速访问6次,即可出现“Blocked by Sentinel (flow limiting)”
        过约10s秒,又会恢复访问
Postmani测试
        postman的设置同上一次;
        循环1000次。延时100ms,是让QPS达到10次,超过最小请求数5,便于产生熔断

运行后,可在浏览器访问 :http://localhost:10004/t3 ,有较小的概率能够访问进入,其余熔断。(题外话:这大概就是访问页面卡住时,我们喜欢不断刷新的原因吧)。

 注意事项和细节
1. 平均响应时间超出阈值且在1s内通过的请求>=5,两个条件同时满足后触发降级
2. 熔断时间过后,关闭断路器,访问恢复正常

熔断降级实例-异常比例

(题外话:又有打卡了^^)
需求分析/图解

1. 需求:通过Sentinel实现熔断降级控制
2. 当调用member-service-nacos-provider-10004的/t4 API接口时,当资源的每秒请求量
>=5,并且每秒异常总数占通过量的比值超过20%(即异常比例到20%),断路器打开(即:进入降级状态),让/t4 API接口微服务不可用
3. 当对/t4 API接口访问降到1S内1个请求,降低访问量了,断路器关闭,5秒后微服务恢复

修改业务类

    //做成静态的计数器,因为每一个线程都是单独,需要静态统一计数。
    public static int num=0;
    @GetMapping("/t4")
    public Result t4(){
        if(++num%2==0){
            //50%的概率发生运行时异常
            System.out.println(3/0);
        }
        log.info("t4()被运行,当前线程id={}",Thread.currentThread().getId());
        return Result.success("t4()被执行");
    }


配置实现步骤


测试
启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启a动member-service-nacos-provider-10004
Postman测试(用例设计)

1.postman循环次数和延时的设置,这样1s就发出10次请求QPS>5

2. 点击Run sentinel

3. 浏览器访问:http://localhost:10004/t4
        出现:“Blocked by Sentinel (flow limiting)”

4. 停止Postman

5. 超过熔断时长后。浏览器访问:http://localhost:10004/t4,结果正常了
        即一次返回异常,一次返回正确结果。

注意事项和细节

1. 当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值,资源进入降级状态,需要两个条件都满足
2. 测试时,如果熔断降级和恢复服务两个状态切换不明显,将时间窗口值调整大一点比如60,就OK了

熔断降级实例-异常数

需求分析

1.需求:通过Sentinel实现熔断降级控制-异常数
2.当调用member-service-nacos-provider-10004的/t5API接口时,当资源的每分钟请求量>=5,并且每分钟异常总数>=5,断路器打开(即:进入降级状态),让/t5 API接口微服务不可用
3.当熔断时间(比如20S)结束后,断路器关闭,微服务恢复修改业务类

修改业务类

        设置异常数10次,前5次在1分钟内发生,则第6次开始熔断
        如果在熔断时间达到后,执行的是第7-10次的异常(一定时间内),那么继续熔断
        如果已经执行到11次后,都是正常的,则不再熔断

    @GetMapping("/t5")
    public Result t5(){
        if(++num<=10){
            System.out.println(3/0);
        }
        log.info("测试异常数熔断,t5()的线程id={}",Thread.currentThread().getId());
        return Result.success("t5()被执行");
    }

配置实现步骤

异常数,是按照1分钟为单位来统计的。


测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
浏览器:http://localhost:10004/t5
        1.http://localhost:10004/t5,访问5次,出现5次异常(1分钟内完成)
        2.20S后,再次访问http://localhost:10004/t5,返回正常结果了

注意事项和细节

1. 资源在1分钟的异常数目超过阈值之后会进行熔断降级
2. 异常数统计是分钟级别的,若设置的熔断时间窗口小于60s,则结束熔断状态后仍可能再进入熔断状态,测试时,最好将熔断时间窗口设置超过60S

Sentinel热点规则

一个问题出热点key限流

1.热点:热点即经常访问的数据。很多时候我们希望统计热点数据中,访问频次最高的TopK数据,并对其访问进行限制。
2.比如某条新闻上热搜,在某段时间内高频访问,为了防止系统雪崩,可以对该条新闻进行热点限流

文档地址:热点参数限流 · alibaba/Sentinel Wiki · GitHub

基本介绍

上图解读:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
Sentinel利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控
令牌桶算法_AldarLin的博客-CSDN博客
热点参数限流支持集群模式 

热点Key限流-实例

需求分析

1.需求:通过Sentinel实现热点Key限流
2.对member-service-nacos-provider-10004的/news?id=x&type=x API接口进行热点限流
3.假定id=10这一条新闻是当前的热点新闻,当查询新闻时,对通常的id请求QPS限定为2,如果id=10 ,QPS限定为100
4.如果访问超出了规定的QPS,触发热点限流机制,调用自定义的方法,给出提示信息。
5.当对/news?id=x&type=x API接口降低访问量,QPS达到规定范围,服务恢复

修改业务类(热点限流的难点)

@SentinelResource注解及参数说明
    @SentinelResource指定触发限流时,需要访问的资源,即限流资源
    value= "news",表示限流资源的名称
    blockHandler = "newsBlockHandler",表示当出现限流时,由newsBlockHandler方法进行处理

    //访问新闻
    @GetMapping("/news")
    @SentinelResource(value= "news",blockHandler = "newsBlockHandler")
    public Result news(@RequestParam(value = "id",required = false)String id,
                       @RequestParam(value="type",required = false)String type){
        log.info("模拟去DB获取新闻信息");
        return Result.success("返回id="+id+"的新闻from DB");
    }


    //设定触发热点限流时的自定义方法
    public Result newsBlockHandler(String id, String type, BlockException blockException){
        return Result.success("查询id="+id+"的新闻 触发热点key限流保护,导致不能访问");
    }


测试

启动Nacos Server8848
启动Sentinel8o8o控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
配置实现步骤

 配置:
        终于在最后时刻看懂参数索引是啥意思了!
        经多次测试发现,是指(下面方法参数简写了)调用方法的参数位置索引:
public Result news(String id,String type)该方法的参数位置,比如0表示id,1表示type的意思。

参看配置好的规则

浏览器访问:http://localhost:10004/news?id=1&type=edu
        1.浏览器输入:http://localhost:10004/news?id=1&type=edu,如果QPS般有超过2,则返回正确结果
        2. 如果QPS超过2,则返回热点key处理信息

配置热点限流阈值,完成后“保存”

 再到“热点规则”选择“编辑”,点开“高级选项”,添加例外的热点规则。
 参数类型,这儿指的是"id"的参数类型是java.lang.String,这个需要根据自己的变量类型选择

1.浏览器输入:
http://localhost:10004/news?id=1&type=edu,如果QPS没有超过100,则返回正确结果

2.浏览器访问的d不是10的,仍然遵守QPS不能超过2的热点限制

个人体会:
        热点限流跟“流控”不一样。热点限流依然进入了10004的服务里面,只是不会走"/news"里面的代码,而是走的限流资源“newsBlockHandler”的代码。简单说,就是控制的粒度更细了,限制粒度到了方法层面。而不是熔断的服务层面。
        体现在显示页面上,热点限流返回的内容,是正常页面的格式,但是内容却是自定义的异常页面。而限流返回的是“Blocked by Sentinel (flow limiting)”

注意事项和细节

1. 热点参数类型是(byte/int/long/float/double/char/String)
2. 热点参数值,可以配置多个。例如:

3. 热点规则只对指定的参数生效,(比如本实例对id生效,对type不生效)。 


系统规则

一个问题引出系统规则

1.如我们系统最大性能能抗100QPS,如何分配/t1/t2的QPS?
2.方案1:/t1分配QPS=50 ;/t2 分配QPS=50,出现的问题,如果/t1当前QPS达到50,而/t2的QPS才10,会造成没有充分利用服务器性能。
3.方案2:/t1分配QPS=100/t2分配QPS=100,问题,容易造成系统没有流量保护,造成请求线程
堆积,形成雪崩。
4.有没有对各个资源请求的QPS弹性设置,只要总数不超过系统最大QPS的流量保护规则?
引出==>系统规则

文档地址:github官网/Documentation/wiki/文档/系统自适应限流
系统自适应限流 · alibaba/Sentinel Wiki · GitHub

一句话:系统规则作用,在系统稳定的前提下,保持系统的吞吐量

基本介绍

1.图示

2. 上图解读:

- 系统处理请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处理顺畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的;
- 反之,当请求堆积的时候,那么处理请求的时间则会变为:排队时间+最短处理时间

3.系统规则

- Load自适应(仅对Linux/Unix-like机器生效):系统的Ioad1作为启发指标,进行自适应系统保
护。当系统Ioad1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的maxQps*ninRt估算得出。设定参考值一般是CPU cores*2.5.
- CPU usage(1.5.0+版本):当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0),比较灵敏。
- 平均RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口QPS:当单台机器上所有入口流重的QPS达到阈值即触发系统保护。

实例

需求分析/图解

1.需求:通过Sentinel实现系统规则入口QPS
2.对member-service-nacos-provider-10004的所有API接口进行流量保护,不管访问哪个API接口,系统入口总的QPS不能大于2,大于2,就进行限流控制
3.提示:上面的QPS是为了方便看效果,设置的很小


配置实现步骤

1.新增入口QPS系统规则

点击新增

演示入口QPS阈值类型的保护

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启a动member-service-nacos-provider-10004
浏览器:

1. 浏览器输入:http://localhost:10004/t1,如果QPS超过2,打开断路器,返回流控信息

2.浏览器输入:http://localhost:10004/news?id=1&type=edu
如果QPS超过2,打开断路器,返回流控信息(说明:之所以选择t1,是因为项目的/t2资源对应方法有休眠代码,所以使用/news?id=x&type=x 测试)

通过一个设置,影响两个不同的API来体会系统QPS限流的作用。

测试结果,通过手动测不出来,原因是限流阈值为2,那么需要到3才会被限流,看“实时监控”的面板,我的点击的QPS最多到3(疑惑:还是超过了2呀,为什么临界值3出不来限流)。需要使用Postman配合,加大QPS访问量才测出来被限流了。

关于系统规则的个人体会:

        感觉入口QPS这类的限流是以系统为单位的,粒度比较大的限流方式。


@SentinelResource注解

自定义全局限流处理类

需求分析
1.回顾之前的@sentinelResource的相关代码(上面有)
说明:当配置的资源名news触发限流机制时,会调用newsBlogkHandler方法
2.上面的处理方案存在一些问题
· 每个@SentinelResource对应一个异常处理方法,会造成方法很多
· 异常处理方法和资源请求方法在一起,不利于业务逻辑的分离
· 解决方案->自定义全局限流处理类。
3.需求:请编写一个自定义全局限流处理类,完成对异常处理。

代码实现(重点/难点)

1. 创建handler/CustomGlobalBlockHandler.java

/**
 * 自定义全局限流处理类
 * 方法需要设为静态static,否则出错
 */
public class CustomGlobalBlockHandler {
    public static Result handlerMethod1(BlockException blockException){
        return Result.error("401","handlerMethod1()被调用");
    }
    public static Result handlerMethod2(BlockException blockException){
        return Result.error("402","handlerMethod2()被调用");
    }
}

2.对该全局处理类进行调用。controller/MemberController.java
 

    //测试自定义限流处理类
    @GetMapping("/t6")
    @SentinelResource(value="t6",
            blockHandlerClass = CustomGlobalBlockHandler.class,//引用类
            blockHandler = "handlerMethod2")//引用方法
    public Result t6(){
        return Result.success("t6()正常执行");
    }

配置实现步骤

1.先访问t6,产生流控信息后,便于设置

设置规则

 测试

 启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004
浏览器:
http://localhost:10004/t6 
可根据所配置的方法,进行灵活的响应。

fallback

看一段代码-引出fallback

        假定:当访问t6资源次数是5的倍数时,就出现了一个java的异常每5次抛出一次运行时异常

if(++num%5==0){
    throw new RuntimeException("num的值异常num="+num);
​​​​​​​}

这样,浏览器访问时,会有3种情况:

1.正常访问

2.限流

3.异常

通过fallback把2和3的处理整合到一起。

基本介绍

blockHandler只负责sentine控制台配置违规
fallback负责Java异常/业务异常

需求分析

需求:请编写一个自定义全局fallback处理类,处理java异常/业务异常

代码实现

先写一个异常处理类GlobalExceptionHandler,类似于上面的。同样,方法必须是静态static的。

再在t6的@SentinelResource()的参数中,添加fallbackClass=指向该类,fallback来调用具体的哪一个方法

测试

启动Nacos Server8848
启动Sentinela8080控制台/Sentinel dashboard
启动member-service-nacos-provider-10004

访问:
​​​浏览器输入:http://localhost:10004/t6,当访问次数是5的倍数,返回fallback指定方法信息
浏览器输入:http://localhost:10004/t6,如果访问QPS大于1,由blockHandler指定的方法处理,访问次数是5的倍数,由fallback指定方法处理,其它情况返回正常的结果。

exceptionsTolgnore

如果希望忽略某个异常,可以使用exceptionsTolgnore

应用实例

@SentinelResource(value ="t6",
                  fallbackClass = CustomGlobalFallbackHandler.class,
                  fallback = "fallbackHandlerMethod1",
                  blockHandlerclass = CustomGlobalBLockHandler.class,
                  blockHandler = "handlerMethodi",
                  exceptionsToIgnore = {RuntimeException.class})

接入Sentinel的方式

1.文档地址:介绍 · alibaba/Sentinel Wiki · GitHub

2.基本使用(具体见文档1.2对应的3步)
        STEP 1.在应用中引入Sentinel Jar包
        STEP 2.定义资源
        STEP 3.定义规则

代码方式(硬编码,侵入性强,不推荐)

        没看懂,因为不推荐,没有继续深入研究。

注解方式(低侵入性,前面用过,推荐)

        什么是埋点

        具体看文档,看文档,看文档。注解支持 · alibaba/Sentinel Wiki · GitHub

openFeign+sentinel对远程调用熔断降级

当前微服务基础环境

当前微服务环境架构图

示意图:

测试

启动Nacos Server8848

member-service-nacos-provider-10004/10006

        在application.yml里面,注销关于sentinel的配置,后期再加回来。

#    sentinel:
#      transport:
#        dashboard: localhost:8080 #指定sentinel Dashboard控制台地址
#        port: 8719 #默认端口就是8719

#配置暴露所有的监控点
#management:
#  endpoints:
#    web:
#      exposure:
#        include: '*'

启动member-service-nacos-consumer-80

注销10004的public Result selectById(@PathVariable("id")Long id)之前为了测试sentinel用的代码,不然会卡顿

//        try {
//            TimeUnit.MILLISECONDS.sleep(2000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

浏览器:
http://localhost/member/nacos/consumer/get/1,目前是Ribbon+RestTemplate
备注:localhost表示的是localhost:80,其中80是默认端口,所以在表示80时,可以省略

服务消费者整合Openfeign

解决的痛点:微服务之前进行调用,如何限流。区别于之前的通过浏览器直接调用微服务。

需求分析/图解

代码+配置实现步骤

1.consumer-80/pom.xml引入openfeign

        <!--引入openFeign,版本靠仲裁-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.创建consumer-80/service/MemberOpenFeignService.interface。配置调用路径

/注解没有填value的话,会报错:[classes/:na]
@FeignClient(value="member-service-nacos-provider")
public interface MemberOpenFeignService {
    /**解读
     * 1.远程调用方式是get
     * 2.远程调用urL为http://member-service-nacos-provider/member/get/{id}
     * 3.member.-service-nacos-provider.是hacos注册中心服务红
     * 4.openfeign会根据负载均衡算法来决定调用的是10004/10006,默认是轮询算法
     */
    @GetMapping("/member/query/{id}")
    public Result selectById(@PathVariable("id")Long id);
}

3.在controller里面

    @Resource
        private MemberOpenFeignService memberOpenFeignService;

    @GetMapping("/member/openfeign/consumer/query/{id}")
    public Result<Member> queryMember(@PathVariable("id")Long id){
        log.info("调用openFeign的queryMember()方法");
        return memberOpenFeignService.selectById(id);
    }

4.记得在Application添加开启OpenFeign的注解

@SpringBootApplication
@EnableDiscoveryClient //启动引入的Nacos发现
@EnableFeignClients//启用OpenFeign客户端
public class MemberNacosConsumerApplication80 {
    public static void main(String[] args) {
        SpringApplication.run(MemberNacosConsumerApplication80.class,args);
    }
}

测试

启动Nacos Server8848
member-service-nacos-provider-10004/10006
启动member-service-nacos-consumer-80
浏览器:
http://localhost/member/openfeign/consumer/query/1

服务消费者整合Sentinel

需求分析

1.需求:在member-service-nacos-consumer-80整合Sentinel 能被Sentinel监控

代码+配置实现步骤

1. consumer-80/pom.xml引入sentinel,然后刷新

        <!--引入sentinel,版本用仲裁-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2. 配置application.yml

    sentinel:
      transport:
        dashboard: localhost:8080 #sentinel控制台地址(dash board)
        port: 8719 #这是默认值,如果被占用,就+1,直到能用
#设置暴露所有的端点(监控点)
management:
  endpoints:
    web:
      exposure:
        include: '*'

测试: 查看consumer-80有没有被sentinel监控

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
member-service-nacos-provider-10004/10006
启动member-service-.nacos-consumer-80
浏览器:
http://localhost/member/openfeign/consumer/query/1
然后在sentinel dashboard 能够看到/member/openfeign/consumer/query/1的资源名

openFeign+sentinel对远程调用熔断降级

需求分析

1.需求/如图:在member-service-nacos-consumer-80调用某个无效服务时,启动Sentine的熔断降级机制,能够快速返回响应,而不是使用默认的超时机制(因为超时机制容易线程堆积,从而导致雪崩)


2.先测试一下,关闭10004/10006,这时openfeign去调用会怎么样?(返回time out)

3.还可以测试一下,让10004服务对应的API执行时间很长(比如休眠2秒),这时openfeign去调用会怎么样?(OpenFeign默认超时时间1秒钟)
        1.如果10004对应的API响应时间比10006明显长(将10004的代码执行休眠2秒)
        2.你发现openfeign+sentinel整合后,会自动选择响应时间短的服务
        3.这时总是调用10006的API 

代码+配置实现步骤

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
member-service-nacos-provider-10004/10006
启动member-.service-nacos-consumer-80
浏览器:
http://localhost/member/openfeign/consumer/query/1

注意事项和细节说明

1.因为nember-service-nacos-consumer-80己经被sentinel监控,所以我们可以加入相关的流控规则,比如为/member/openfeign/consumer/get/1加入流控规则qps=1

在member/openfeign/consumer/query/1 资源下,新增限流规则:

关闭10004/6这两个服务,测试会出现以下两种情况:
        1. 如果/member/openfeign/consumer/query/1请求QPS超过1,会输出:flow limiting(限流)
        2. QPS没有超过1,会被fallback处理。输出自己的设定。

如果恢复10004/6其中1个服务,那么访问时http://localhost/member/openfeign/consumer/query/1时,只会出现10004,而不会出现10006服务异常的信息。因为nacos检查到10006异常后,只会分配10004来提供服务。

规则持久化

规则没有持久化的问题

如果sentinel流控规则没有持久化,当重启调用API/接口所在微服务后,规则就会丢失,需要重新加入
解决方案:通过Nacos进行持久化(官方推荐方案)

规则持久化方案

阿里云Ahas[最方便/付费]

1.官方文档:
应用高可用服务 AHAS-阿里云帮助中心
√在Nacos Server配置规则,完成持久化-官方推荐
datasource支持nacos,redis,apollo,zk,file

Nacos Server配置中心-规则持久化实例

工作原理示意图

需求分析/图解

1.需求:为member-service-nacos-consumer-80微服务的/member/openfeign/consumer/query/1
API接口添加流控规则QPS=1/快速失败。
2.要求将该流控规则加入到nacos server配置中心,实现持久化

代码+配置实现步骤

1.在Nacos Server配置中心增加Sentinel客户端/微服务模块的流控规则

需要先运行nacos dashboard

再进入localhost:8848/nacos登录,找到 配置管理/配置列表(如下图),点击“+”加号新建

 新建配置,进行配置

 配置内容的代码:(细心!不要写错了)

[
    {
        "resource": "/member/openfeign/consumer/query/1",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

右下角“发布”,然后确定。

2.在Nacos Server配置中心增加Sentinel客户端/微服务模块的流控规则参数说明

resource:资源名称;
limlitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群
和上图各项,一一对应

3.pom.xml引入sentinel和nacos持久化整合的依赖

        <!--sentinel和nacos持久化整合依赖,版本用仲裁-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

4.修改member-service-nacos-consumer-80的application.yml,配置从nacos获取流控规则

      #对齐前面sentinel.transport的缩进
      datasource:
        ds1:
          #流控规则配置是从nacos server配置中心获取
          nacos:
            server-addr: localhost:8848 #nacos server配置中心地址
            dataId: member-service-nacos-consumer-80 #nacos server配置中心的dataId
            groupId: DEFAULT_GROUP #指定组[nacos server配置中心]
            data-type: json #指定配置流控规刚的数据类型
            rule-type: flow #规则类型:流控规则 表示方式一会看文档

测试

启动Nacos Server8848
启动Sentinel8080控制台/Sentinel dashboard
member-service-nacos-provider-10004/10006
启动member-service-nacos-consumer-80
浏览器:
http://localhost/member/openfeign/consumer/query/1
然后访问http://localhost:8080/进入sentinel dashboard,即可在“流控规则”看到配置

注意事项和细节

  在nacos server配置sentinel流控规则的Data ID也可以自己指定,比如写成stein-id,只要在sentinel client/微服务的applicaion.yml的datasource.ds1.nacos.dataId的值保持一致即可

其它类型规则

1.前面通过sentinel控制台我们详细讲解了配置 如下规则

2.在被监控保护的微服务模块,我们配置了如下:

        这里rule-type可以是

                flow,流控规则

                degrade,降级规则

                param-flow,热点规则

                system,系统规则

                等。 

通过Ctrl+N,查询RuleType,可以看到这些规则配置名称的来源

 3.其它规则的种类配置文档:basic-api-resource-rule | Sentinel

找到“规则的种类”,查看对应规则字段,即可使用json格式,配置内容,比如:

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

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

相关文章

Android Studio Notification(状态栏通知) 不显示通知 解决

引言&#xff1a;在学习的过程中&#xff0c;我发现&#xff0c;无论怎么修改&#xff0c;甚至是直接复制了大佬的代码&#xff0c;我的程序都不呢个正确的弹出一个状态栏通知&#xff0c;在经过一晚上的纠缠后&#xff0c;终于找到了原因 通知不显示可能由多种原因引起&#…

C++自动推导与函数模板

自动推导、函数模板、类模板 目录 1. 自动推导出数据类型 2. 函数模板 基本概念注意事项函数模板的具体化函数模板分文件编写函数模板高级函数后置返回类型 1. 自动推导出数据类型 auto关键字 linux 系统下使用的话&#xff0c;要在编译时 —stdc11 注意&#xff1a; a…

关于B+树的介绍、用途和c++代码实现

数据结构和算法的重要性不言而喻&#xff0c;一些优秀的开源项目的核心和灵魂就是数据结构、算法。在实际的编程中我们经常可以在各种框架、算法中看见B树、B树的身影。特别是在数据库的数据库引擎中&#xff0c;它们更是占据着重要的地位。 下面我将通过简单的二叉树&#xff…

2023/5/12总结

这俩天主要花时间在项目上&#xff1a; 实现了创建群聊和添加群聊&#xff1a; 点击创建群聊&#xff1a; &#xff0c;点击确定之后&#xff0c;会分配到一个群聊&#xff0c;默认头像会是下面这个圆形的头像&#xff1a; 添加群聊&#xff1a; 如果你要加入的群聊在自己的列…

06-HTML-列表标签

1、 <ul> 标签定义无序列表。 2、<ol> 标签定义有序列表。 属性值描述compactcompact HTML5 中不支持。HTML 4.01 中不赞成使用。 规定列表呈现的效果比正常情况更小巧。 reversedreversed规定列表顺序为降序。(9,8,7...)startnumber规定有序列表的起始值。type 1A…

为什么使用ConcurrentHashMap

currentHashMap的介绍 ConcurrentHashMap是线程安全并且高效的一种容器,我们就需要研究一下ConcurrentHashMap为什么既能够保证线程安全,又可以保证高效的操作。 为什么使用ConcurrentHashMap,我们就需要和HashMap以及HashTable进行比较&#xff1f; HashMap是线程不安全的&…

唐朔飞计组 第六章运算方法简单复习

在计算机中参与运算的数有两类&#xff1a;有符号数和无符号数 int 和unsigned unsigned可以看成是正数或者绝对值。 有符号数分为原码反码和补码 原码和反码的表示范围是相同的 但是补码由于将-0的位置换成2^n所以补码表示范围比原码和反码要多一位&#xff0c; 判断溢出比较…

诚邀社区开发者参与DeepBook测试和集成

DeepBook是Sui的基础流动性层&#xff0c;Sui基金会诚挚邀请社区开发者参与其测试和集成。 DeepBook为Sui的原生中央订单簿&#xff08;Central Limit Order Book&#xff0c;CLOB&#xff09;和基础流动性层&#xff0c;将会在未来数周准备完成&#xff0c;我们邀请大家参与测…

Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置

目录 1、Shader控制一棵草的渲染 2、草地的动态交互 3、使用GPUInstancing渲染大面积的草 4、对大面积草地进行区域剔除和显示等级设置 Unity使用GPU Instancing制作大面积草地效果 大家好&#xff0c;我是阿赵。 这里开始讲大面积草地渲染的第四个部分&#xff0c;对大面积草地…

零知识证明:安全定义

之前在本科的课程仅仅略微介绍了下零知识证明&#xff0c;之后自学了一些相关内容&#xff0c;但不成体系。本学期跟着邓老师较为系统地学习了 ZKP&#xff0c;发现自己之前有很多的误解&#xff0c;临近期末整理下重要内容。 参考文献&#xff1a; Goldreich O. Foundations…

C语言实现个人通讯录(功能优化)

实战项目---通讯录&#xff08;功能优化&#xff09; 1.基本思路介绍&#xff1a;1.1基本思路&#xff1a; 2.通讯录的具体实现&#xff1a;2.1 通讯录的建立&#xff1a;2.2通讯录功能&#xff1a; 3.具体功能函数的实现&#xff1a;3.1 增添联系人&#xff1a;3.2 删除联系人…

从零开始学习JVM--初识Java虚拟机

1 虚拟机与Java虚拟机 1.1 基本介绍 所谓虚拟机&#xff08;Virtual Machine&#xff09;。就是一台虚拟的计算机。它是一款软件&#xff0c;用来执行一系列虚拟计算机指令。大体上&#xff0c;虚拟机可以分为系统虚拟机和程序虚拟机。 系统虚拟机&#xff1a;完全对物理计算…

树莓派(主)与STM32(从)使用SPI通信(持续更新中)

1.实验目的 使用树莓派作为主机向 STM32 从机发送数据&#xff0c;STM32 收到数据后通过串口的方式将数据打印到电脑上&#xff0c;同时返回给树莓派数据。树莓派接收到数据后打印在控制台上。 2.SPI 简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接…

进程控制下(程序替换部分)

目录&#xff1a; 1. 进程程序替换的原理 2.将磁盘的数据和代码加载进物理内存 3.程序替换函数的基本使用 ----------------------------------------------------------------------------------------------------------------------------- 1. 进程程序替换的原理 蓝色框内…

图解LeetCode——48. 旋转图像

一、题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 二、示例 2.1> 示例 1&#xff1a; 【输入】matrix [[1,2,3],[…

AVL树的实现

文章目录 AVL树前言1. AVL树的概念2. AVL树的结构2.1 AVL树节点的定义2.2 AVL树的结构 3. AVL树的操作3.1 AVL树的插入3.2 AVL树的旋转(重要)3.2.1 左单旋过程代码 3.2.2 右单旋过程代码 3.2.3 左右双旋过程代码 3.2.4 右左双旋过程代码 旋转整体代码 3.3 AVL树的验证3.4 AVL树…

Day967.团队拓扑学 -遗留系统现代化实战

团队拓扑学 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于团队拓扑学的内容。 看看最近这几年来新诞生的组织结构模型——团队拓扑学&#xff08;Team Topologies&#xff09;。 一、团队拓扑 尽管组件团队、特性团队和 Spotify 模型&#xff0c;都为团队的组成提…

JavaScript实现输入年份判断是否为闰年的代码

以下为实现输入年份判断是否为闰年的程序代码和运行截图 目录 前言 一、输入年份判断是否为闰年 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b; 2.本博文代码可以根据题目要…

阿里云 aliplayer 加密的视频 key解密解密下载过程实现

第一步&#xff1a;打开开发者工具 打开需要下载的视频链接&#xff0c;按F12打开开发者工具&#xff0c;然后强制刷新&#xff08;ctrlf5&#xff09; 第二步&#xff1a;定位key加密 内存搜索&#xff0c;关键词&#xff1a;_sce_dlgtqred 进入第二个结果&#xff1a;https…

Map在循环中修改自己的key与value

Map在循环中修改自己的key与value 1.解决方案2.深入了解 1.解决方案 使用ConcurrentHashMap package com.company.newtest;import java.util.*; import java.util.concurrent.ConcurrentHashMap;public class test30 {public static void main(String[] args) {Map<String…