Hystrix断路器

news2024/11/16 3:26:29

目录

一、概述

(一)分布式系统面临的问题

(二)Hystrix是什么

(三)能干吗

(四)官网

(五)Hystrix官宣,停更进维

二、Hystrix重要概念

(一)服务降级

(二)服务熔断

(三)服务限流

三、hystrix案例

(一)服务降级

(二)服务熔断


一、概述

(一)分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。

服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.
 
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
 

(二)Hystrix是什么

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
 
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
 

(三)能干吗

服务降级、服务熔断、接近实时的监控

(四)官网

How To Use · Netflix/Hystrix Wiki · GitHub

(五)Hystrix官宣,停更进维

很遗憾的是,Hystrix官方已经宣布不再更新并且进入维护阶段

GitHub - Netflix/Hystrix: Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

 

二、Hystrix重要概念

(一)服务降级

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback

哪些情况可能出现服务降级呢?

程序运行异常, 方法运行超出规定时间,服务熔断触发服务降级,线程池/信号量打满也会导致服务降级

(二)服务熔断

类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

服务的降级->进而熔断->恢复调用链路

(三)服务限流

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

三、hystrix案例

客户端80端口,服务端8001端口 , 客户端会调用服务端

需要解决的问题:

① 对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级

② 对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级

③ 对方服务(8001)OK,调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级

(一)服务降级

1、降级配置

@HystrixCommand

2、对于8001

设置自身调用超时时间的峰值,峰值内可以正常运行,
超过了需要有兜底的方法处理,作服务降级fallback

3、8001fallback

业务类

@Service
public class PaymentService
{
    /**
     * 正常访问,一切OK
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id)
    {
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O";
    }

    /**
     * 超时访问,演示降级
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    })
    public String paymentInfo_TimeOut(Integer id)
    {
        int second = 5;
        try { TimeUnit.SECONDS.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); }
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id: "+id+"\t"+"O(∩_∩)O,耗费秒: "+second;
    }
    public String paymentInfo_TimeOutHandler(Integer id){
        return "/(ㄒoㄒ)/调用支付接口超时或异常:\t"+ "\t当前线程池名字" + Thread.currentThread().getName();
    }
}

主启动类上添加新注解@EnableCircuitBreaker 

4、80fallback

YML配置文件

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

feign:
  hystrix:
    enabled: true

主启动类上添加注解@EnableHystrix

业务类

@RestController
@Slf4j
public class PaymentHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
{
    String result = paymentHystrixService.paymentInfo_TimeOut(id);
    return result;
}
//兜底(fallback)方法
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
{
    return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}

}

上面的代码可以实现服务降级,但是带来的新的问题是会出现代码膨胀,因为每一个方法都需要写一个对应的兜底方法以及相应的@HystrixCommand注解,在这里我们可以使用一个统一的全局降级默认方法注解@DefaultProperties(defaultFallback = ""),对于加了@Hystrix但是没有指明fallback方法,会找到默认的全局fallback方法。通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量


 

 

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class PaymentHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand //加了@DefaultProperties属性注解,并且没有写具体方法名字,就用统一全局的
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "paymentTimeOutFallbackMethod,对方系统繁忙,请10秒钟后再次尝试/(ㄒoㄒ)/";
    }

    public String payment_Global_FallbackMethod()
    {
        return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
    }
}

我们还需要解决另外一个问题,那就是fallback方法和业务方法写在一起导致的业务逻辑混乱,这个问题如何解决呢?我们可以结合openfeign,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦

对于80端口已经有的PaymentHystrixService接口,重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理,然后将PaymentFallbackService注册进PaymentHystrixService接口上的注解

@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)
@Component //必须加 //必须加 //必须加
public class PaymentFallbackService implements PaymentFeignClientService
{
    @Override
    public String getPaymentInfo(Integer id)
    {
        return "服务调用失败,提示来自:cloud-consumer-feign-order80";
    }
}


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

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentFeignClientService
{
    @GetMapping("/payment/hystrix/{id}")
    public String getPaymentInfo(@PathVariable("id") Integer id);
}

此时即使服务端provider已经down了,但是我们做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器

(二)服务熔断

熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
 
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand。

在8001服务端,我们添加一些方法来测试

PaymentService

对于HystrixCommand中的参数既可以参照官网,也可以打开HystrixProperties类进行查看

//=========服务熔断=========
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求总数阈值
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //快照时间窗
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //错误百分比阀值
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id)
    {
        if(id < 0)
        {
            throw new RuntimeException("******id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();

        return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
    }
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id)
    {
        return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
    }

 

 

 HystrixCommandProperties

 

PaymentController

@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id)
{
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result: "+result);
    return result;
}

经过多次错误访问后,此时失败率高于60%,断路器打开,方法处于快照时间窗,即使是正确的访问也不能获得正确的回应,当正确的访问变多, 失败率降低,断路器会关闭,服务变正常。


 

 

总结:

① 熔断打开:请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态

② 熔断关闭:熔断关闭不会对服务进行熔断

熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

断路器重要参数

 

涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。
1:快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
 
2:请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
 
3:错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。

断路器开启或者关闭的条件

当满足一定的阀值的时候(默认10秒内超过20个请求次数),若在最近的设置的请求次数中失败率达到一定的时候(默认10秒内超过50%的请求失败),断路器将会开启

当开启的时候,所有请求都不会进行转发,一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启断路器, 五秒后再次尝试。

断路器打开之后

1:再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
 
2:原来的主逻辑要如何恢复呢?
对于这一问题,hystrix也为我们实现了自动恢复功能。
当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑;
当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,
主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

 

HystrixCommand常用配置

//========================All
@HystrixCommand(fallbackMethod = "str_fallbackMethod",
        groupKey = "strGroupCommand",
        commandKey = "strCommand",
        threadPoolKey = "strThreadPool",

        commandProperties = {
                // 设置隔离策略,THREAD 表示线程池 SEMAPHORE:信号池隔离
                @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                // 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
                @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
                // 配置命令执行的超时时间
                @HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
                // 是否启用超时时间
                @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
                // 执行超时的时候是否中断
                @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
                // 执行被取消的时候是否中断
                @HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
                // 允许回调方法执行的最大并发数
                @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
                // 服务降级是否启用,是否执行回调函数
                @HystrixProperty(name = "fallback.enabled", value = "true"),
                // 是否启用断路器
                @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
                // 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,
                // 如果滚动时间窗(默认10秒)内仅收到了19个请求, 即使这19个请求都失败了,断路器也不会打开。
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
                // 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过
                // circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50,
                // 就把断路器设置为 "打开" 状态,否则就设置为 "关闭" 状态。
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                // 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后,
                // 会将断路器置为 "半开" 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 "打开" 状态,
                // 如果成功就设置为 "关闭" 状态。
                @HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
                // 断路器强制打开
                @HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
                // 断路器强制关闭
                @HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
                // 滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
                @HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
                // 该属性用来设置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据
                // 设置的时间窗长度拆分成多个 "桶" 来累计各度量值,每个"桶"记录了一段时间内的采集指标。
                // 比如 10 秒内拆分成 10 个"桶"收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
                @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
                // 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。
                @HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
                // 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
                @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
                // 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。
                @HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
                // 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数,
                // 就从最初的位置开始重写。例如,将该值设置为100, 滚动窗口为10秒,若在10秒内一个 “桶 ”中发生了500次执行,
                // 那么该 “桶” 中只保留 最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间。
                @HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
                // 该属性用来设置采集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
                @HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
                // 是否开启请求缓存
                @HystrixProperty(name = "requestCache.enabled", value = "true"),
                // HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中
                @HystrixProperty(name = "requestLog.enabled", value = "true"),
        },
        threadPoolProperties = {
                // 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
                @HystrixProperty(name = "coreSize", value = "10"),
                // 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,
                // 否则将使用 LinkedBlockingQueue 实现的队列。
                @HystrixProperty(name = "maxQueueSize", value = "-1"),
                // 该参数用来为队列设置拒绝阈值。 通过该参数, 即使队列没有达到最大值也能拒绝请求。
                // 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue
                // 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
                @HystrixProperty(name = "queueSizeRejectionThreshold", value = "5"),
        }
)
public String strConsumer() {
    return "hello 2020";
}
public String str_fallbackMethod()
{
    return "*****fall back str_fallbackMethod";
}
 

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

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

相关文章

JAVA开发(springBoot之HikariDataSource)

HikariDataSource是springBoot自带的数据源管理工具。应该是有zaxxer公司提供贡献给spring社区的。它是一款优秀的数据库连接池工具&#xff08;新的东西一般会吹吹牛&#xff09;&#xff0c;号称 Java WEB 当前速度最快的数据源&#xff0c;相比于传统的 C3P0 、DBCP、Tomcat…

【数据结构】认识顺序表

目录 1、先来认识一下线性表 1.1、对非空的线性表或者线性结构的特点&#xff1a; 1.2、线性表的实现方式 2、顺序表 2.1、定义一个类&#xff0c;实现顺序表 2.2、顺序表的操作方法 2.2.1、打印顺序表&#xff08;display&#xff09; 2.2.2、获取顺序表的长度&#x…

Rancher 中使用 Longhorn 备份恢复数据卷

全文目录导航0. 前言1. NFS 安装配置1.1 安装 nfs 及 rpcbind1.2 创建共享目录1.3 配置访问权限1.4 限制 showmount -e 防止漏洞扫描1.5 防火墙配置2. Longhorn 备份配置2.1 在 Longhorn UI 中配置3. 数据卷备份恢复操作3.1 创建示例工作负载3.2 创建测试数据3.3 创建数据卷备份…

车载以太网 - SomeIP测试专栏 - SomeIP Header - 03

前面已经简单的介绍了整帧SomeIP报文的组成部分,由于Ethernet报文头都是通用的,因此不会做详细的介绍,当然后面在介绍TC8中的TCP、UDP、IPv4、IPv6的时候也会做简单的介绍。不过在这里就不做介绍了,我们直接介绍SomeIP。 SomeIP Header 一、Message ID Message ID是由Serv…

Web3中文|构建Web3融资交易:股权和内部代币分配的比例

2017年&#xff0c;首次币发行&#xff08;ICO&#xff0c;Initial Coin Offering&#xff0c;也称首次代币发售、区块链众筹&#xff0c;是用区块链把使用权和加密货币合二为一&#xff0c;来为开发、维护、交换相关产品或者服务的项目进行融资的方式&#xff09;的融资方式激…

聚观早报 | 抖音超市上线;首架国产大飞机 C919 完成首次飞行

今日要闻&#xff1a;抖音超市上线&#xff1b;首架国产大飞机 C919 完成首次飞行&#xff1b;小鹏汽车计划有 5 款车型上市&#xff1b;2023年春节档电影总票房67.58亿元&#xff1b;亚洲首富被空头重创抖音超市上线 1 月 28 日消息&#xff0c;抖音超市已上线抖音 App&#x…

Javadoc(文档注释)详解

Java 支持 3 种注释&#xff0c;分别是单行注释、多行注释和文档注释。文档注释以/**开头&#xff0c;并以*/结束&#xff0c;可以通过 Javadoc 生成 API 帮助文档&#xff0c;Java 帮助文档主要用来说明类、成员变量和方法的功能。文档注释只放在类、接口、成员变量、方法之前…

vue+element高度仿照QQ音乐,完美实现PC端QQ音乐

一.前言 QQ音乐官网&#xff1a;点击访问作者成品效果预览&#xff1a;点击访问作者其他博客成品汇总预览&#xff1a;点击访问 暂时源码并没有提供其他获取渠道&#xff0c;私聊作者获取即可&#xff0c;或通过博客后面名片添加作者&#xff0c;很简单&#xff01; 二.主要…

创建的vue项目--打包

自创建的项目&#xff08;未使用项目框架&#xff09;&#xff0c;使用weabpack打包 1.在package.json文件中配置 2.在控制台执行打包命令npm run build 打包完成后&#xff0c;会在项目中生成一个dist文件夹&#xff0c;其中就是打包生成的静态文件 3.打开index.html&…

RocketMq基础详解

1、RocketMq的架构&#xff1a; 在RocketMq中有四个部分组成&#xff0c;分别是Producer&#xff0c;Consumer&#xff0c;Broker&#xff0c;以及NameServer&#xff0c;类比于生活中的邮局&#xff0c;分别是发信者&#xff0c;收信者&#xff0c;负责暂存&#xff0c;传输的…

找到二叉树中的最大搜索二叉树

题目 给定一棵二叉树的头节点 head&#xff0c;一致其中所有节点的值都不一样&#xff0c;找到含有节点最多的搜索二叉树&#xff0c;并返回这棵子树的头节点。 示例 分析 树形dp套路&#xff1a;如果题目求解目标是S规则&#xff0c;则求解流程可以定成以每一个节点为头节点…

【前端】如何判断是页面滚动还是窗口滚动

在写项目的时候遇到这个问题&#xff0c;现在举两个例子来记录这个问题。 页面滚动 html: <div class"temp"><template v-for"item in 100"><div>{{ item }}</div></template> </div>css: .temp {height: 100px;o…

老马闲评数字化「3」业务说了算还是技术说了算?

原文作者&#xff1a;行云创新CEO 马洪喜 导语 前两集和大伙聊了一下“数字化不转型行不行”以及“你的企业急不急着转”这两个话题。后面收到不少朋友的消息&#xff0c;说写的挺好&#xff0c;但“急着转、不敢转”的情况非常的普遍&#xff0c;有没有啥好主意给说一说。 麦…

冬去春来,ToB行业压缩的弹簧就要迸发了

目前来看&#xff0c;认知、实践、技术、服务这四方面的新变化&#xff0c;都将成为2023年企业数智化业务需求“井喷”的重要原因。 作者|周羽 出品|产业家 2023&#xff0c;冬去春来。 不止于字面。新的一年&#xff0c;中国的ToB厂商即将迎来“拨云见日”的朗朗晴空。 …

[文件上传工具类] MultipartFile 统一校验

目录​​​​​​​ 1. 创建上传文件的统一校验类 包含功能: -> 1. 多文件上传校验 -> 2. 文件名字校验(特殊符号) -> 3. 文件后缀校验 2. 使用方式 建议: 在文件上传开始的位置添加 -> 两个重载方法, 单文件 多文件都支持 -> 示例: 直接可以用, 任意位…

C++ 包装器function

目录 1、为什么需要包装器&#xff1f; 2、包装器的声明和使用 (1) 声明 (2) 实际应用 (3) 包装器接收类成员函数 3、包装器的绑定&#xff1a;bind函数 (1) 调整参数顺序 (2) 调整参数个数 1、为什么需要包装器&#xff1f; 函数模板可以接收各种不同类型的参数&…

光流正负值的含义以及如何利用光流进行warping

本文主要介绍光流的形式&#xff0c;光流值的正负代表什么含义&#xff0c;以及如何利用光流进行warping。 1. 光流正负值的含义 光流的概念&#xff1a;光流表示的是从reference frame到target frame&#xff0c;物体的移动。光流的形式&#xff1a;光流的表示也是数字化的。…

镭速-跨国车企数据高速、安全跨境传输解决方案

一、背景及趋势 在新一代信息技术驱动的数字经济时代&#xff0c;数据已然成为新型生产要素&#xff0c;是国家基础性资源和战略性资源。在汽车市场全球化背景下&#xff0c;产品、数据双跨境将成为车企未来常态。数据的价值核心在于流通和应用&#xff0c;但数据也牵涉着竞争…

23.1.30 将TF-A源码移植的过程,整理成自己的笔记

将TF-A源码移植的过程&#xff0c;整理成自己的笔记&#xff0c;上传到CSDN 一、配置TF-A源码 自动探测 自动换行 1.对tf-a源码进行解压 tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz 打补丁 3.进入tf-a源码目录 $> cd tf-a-stm32mp-2.2.r2 4.打补丁命令 $> for p in ls -1 .…

JavaScript中的Array对象~

初识Array&#xff1a; Array 对象用于在单个的变量中存储多个值 定义&#xff1a; 方式1 //返回的数组为空&#xff0c;length字段为0 var 变量名new Array(); //size是期望的数组元素个数&#xff0c;返回的length字段将被设置为size的值--返回具有指定个数&#xff0c;元…