微服务之CircuitBreaker断路器

news2024/11/15 21:43:54

一、概述

1.1背景

在一个分布式系统中,每个服务都可能会调用其它的服务器,服务之间是相互调用相互依赖。假如微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务。这就是构成所谓“扇出”。

如果扇出的链路上某个微服务的调用响应的时间过长或者不可用,对微服A的调用就会占用越来越多的系统资源,进而引起系统崩溃,即"雪崩效应"。

对于高流量的应用来说,单一的后端依赖可能会导致所有的服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

为应对微服务器系统出现“雪崩”事故,使用微服务Hystrix能避免级联故障,以提高分布式系统的弹性。

1.2断路器概述

- 有问题的节点,快速熔断(快速返回失败处理或者返回默认兜底数据【服务降级】)。

 

“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack)而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

功能:

  • 服务熔断
    • 类比保险丝,保险丝闭合状态(CLOSE)可以正常使用,当达到最大服务访问后,直接拒绝访问跳闸限电(OPEN),此刻调用方会接受服务降级的处理并返回友好兜底提示
    • 就是家里保险丝,从闭合CLOSE供电状态跳闸OPEN打开状态
  • 服务降级
    • 服务器忙,请稍后再试。不让客户端等待并立刻返回一个友好提示,fallback
  • 服务限流
    • 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
  • 服务限时
  • 服务预热
  • 接近实时的监控
  • 兜底的处理动作

请求限流

服务故障最重要原因,就是并发太高!解决了这个问题,就能避免大部分故障。当然,接口的并发不是一直很高,而是突发的。因此请求限流,就是限制或控制接口访问的并发流量,避免服务因流量激增而出现故障。

请求限流往往会有一个限流器,数量高低起伏的并发请求曲线,经过限流器就变的非常平稳。这就像是水电站的大坝,起到蓄水的作用,可以通过开关控制水流出的大小,让下游水流始终维持在一个平稳的量。

线程隔离

当一个业务接口响应时间长,而且并发高时,就可能耗尽服务器的线程资源,导致服务内的其它接口受到影响。所以我们必须把这种影响降低,或者缩减影响的范围。线程隔离正是解决这个问题的好办法。

为了避免某个接口故障或压力过大导致整个服务不可用,我们可以限定每个接口可以使用的资源范围,也就是将其“隔离”起来。

服务熔断

线程隔离虽然避免了雪崩问题,但故障服务(商品服务)依然会拖慢购物车服务(服务调用方)的接口响应速度。而且商品查询的故障依然会导致查询购物车功能出现故障,购物车业务也变的不可用了。

所以,我们要做两件事情:

  • 编写服务降级逻辑:就是服务调用失败后的处理逻辑,根据业务场景,可以抛出异常,也可以返回友好提示或默认数据。

  • 异常统计和熔断:统计服务提供方的异常比例,当比例过高表明该接口会影响到其它服务,应该拒绝调用该接口,而是直接走降级逻辑。

1.3Hystrix(过时了解)

Hystrix是一个用于处理分布式系统的延迟容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

1.4Spring Cloud断路器

Spring Cloud Circuit Breaker提供了跨不同断路器实现的抽象。它提供了在应用程序中使用的一致API,允许开发人员选择最适合您的应用程序需求的断路器实现。

CircuitBreaker的目的是保护分布式系统免受故障和异常,提高系统的可用性和健壮性。

 

当一个组件或服务出现故障时,CircuitBreaker会迅速切换到开放OPEN状态(保险丝跳闸断电),阻止请求发送到该组件或服务从而避免更多的请求发送到该组件或服务。这可以减少对该组件或服务的负载,防止该组件或服务进一步崩溃,并使整个系统能够继续正常运行。同时,CircuitBreaker还可以提高系统的可用性和健壮性,因为它可以在分布式系统的各个组件之间自动切换,从而避免单点故障的问题。

Circuit Breaker!只是一套规范和接口,落地实现者是Resilience4J

1.5Resilience4J

Resilience4j是一个专为函数式编程设计的轻量级容错库。Resilience4i提供高阶函数(装饰器),以通过断路器、速率、限制器、重试或隔板增强任何功能接口、lambda表达式或方法引用。您可以在任何函数式接口、lambda表达式或方法引用上堆叠多个装饰器。优点是您可以选择您需要的装饰器,而没有其他选择。


Resilience42需要Java17。

官网CircuitBreaker 

中文网站https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/index.md

二、实战

2.1熔断

原理

 配置属性

 需求

 #  6次访问中当执行方法的失败率达到50%CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
#  等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
#  如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。

实现 计数的滑动窗口

客户端控制类

package com.yanyu.cloud.controller;

import cn.hutool.core.util.IdUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController // 声明这是一个RESTful风格的控制器
public class PayCircuitController {
    // 使用Resilience4j CircuitBreaker的例子
    @GetMapping(value = "/pay/circuit/{id}") // 定义一个GET请求映射,路径为/pay/circuit/{id}
    public String myCircuit(@PathVariable("id") Integer id) { // 定义一个方法,接收一个名为id的路径参数
        if (id == -4) throw new RuntimeException("----circuit id 不能负数"); // 如果id为-4,抛出异常
        if (id == 9999) { // 如果id为9999
            try {
                TimeUnit.SECONDS.sleep(5); // 让线程休眠5秒
            } catch (InterruptedException e) {
                e.printStackTrace(); // 打印异常堆栈信息
            }
        }
        return "Hello, circuit! inputId:  " + id + " \t " + IdUtil.simpleUUID(); // 返回一个字符串,包含输入的id和一个随机生成的UUID
    }
}

配置

<!--resilience4j-circuitbreaker-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

yml配置

 # 开启circuitbreaker和分组激活 spring.cloud.openfeign.circuitbreaker.enabled
            circuitbreaker:
        enabled: true
        group:
          enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
# Resilience4j CircuitBreaker 按照次数:COUNT_BASED 的例子
#  6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
#  等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
#  如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
resilience4j:
  circuitbreaker:
    configs:
      default:
        failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
        slidingWindowType: COUNT_BASED # 滑动窗口的类型
        slidingWindowSize: 6 #滑动窗⼝的⼤⼩配置COUNT_BASED表示6个请求,配置TIME_BASED表示6秒
        minimumNumberOfCalls: 6 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。如果minimumNumberOfCalls为10,则必须最少记录10个样本,然后才能计算失败率。如果只记录了9次调用,即使所有9次调用都失败,断路器也不会开启。
        automaticTransitionFromOpenToHalfOpenEnabled: true # 是否启用自动从开启状态过渡到半开状态,默认值为true。如果启用,CircuitBreaker将自动从开启状态过渡到半开状态,并允许一些请求通过以测试服务是否恢复正常
        waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
        permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。在半开状态下,CircuitBreaker将允许最多permittedNumberOfCallsInHalfOpenState个请求通过,如果其中有任何一个请求失败,CircuitBreaker将重新进入开启状态。
        recordExceptions:
        - java.lang.Exception
    instances:
      cloud-payment-service:
        baseConfig: default

服务端控制类

@RestController // 声明这是一个RESTful风格的控制器
public class OrderCircuitController {
    @Resource // 注入PayFeignApi接口的实现类
    private PayFeignApi payFeignApi;

    @GetMapping(value = "/feign/pay/circuit/{id}") // 定义一个GET请求映射,路径为/feign/pay/circuit/{id}
    @CircuitBreaker(name = "cloud-payment-service", fallbackMethod = "myCircuitFallback") // 使用CircuitBreaker注解,指定熔断器名称和降级方法
    public String myCircuitBreaker(@PathVariable("id") Integer id) { // 定义一个方法,接收一个名为id的路径参数
        return payFeignApi.myCircuit(id); // 调用PayFeignApi接口的myCircuit方法,并返回结果
    }

    // myCircuitFallback是服务降级后的兜底处理方法
    public String myCircuitFallback(Integer id, Throwable t) {
        // 这里是容错处理逻辑,返回备用结果
        return "myCircuitFallback,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~";
    }
}
@CircuitBreaker注解

@CircuitBreaker是Spring Cloud Circuit Breaker库中的一个注解,用于为方法提供熔断器功能。当方法调用失败或超时时,熔断器会触发并执行备用逻辑,以避免对整个系统造成影响。

使用@CircuitBreaker注解时,需要指定一个名称(name)和一个备用方法(fallbackMethod)。名称用于标识熔断器,备用方法用于在熔断器触发时执行的代码。

50%错误后触发熔断并给出服务降级,告知调用者服务不可用此时就算是输入正确的访问地址也无法调用服务(我明明是正确的也不让用(ToTY~),.它还在断路中(OPEN状态),一会儿过度到半开并继续正确地址访问,慢慢切换回CLO$E状态,可以正常访问了链路回复

 实现 时间的滑动窗口

# Resilience4j CircuitBreaker 按照时间:TIME_BASED 的例子
resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 10s #神坑的位置,timelimiter 默认限制远程1s,超于1s就超时异常,配置了降级,就走降级逻辑
  circuitbreaker:
    configs:
      default:
        failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
        slowCallDurationThreshold: 2s #慢调用时间阈值,高于这个阈值的视为慢调用并增加慢调用比例。
        slowCallRateThreshold: 30 #慢调用百分比峰值,断路器把调用时间⼤于slowCallDurationThreshold,视为慢调用,当慢调用比例高于阈值,断路器打开,并开启服务降级
        slidingWindowType: TIME_BASED # 滑动窗口的类型
        slidingWindowSize: 2 #滑动窗口的大小配置,配置TIME_BASED表示2秒
        minimumNumberOfCalls: 2 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。
        permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。
        waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
        recordExceptions:
          - java.lang.Exception
    instances:
      cloud-payment-service:
        baseConfig: default 

 2.2隔离

依赖隔离&负载保护:用来限制对于下游服务的最大并发数量的限制
Resilience4j提供了如下两种隔离的实现方式

SemaphoreBulkhead(信号量舱壁)

原理

配置

<!--resilience4j-bulkhead-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-bulkhead</artifactId>
</dependency>

 

yml配置

# resilience4j bulkhead 的例子
resilience4j:
  # 配置bulkhead隔离策略
  bulkhead:
    configs:
      # 默认配置
      default:
        maxConcurrentCalls: 2 # 隔离允许并发线程执行的最大数量
        maxWaitDuration: 1s # 当达到并发调用数量时,新的线程的阻塞时间,我只愿意等待1秒,过时不候进舱壁兜底fallback
    instances:
      # 实例名称为cloud-payment-service的配置
      cloud-payment-service:
        baseConfig: default # 使用默认配置
  # 配置timelimiter超时策略
  timelimiter:
    configs:
      # 默认配置
      default:
        timeout-duration: 20s # 设置超时时间为20秒
@GetMapping(value = "/feign/pay/bulkhead/{id}")
    @Bulkhead(name = "cloud-payment-service",fallbackMethod = "myBulkheadFallback",type = Bulkhead.Type.SEMAPHORE)
    public String myBulkhead(@PathVariable("id") Integer id)
    {
        return payFeignApi.myBulkhead(id);
    }
    public String myBulkheadFallback(Throwable t)
    {
        return "myBulkheadFallback,隔板超出最大数量限制,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~";
    }

  @Bulkhead注解

@Bulkhead是Spring Cloud Circuit Breaker库中的一个注解,用于为方法提供隔离功能。当方法调用失败或超时时,隔离器会阻止更多的请求进入该方法,以避免对整个系统造成影响。

使用@Bulkhead注解时,需要指定一个名称(name)和一个最大并发数(maxConcurrentCalls)。名称用于标识隔离器,最大并发数用于限制允许同时执行的请求数量。

实现FixedThreadPoolBulkhead(固定线程池舱壁)

配置yml

####resilience4j bulkhead -THREADPOOL的例子
resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 10s #timelimiter默认限制远程1s,超过报错不好演示效果所以加上10秒
  thread-pool-bulkhead:
    configs:
      default:
        core-thread-pool-size: 1
        max-thread-pool-size: 1
        queue-capacity: 1
    instances:
      cloud-payment-service:
        baseConfig: default
# spring.cloud.openfeign.circuitbreaker.group.enabled 请设置为false 新启线程和原来主线程脱离
/**
 * (船的)舱壁,隔离,THREADPOOL
 * @param id
 * @return
 */
@GetMapping(value = "/feign/pay/bulkhead/{id}")
@Bulkhead(name = "cloud-payment-service",fallbackMethod = "myBulkheadPoolFallback",type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> myBulkheadTHREADPOOL(@PathVariable("id") Integer id)
{
    System.out.println(Thread.currentThread().getName()+"\t"+"enter the method!!!");
    try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
    System.out.println(Thread.currentThread().getName()+"\t"+"exist the method!!!");

    return CompletableFuture.supplyAsync(() -> payFeignApi.myBulkhead(id) + "\t" + " Bulkhead.Type.THREADPOOL");
}
public CompletableFuture<String> myBulkheadPoolFallback(Integer id,Throwable t)
{
    return CompletableFuture.supplyAsync(() -> "Bulkhead.Type.THREADPOOL,系统繁忙,请稍后再试-----/(ㄒoㄒ)/~~");
}

2.3限流

限流 就是限制最大访问流量。系统能提供的最大并发是有限的,同时来的请求又太多,就需要限流。 

比如商城秒杀业务,瞬时大量请求涌入,服务器忙不过就只好排队限流了,和去景点排队买票和去医院办理业务排队等号道理相同。

常见限流算法

漏斗算法

这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。

令牌桶算法

SpringCloud默认使用该算法

滚动时间窗

缺点:间隔临界的一段时间内的请求就会超过系统限制,可能导致系统被压垮

滑动时间窗口 

实现

配置

<!--resilience4j-ratelimiter-->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
</dependency>

 

 yml配置

####resilience4j ratelimiter 限流的例子
resilience4j:
  ratelimiter:
    configs:
      default:
        limitForPeriod: 2 #在一次刷新周期内,允许执行的最大请求数
        limitRefreshPeriod: 1s # 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
        timeout-duration: 1 # 线程等待权限的默认等待时间
    instances:
        cloud-payment-service:
          baseConfig: default

控制类

@GetMapping(value = "/feign/pay/ratelimit/{id}")
    @RateLimiter(name = "cloud-payment-service",fallbackMethod = "myRatelimitFallback")
    public String myBulkhead1(@PathVariable("id") Integer id)
    {
        return payFeignApi.myRatelimit(id);
    }
    public String myRatelimitFallback(Integer id,Throwable t)
    {
        return "你被限流了,禁止访问/(ㄒoㄒ)/~~";
    }
@RateLimiter

@RateLimiter是Spring Cloud Circuit Breaker库中的一个注解,用于为方法提供限流功能。当方法调用失败或超时时,限流器会限制请求的速率,以避免对整个系统造成影响。

使用@RateLimiter注解时,需要指定一个名称(name)和一个最大速率(maxRate)。名称用于标识限流器,最大速率用于限制允许每秒执行的最大请求数量。

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

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

相关文章

【详细的Kylin使用心得】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

【任务调度】Apache DolphinScheduler快速入门

Apache DolphinScheduler基本概念 概念&#xff1a;分布式、去中心化、易扩展的可视化DAG工作流任务调度系统。 作用&#xff1a;解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。Apache DolphinScheduler是一款开源的调度工具&#xff…

高仿小米商城用户端

高仿小米商城用户端(分为商城前端&#xff08;tongyimall-vue)和商城后端(tongyimall-api)两部分)&#xff0c;是Vue SpringBoot的前后端分离项目&#xff0c;用户端包括首页门户、商品分类、首页轮播、商品展示、商品推荐、购物车、地址管理、下订单、扫码支付等功能模块。 …

邮箱群组是什么?怎么创建邮箱群组?

在我们群发邮件时&#xff0c;可能会遇到这样的状况&#xff0c;一个个输入邮箱地址效率很低&#xff0c;而且很容易就漏发。而对于一个企业来说&#xff0c;如果出现这样的问题&#xff0c;很有可能会影响公司的业务进展和团队协作。这个时候我们就需要邮箱群组这个功能&#…

spring cloud介绍

Spring Cloud是一系列框架的集合&#xff0c;它旨在简化构建分布式系统的过程。基于Spring Boot的快速配置和管理&#xff0c;Spring Cloud为微服务架构提供了全面的基础设施支持。它包括但不限于以下组件&#xff1a; 1. **Spring Cloud Discovery** - 服务发现组件&#xff0…

MySQL行级锁——技术深度+1

引言 本文是对MySQL行级锁的学习&#xff0c;MySQL一直停留在会用的阶段&#xff0c;需要弄清楚锁和事务的原理并DEBUG查看。 PS:本文涉及到的表结构均可从https://github.com/WeiXiao-Hyy/blog中获取&#xff0c;欢迎Star&#xff01; MySQL行级锁 行级锁&#xff08;Row-…

并发学习28--多线程 Fork、Join线程池

概念 使用 import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask;public class TC51 {public static void main(String[] args) {//递归到最小不可分解单元&#xff0c;再进行计算ForkJoinPool pool new ForkJoinPool(5);pool.invoke(new My…

短视频素材在哪下载?优质视频素材APP下载

在这个视频内容日益成为关键传播手段的时代&#xff0c;选择正确的视频素材可以极大地增强你的内容影响力。无论是制作广告、社交媒体内容还是电影制作&#xff0c;高质量的视频素材都是不可或缺的。以下是精心挑选的全球顶级视频素材网站列表&#xff0c;每个网站都能为你的视…

嵌入式4-18

做一个简单数据库终端操作系统 #include <myhead.h> int main(int argc, const char *argv[]) {int id;char name[16];float score;sqlite3 *pNULL;if(sqlite3_open("./my.db",&p)!SQLITE_OK){printf("sqlite3_open error\n");return -1;} …

QT Webengine开发过程报错qml: Render process exited with code 159 (killed)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、解决方法二、补充说明总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 基于QT的Webengine开发过程中&#xff0c;QT的官方示例…

C语言进阶课程学习记录-函数指针的阅读

C语言进阶课程学习记录-函数指针的阅读 5个标识符含义解析技巧 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 5个标识符含义解析 int (*p1) (int* , int (*f) ( int* ) );定义了指针p1,指向函数&#…

面试题:一个 URL 在浏览器被输入到页面展现的过程中发生了什么

文章目录 前言一、回答二、深入追问 前言 这是一段~ 经典的旋律 ~&#xff0c;不好意思串台了&#xff0c;哈哈&#xff0c;这是一个经典的面试题&#xff1a;一个URL从浏览器到页面的过程中发生了什么&#xff0c;那么今天就带大家九浅一深来研究一下 觉得不错的同学可以加我…

RocketMQ 02 功能大纲介绍

RocketMQ 02 主流的MQ有很多&#xff0c;比如ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ等。 之前阿里巴巴也是使用ActiveMQ&#xff0c;随着业务发展&#xff0c;ActiveMQ IO 模块出现瓶颈&#xff0c;后来阿里巴巴 通过一系列优化但是还是不能很好的解决&#xff0c;之后…

SAP SD学习笔记06 - 受注的据否,受注的理由,简易变更(一括处理)

上文讲了一括处理和Block&#xff08;冻结&#xff09;处理。 SAP SD学习笔记05 - SD中的一括处理&#xff08;集中处理&#xff09;&#xff0c;出荷和请求的冻结&#xff08;替代实现承认功能&#xff09;-CSDN博客 本章继续讲SAP的流程中一些常用的操作。 1&#xff0c;受注…

计算机网络练习-计算机网络体系结构与参考模型

计算机网络分层结构 ----------------------------------------------------------------------------------------------------------------------------- 1.在ISO/OSI参考模型中&#xff0c;实现两个相邻结点间流量控制功能的是( )。 A.物理层 B. 数据链路层 C.网络层 D.传…

Nougat项目学习

简介 论文学习 https://arxiv.org/abs/2308.13418 项目地址 GitHub - facebookresearch/nougat: Implementation of Nougat Neural Optical Understanding for Academic Documents 项目主页 Nougat 这个项目主要是实现将pdf文档图片转换为markdown格式&#xff1b;针对纯英…

【蓝桥杯2025备赛】素数判断:从O(n^2)到O(n)学习之路

素数判断:从O( n 2 n^2 n2)到O(n)学习之路 背景:每一个初学计算机的人肯定避免不了碰到素数&#xff0c;素数是什么&#xff0c;怎么判断&#xff1f; 素数的概念不难理解:素数即质数&#xff0c;指的是在大于1的自然数中&#xff0c;除了1和它本身不再有其他因数的自然数。 …

宏集eX700M系列HMI实现港口设备数据上云

前言 随着港口设备信息化技术的快速发展&#xff0c;越来越多的企业想要把现场设备数据上传到云平台&#xff0c;进而实现关键数据的远程监控和分析处理。在此背景下&#xff0c;国内某信息化公司想要将港口设备数据通过MQTT上传到该公司自研IOT平台&#xff0c;实现数据上云&…

我三战华东师范大学的同桌真的很牛

标题党一下&#xff0c;其实是我的一个关系很好的高中同桌死磕华东师范大学三年&#xff0c;最终第二名上岸的故事。 其实我们是同一届的&#xff0c;我为了早点走选择了个排名还行的双非院校就走了&#xff0c;而我这个同桌相当有毅力&#xff0c;他能坚持这么久我其实很佩服&…

C++类和对象 中(六大默认成员函数)

前言 紧接着上一篇文章&#xff0c;接下来我们来认识下类的六大默认成员函数&#xff0c;如下图。之所以叫他默认成员函数&#xff0c;是因为即使我们不写&#xff0c;编译器会默认帮我们写&#xff0c;但只要我们自己显示的写了&#xff0c;编译器就不会帮我们生成对应的成员函…