当前位置: 首页 > news >正文

服务容错治理框架resilience4jsentinel基础应用---微服务的限流/熔断/降级解决方案

写在前文:hystrix停止维护,不做总结;

本文主要总结sentinel和resilience4j这两个框架;另外额外补充面试可能会问到的限流算法;

目录

限流算法

漏桶算法

计数器算法

令牌桶算法

resilience4j与sentinel

resilience4j+springboot3环境搭建

Step1、环境准备

引入依赖

配置application.yml 

Config配置 --- 后续这个不生效,使用的是application.yml中的配置

定义全局处理类

定义模拟外部API调用类

Step2、限流RateLimiter

Application.yml中有两个配置

Java代码中的配置RateLimiterRegistry Bean

限流器使用

coontroller

service

另外一种写法

Step3、熔断CircuitBreaker

coontroller

 service

Step4、隔板Bulkhead --- 也可以当并发限制

controller

service

Step5、超时

controller

service

Step6、重试Retry

controller

service

Step7、综合使用

controller

service

Sentinel


限流算法

漏桶算法

原理:系统内部维护一个固定的容器,请求到达时,如果桶未满,就存入桶中,如果桶满了,就拒绝请求;以恒定速率处理请求;

优势:速率可控,输出流量平滑;

缺点:无法应对合理突发流量、临界值突变依然有问题

计数器算法

原理:将时间划分为固定窗口(比如1s一个窗口),在窗口内,维护一个计数器,每次请求来时,计数器+1,如果没有超过限制阈值那么就允许通过,否则就拒绝请求;时间窗口滑动时重置计数器;

缺点:如果0.8s到1s请求来了100个,其余时间为0,1s~1.2s请求来了100个其余时间为0,那么此时0.8s~1.2s总供处理了200个请求,但是0~0.8以及1.2~2s并没有处理;

令牌桶算法

原理:令牌生成器以固定速率向桶中添加令牌- --- 比如桶最大容量限制100个,有请求来时,获取获取一个令牌token,如果有令牌token那么允许通过,如果没有那么就拒绝请求/排队等待;

优势:可以应对突发流量(比如令牌生成速度为1s一个,桶容量为100个,那么峰值就是100个,往后即便流量再多也只能每秒获取一个token)

特征计数器算法漏桶算法令牌桶算法
流量突发处理❌ 窗口临界问题❌ 严格限制✅ 允许合理突发
流量平滑性❌ 窗口突变✅ 绝对平滑✅ 可配置平滑度
系统资源消耗✅ 低✅ 低✅ 中等
实现复杂度✅ 简单✅ 中等⚠️ 较高
实时调整能力❌ 困难⚠️ 一般✅ 灵活
典型应用简单接口限流硬件设备控制互联网高并发系统

resilience4j与sentinel

sentinel比较重(功能比较全面,但是配置项复杂、部署维护成本比较大),而resilience4j是轻量化(功能虽少,但是核心功能--降级/熔断/限流/重试/并发隔离功能都有);

在业务中如何选择,可以从下面几个方面考虑:

        1、系统是否采用springcloud alibaba技术体系;

        2、团队人数;

        3、学习成本;

resilience4j+springboot3环境搭建

Step1、环境准备

本文所有配置、依赖外部服务均在这里,后续不做详细解释

引入依赖

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.1</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies>
<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot3</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--       要使用resilience4j就必须要引入下面的AOP不然不会生效 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
</dependencies>

配置application.yml 

server:port: 8080servlet:context-path: /fault
spring:application:name: fault-guard
# 如果要使用type = Bulkhead.Type.THREADPOOL线程隔离需要配置,不然系统会采用默认参数
#  task:
#    execution:
#      pool:
#        core-size: 5
#        max-size: 10
#        queue-capacity: 100
management:endpoint:health:show-details: always  # 设置为"always"意味着健康检查详情总是显示给所有访问者,包括详细的状态信息。endpoints:web:exposure:#  配置完下面以后就可以查看具体状态:### 查看Resilience4j熔断器状态:GET http://localhost:8080/fault/4j/actuator/circuitbreakers### 查看Resilience4j限流器状态:GET http://localhost:8080/fault/actuator/ratelimiters### 查看Resilience4j隔板状态:GET http://localhost:8080/fault/actuator/bulkheads### 查看Resilience4j重试状态:GET http://localhost:8080/fault/actuator/retries### 查看Resilience4j超时状态: GET http://localhost:8080/fault/actuator/timelimitersinclude: health,circuitbreakers,ratelimiters,bulkheads,retries,timelimiters # 指定要通过HTTP暴露的端点列表。
resilience4j:
# 限速 - Rate Limiterratelimiter:metrics:enabled: trueinstances:rateLimiterApi:                           # 自定义的限流器实例名称,该名称会在代码中引用。使用时:@RateLimiter(name="rateLimiterApi")register-health-indicator: true         # 注册健康指标,可用于健康检查端点# 60s以内,超过1次,即第2次就会被限流limit-for-period: 1                     # 每个时间段允许的请求数(即限流阈值)limit-refresh-period: 60s               # 限流刷新时间间隔(这里是60秒)timeout-duration: 0s                    # 获取许可的最大等待时间为0秒(即不等待)allow-health-indicator-to-fail: true    # 即使限流触发失败,健康检查也视为通过subscribe-for-events: true              # 启用事件订阅,可用于监听限流事件event-consumer-buffer-size: 50          # 限流事件消费者的缓冲区大小
#        baseConfig: default                    # 可以基础配置为default,这样就可以不用上面一项一项配置
#      compositeApi:                            # 配置多个,在使用的时候就可以@RateLimiter(name="compositeApi")
#        baseConfig: default
#  熔断 - Circuit breakercircuitbreaker:metrics:enabled: true                             # 启用指标收集,可以与Micrometer等监控系统集成instances:circuitBreakerApi:                        # 自定义的断路器实例名称,该名称会在代码中引用。使用时:@CircuitBreaker(name = "circuitBreakerApi", fallbackMethod = "circuitBreakerFallback")# 过去10次请求中,如果超过了50%(至少6次)失败,则断路器变为OPEN状态;此时服务只能进入到Controller,无法进入到Servicefailure-rate-threshold: 50              # 触发断路的失败请求比例阈值(%)。例如设置为50表示失败率达到50%时触发断路minimum-number-of-calls: 5              # 在一个滑动窗口内最少需要多少次调用才会计算失败率# 当断路器处于OPEN状态时,所有请求直接失败,不真实调用业务逻辑。并且5秒后自动变为 HALF-OPEN 状态。automatic-transition-from-open-to-half-open-enabled: true # 是否启用自动从 OPEN 状态切换到 HALF-OPEN 状态wait-duration-in-open-state: 5s         # 当断路器处于 OPEN 状态时,等待多久后尝试进入 HALF-OPEN 状态# 在 HALF-OPEN 状态下。最多允许 3个请求通过 去测试系统是否恢复。如果这3次请求都成功,则变为 CLOSED 状态;如果还有失败,则重新回到 OPEN。permitted-number-of-calls-in-half-open-state: 3   # 在 HALF-OPEN 状态下允许处理的请求数sliding-window-size: 10                 # 滑动窗口的长度,取决于 sliding-window-type 是次数还是时间sliding-window-type: count_based        # 滑动窗口类型,可选值:count_based(基于请求次数) time_based(基于时间窗口)
#        baseConfig: default
#      compositeApi:
#        baseConfig: default
#  隔板 - Bulkheadbulkhead:metrics:enabled: trueinstances:bulkheadApi:                # 自定义的舱壁实例名称,该名称会在代码中引用 @Bulkhead(name = "bulkheadApi", type = Bulkhead.Type.THREADPOOL, fallbackMethod = "bulkheadFallback")max-concurrent-calls: 2   # 允许的最大并发调用数量。意味着最多同时有2个线程可以进入并执行被保护的方法或服务调用。max-wait-duration: 1      # 请求在进入舱壁前等待的最大时间,如果隔板已满,每个线程只能等待 1 毫秒
#        baseConfig: default
#      compositeApi:
#        baseConfig: default
#  超时 - Time Limitertimelimiter:metrics:enabled: trueinstances:timeLimiterApi:               # 自定义的超时实例名称,该名称会在代码中引用@TimeLimiter(name = "timeLimiterApi", fallbackMethod = "timeLimiterFallback")timeout-duration: 2s        # 设置超时时间为2秒,即当操作超过这个时间还未完成,则认为超时。cancel-running-future: true # 当设置为true时,若操作超时,则尝试取消正在执行的操作(如果支持的话)。#        baseConfig: default#      compositeApi:#        baseConfig: default
# 重试 - Retryretry:metrics:enabled: true             # 是否开启度量统计,默认为false。如果设置为true,则会收集并报告此Retry的相关指标。legacy:enabled: true           # 是否启用遗留的度量方式。这通常用于向后兼容旧版本的监控和度量系统。instances:retryApi:                 # 自定义的重试实例名称,该名称会在代码中引用max-attempts: 3         # 最大重试次数,包含初次尝试在内共尝试3次。wait-duration: 1s       # 每次重试之间等待的时间间隔,此处设置为1秒。
#        baseConfig: default
#      compositeApi:
#        baseConfig: default

Config配置 --- 后续这个不生效,使用的是application.yml中的配置

只做展示

/*** 可以直接全部在YML中配置,而不使用Resilience4jConfig;* 我们一旦统一定义了**Registry以后,我们在使用的时候貌似只能同时使用一个..* 比如:当我们定义了RateLimiterRegistry以后,我们在使用的时候的就可以“@RateLimiter(name="xxx")”,这个xxx随便什么名字都会被应用到这个bean的配置,好像也只能这一个配置...*/
//@Configuration
public class Resilience4jConfig {// 限流配置@Beanpublic RateLimiterRegistry rateLimiterRegistry() {RateLimiterConfig config = RateLimiterConfig.custom().limitRefreshPeriod(Duration.ofSeconds(60)) // 刷新周期是多少秒.limitForPeriod(1) // 每个周期内允许多少个请求.timeoutDuration(Duration.ofMillis(0)) // 等待时间.build();
//         return RateLimiterRegistry.of(config);// 手动注册实例 "rateLimiterApi" --- 但是我测试以后,系统好像会自动注入...不需要自己单独再定义,rateLimiterApi即可生效// 如果是想使用自定义实例名称,那么使用下面的方法即可RateLimiterRegistry registry = RateLimiterRegistry.of(config);registry.rateLimiter("rateLimiterApi(自定义名称)", config);return registry;}// 熔断器配置@Beanpublic CircuitBreakerRegistry circuitBreakerRegistry() {CircuitBreakerConfig config = CircuitBreakerConfig.custom().failureRateThreshold(50) // 失败率阈值百分比.waitDurationInOpenState(Duration.ofSeconds(5)) // 熔断后等待时间.permittedNumberOfCallsInHalfOpenState(2) // 半开状态允许的调用次数.slidingWindowSize(5) // 滑动窗口大小.recordExceptions(Exception.class) // 记录哪些异常.build();return CircuitBreakerRegistry.of(config);}// 超时配置@Beanpublic TimeLimiterRegistry timeLimiterRegistry() {TimeLimiterConfig config = TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(2)) // 超时时间2秒.build();return TimeLimiterRegistry.of(config);}// 隔板配置@Beanpublic BulkheadRegistry bulkheadRegistry() {BulkheadConfig config = BulkheadConfig.custom().maxConcurrentCalls(3) // 最大并发数.maxWaitDuration(Duration.ofMillis(500)) // 等待时间.build();return BulkheadRegistry.of(config);}// 重试配置@Beanpublic RetryRegistry retryRegistry() {RetryConfig config = RetryConfig.custom().maxAttempts(3) // 最大重试次数.waitDuration(Duration.ofMillis(500)) // 重试间隔.retryExceptions(RuntimeException.class) // 重试哪些异常.build();return RetryRegistry.of(config);}
}

定义全局处理类

通过@RestControllerAdvice定义全局异常处理类

@RestControllerAdvice
public class ApiExceptionHandler {@ExceptionHandler({CallNotPermittedException.class})@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)public String handleCallNotPermittedException() {System.out.println("熔断异常全局处理");return "熔断异常全局处理";}@ExceptionHandler({TimeoutException.class})@ResponseStatus(HttpStatus.REQUEST_TIMEOUT)public void handleTimeoutException() {System.out.println("超时异常全局处理");}@ExceptionHandler({BulkheadFullException.class})@ResponseStatus(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED)public void handleBulkheadFullException() {System.out.println("隔板异常全局处理");}@ExceptionHandler({RequestNotPermitted.class})@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)public String handleRequestNotPermitted() {System.out.println("限流异常全局处理");return "限流异常全局处理";}
}

定义模拟外部API调用类

@Service
public class ExternalApiService {// 模拟外部API调用,有概率失败或延迟public String callExternalApi(boolean shouldFail) throws InterruptedException {Random random = new Random();int delay = random.nextInt(10000); // 随机延迟0-10秒 --- 测试时,可以根据接口适当调动System.out.println("进入ExternalApiService");TimeUnit.MILLISECONDS.sleep(delay);if (shouldFail) {throw new RuntimeException("External API call failed");}return "External API response after " + delay + "ms";}
}

Step2、限流RateLimiter

本文只展示限流这一种比较详细的使用,其余的都是直接上代码以及开发中遇到的坑

配置参数有2种配置方法,一种是在application.yml中配置,一种是在Java代码中配置“*Registry”; 
配置优先级:代码中的 *Registry Bean会覆盖了YAML配置 ---- 创建*RegistryBean配置方法只展示限流,其余不展示;
在 Spring Boot 中,如果你通过 @Bean 手动创建了 RateLimiterRegistry,YAML 中的配置会被完全忽略。此时 application.yml 中的 resilience4j.ratelimiter 配置不会生效 
要使用YML配置生效,我们只需要把RateLimiterRegistry注销即可,不注入Spring即可。

Application.yml中有两个配置

        1、一种是配置baseConfig为default默认值;

resilience4j.ratelimiter.metrics.enabled=true
resilience4j.ratelimiter.instances.rateLimiterApi(自定义的限流器实例名称).baseConfig=default
resilience4j.ratelimiter.instances.otherApi(自定义的限流器实例名称).baseConfig=default

        2、一种是直接配置具体的参数:

# 注意:rateLimiterApi是限流器实例名称,可以任意取;同样的可以配置多个实例
resilience4j.ratelimiter.metrics.enabled=true                                           # 是否启用
resilience4j.ratelimiter.instances.rateLimiterApi.register-health-indicator=true        # 注册健康指标,可用于健康检查端点
resilience4j.ratelimiter.instances.rateLimiterApi.limit-for-period=1                    # 每个时间段允许的请求数(即限流阈值)
resilience4j.ratelimiter.instances.rateLimiterApi.limit-refresh-period=60s              # 限流刷新时间间隔(这里是60秒)
resilience4j.ratelimiter.instances.rateLimiterApi.timeout-duration=0s                   # 获取许可的最大等待时间为0秒(即不等待)
resilience4j.ratelimiter.instances.rateLimiterApi.allow-health-indicator-to-fail=true   # 即使限流触发失败,健康检查也视为通过
resilience4j.ratelimiter.instances.rateLimiterApi.subscribe-for-events=true             # 启用事件订阅,可用于监听限流事件
resilience4j.ratelimiter.instances.rateLimiterApi.event-consumer-buffer-size=50         # 限流事件消费者的缓冲区大小resilience4j.ratelimiter.instances.otherApi1.register-health-indicator=true        # 注册健康指标,可用于健康检查端点
resilience4j.ratelimiter.instances.otherApi1.limit-for-period=5                    # 每个时间段允许的请求数(即限流阈值)
resilience4j.ratelimiter.instances.otherApi1.limit-refresh-period=60s              # 限流刷新时间间隔(这里是60秒)
resilience4j.ratelimiter.instances.otherApi1.timeout-duration=0s                   # 获取许可的最大等待时间为0秒(即不等待)
resilience4j.ratelimiter.instances.otherApi1.allow-health-indicator-to-fail=true   # 即使限流触发失败,健康检查也视为通过
resilience4j.ratelimiter.instances.otherApi1.subscribe-for-events=true             # 启用事件订阅,可用于监听限流事件
resilience4j.ratelimiter.instances.otherApi1.event-consumer-buffer-size=50         # 限流事件消费者的缓冲区大小resilience4j.ratelimiter.instances.otherApi2.register-health-indicator=true        # 注册健康指标,可用于健康检查端点
resilience4j.ratelimiter.instances.otherApi2.limit-for-period=5                    # 每个时间段允许的请求数(即限流阈值)
resilience4j.ratelimiter.instances.otherApi2.limit-refresh-period=60s              # 限流刷新时间间隔(这里是60秒)
resilience4j.ratelimiter.instances.otherApi2.timeout-duration=0s                   # 获取许可的最大等待时间为0秒(即不等待)
resilience4j.ratelimiter.instances.otherApi2.allow-health-indicator-to-fail=true   # 即使限流触发失败,健康检查也视为通过
resilience4j.ratelimiter.instances.otherApi2.subscribe-for-events=true             # 启用事件订阅,可用于监听限流事件
resilience4j.ratelimiter.instances.otherApi2.event-consumer-buffer-size=50         # 限流事件消费者的缓冲区大小

Java代码中的配置RateLimiterRegistry Bean

/*** 可以直接全部在YML中配置,而不使用Resilience4jConfig;* 因为我们一旦统一定义了**Registry以后,我们在使用的时候貌似只能同时使用这一个配置...* 比如:当我们定义了RateLimiterRegistry以后,我们在使用的时候的就可以“@RateLimiter(name="xxx")”,这个xxx随便什么名字都会被应用到这个bean的配置,好像也只能这一个配置...*/
@Configuration
public class Resilience4jConfig {// 限流配置@Beanpublic RateLimiterRegistry rateLimiterRegistry() {RateLimiterConfig config = RateLimiterConfig.custom().limitRefreshPeriod(Duration.ofSeconds(60)) // 刷新周期是多少秒.limitForPeriod(1) // 每个周期内允许多少个请求.timeoutDuration(Duration.ofMillis(0)) // 等待时间.build();
//         return RateLimiterRegistry.of(config);// 手动注册实例 "rateLimiterApi" --- 但是我测试以后,系统好像会自动注入...不需要定义...rateLimiterApi// 如果是想使用自定义实例名称,那么使用下面的方法即可RateLimiterRegistry registry = RateLimiterRegistry.of(config);registry.rateLimiter("rateLimiterApi(自定义名称)", config);return registry;}
}

限流器使用

coontroller

请求地址:XXX/rate-limiter

效果展示:60s内连续请求2次,第二次将被限流;

限流器状态:/actuator/ratelimiters

// 正常情况下,按照上面limitRefreshPeriod=60,limitForPeriod=1的配置,1分钟内连续请求1次就会被限制;
@RestController
public class Resilience4JController {@Autowiredprivate Resilience4JService resilience4JService;@GetMapping("/rate-limiter")public String rateLimiter() {String uid = UUID.randomUUID().toString().replace("-", "");long time = System.currentTimeMillis();System.out.println(uid + ",请求时间: " + time);String result = resilience4JService.rateLimiterExample(time, uid);if (("限流示例:" + uid).equals(result)) {return uid + ",未被限流:" + time;}return uid + ",限流:" + time;}
}
service

如果被限流,那么系统是不会进入到service方法内部...

@Service
public class Resilience4JService {@RateLimiter(name="rateLimiterApi") //如果使用的是创建RateLimiterRegistry,那么此处名字好像无所谓...否则要和application.yml中对应public String rateLimiterExample(Long time,String uid) {System.out.println(uid+" 未被限流... " + time);return "限流示例:"+uid;}
}
另外一种写法

此种方法如果被限流的话,那么系统返回的是“限流异常全局处理“是全局异常处理获取到的;并且不会进入rateLimiter方法内部

    @GetMapping("/rate-limiter")@RateLimiter(name="rateLimiterApi") //如果使用的是创建RateLimiterRegistry,那么此处名字好像无所谓...否则要和application.yml中对应public String rateLimiter() {String uid = UUID.randomUUID().toString().replace("-", "");long time = System.currentTimeMillis();return uid + ",未被限流:" + time;}

Step3、熔断CircuitBreaker

请求地址:xxxx/circuit-breaker?shouldFail=true

效果:我们的外部服务模拟直接抛出异常,所以系统会进入到异常处理,返回异常处理信息;

熔断器状态:actuator/circuitbreakers

coontroller

    @GetMapping("/circuit-breaker")public String circuitBreaker(@RequestParam(defaultValue = "false") boolean shouldFail) throws InterruptedException {System.out.println("进入Resilience4JController");return resilience4JService.circuitBreakerExample(shouldFail);}

 service

本地异常处理、全局异常处理

    // 熔断示例@CircuitBreaker(name = "circuitBreakerApi") // 回到全局异常public String circuitBreakerExample(boolean shouldFail) throws InterruptedException {System.out.println("进入全局 Resilience4JService");return externalApiService.callExternalApi(shouldFail);}// 使用本地异常
@CircuitBreaker(name = "circuitBreakerApi", fallbackMethod = "circuitBreakerFallback")public String circuitBreakerLocalFallbackExample(boolean shouldFail) throws InterruptedException {System.out.println("进入本地loalfallback Resilience4JService");return externalApiService.callExternalApi(shouldFail);}public String circuitBreakerFallback(boolean shouldFail, Exception e) {return "熔断回退: 本地返回服务不可用";}

Step4、隔板Bulkhead --- 也可以当并发限制

请求地址:/bulkhead (不使用JMeter);/bulkhead_jmeter(使用JMeter)

状态:/actuator/bulkheads

效果:不使用JMeter时----本文使用的是信号量方式,并且支持并发数为2---即只允许同时处理2个请求,且每个线程只等待1ms,1ms以后没有进入到系统,就会被抛出异常处理里面的内容,并且在通过浏览器直接访问接口的时候,系统会直接返回“测试...”;

注意:

        要测试bulkhead就需要用JMeter之类的测试工具才有效果,不然的话就可以使用for循环的形式,但是这种方法就没法使用全局异常了...;

        resilience4j的Bulkhead默认使用的是Bulkhead.Type.SEMAPHORE信号量,如果要使用Bulkhead.Type.THREADPOOL可以在使用时设置type=Bulkhead.Type.THREADPOOL,但是这种方法需要设置系统默认的线程池参数....

        像@Bulkhead、@TimeLimiter这个是强制要求返回值类型为“CompletionStage”不然要报错---这是强制要求

io.github.resilience4j.spring6.timelimiter.configure.IllegalReturnTypeException: java.lang.String com.lting.resilience4j.service.Resilience4JService#timeLimiterExample has unsupported by @TimeLimiter return type. CompletionStage expected. at io.github.resilience4j.spring6.timelimiter.configure.TimeLimiterAspect.proceed(TimeLimiterAspect.java:106) ~[resilience4j-spring6-2.3.0.jar:2.3.0]

controller

    @GetMapping("/bulkhead/")public CompletableFuture<String> bulkhead() throws ExecutionException, InterruptedException {// 因为本例为了测试并发,使用for循环同时发送多个请求;// 而全局异常拦截的话要同步返回才行,所以在这个案例中的全局异常是不生效的.for (int i = 0; i < 5; i++) {resilience4JService.bulkheadLocalFallbackExample().whenComplete((result, throwable) -> {if (throwable == null) {System.out.println("返回值:" + result);} else {System.out.println("错误:" + throwable.getMessage());}});}return CompletableFuture.completedFuture("测试...");}// 可以使用JMeter工具测试这个接口 --- 这是同步返回结果@GetMapping("/bulkhead_jmeter/")public CompletableFuture<String> bulkhead1() throws ExecutionException, InterruptedException {return resilience4JService.bulkheadExample();}

service

    /*** 隔板示例 -- 并发** @return* @throws InterruptedException* @Bulkhead(name = "bulkheadApi") //使用全局异常处理 ----* @Bulkhead(name = "bulkheadApi", type= Bulkhead.Type.THREADPOOL, fallbackMethod = "bulkheadFallback")* type: 默认使用的是 Bulkhead.Type.SEMAPHORE,如果使用Bulkhead.Type.THREADPOOL需要配置线程池相关参数:* 线程池参考:* spring:*   task:*     execution:*       pool:*         core-size: 5*         max-size: 10*         queue-capacity: 100* 注意,Bulkhead要求的返回值类型为"CompletionStage",如果返回其他会报错,* 本案例是为了测试并发,所以在controller中使用的是for循环,请求进来后会直接返回字符串"测试...",是相当于异步并发请求了service;* 但是全局异常要同步返回才行,所以在本案例中,如果要使用全局异常处理就不能使用"CompletableFuture.supplyAsync";或者将返回值修改为同步,并使用JMeter之类的并发测试工具才能看到效果;* 不然全局异常要失效,无法拦截,** 具体原因如下: BulkheadFullException 是在 异步线程supplyAsync中抛出的异常,而我的 @ExceptionHandler 只能处理 同步请求主线程中的异常。* 所以,即使 Resilience4j 抛出了 BulkheadFullException,它也是发生在我的异步执行的那个线程里(比如 ForkJoinPool 或者自己定义的线程池),而不是 Spring MVC 的控制器主线程中。* 即: 因为是异步,控制器方法 bulkhead() 很快就返回了 。所有异常都发生在异步回调中,不会进入 Spring MVC 的异常处理流程(@ControllerAdvice / @ExceptionHandler)。*/// 本地异常返回
//    @Bulkhead(name = "bulkheadApi",type = Bulkhead.Type.THREADPOOL, fallbackMethod = "bulkheadFallback")@Bulkhead(name = "bulkheadApi", fallbackMethod = "bulkheadFallback")public CompletableFuture<String> bulkheadLocalFallbackExample() throws InterruptedException {System.out.println("局部并发拦截 进入成功...");return CompletableFuture.supplyAsync(() -> {try {return externalApiService.callExternalApi(false);} catch (InterruptedException e) {throw new RuntimeException(e);}});}public CompletableFuture<String> bulkheadFallback(Exception e) {return CompletableFuture.completedFuture("Bulkhead 回退: 并发请求过多,本地fallback返回");}@Bulkhead(name = "bulkheadApi") // 使用JMeter就可以使用全局异常public CompletableFuture<String> bulkheadExample() throws InterruptedException {System.out.println("全局并发拦截 进入成功...");// 同步返回
//        return CompletableFuture.completedFuture(externalApiService.callExternalApi(false));// 异步返回return CompletableFuture.supplyAsync(() -> {try {return externalApiService.callExternalApi(false);} catch (InterruptedException e) {throw new RuntimeException(e);}});}

Step5、超时

请求地址:/time-limiter

效果: ---- 测试本例时,可以将ExternalApiService里面的休息时间设置长一点,本文设置的超时时间为2s如果2s没有返回那么系统回返回全局异常/本地异常处理里面的内容

状态:/actuator/timelimiters

controller

    @GetMapping("/time-limiter")public CompletableFuture<String> timeLimiter() throws InterruptedException {return resilience4JService.timeLimiterExample();}

service

    // 超时示例/*** 注意:TimeLimiterl类要求强制返回CompletionStage,如果返回的是String\List什么的话要报错...* 报错:* io.github.resilience4j.spring6.timelimiter.configure.IllegalReturnTypeException: xxxxx timeLimiterExample has unsupported by @TimeLimiter return type. CompletionStage expected.* 	at io.github.resilience4j.spring6.timelimiter.configure.TimeLimiterAspect.proceed(TimeLimiterAspect.java:106) ~[resilience4j-spring6-2.3.0.jar:2.3.0]* @return* @throws InterruptedException*/@TimeLimiter(name = "timeLimiterApi") // 使用全局异常public CompletableFuture<String> timeLimiterExample() throws InterruptedException {return CompletableFuture.supplyAsync(()->{try {return externalApiService.callExternalApi(false);} catch (InterruptedException e) {throw new RuntimeException(e);}});}// 超时使用本地异常返回@TimeLimiter(name = "timeLimiterApi", fallbackMethod = "timeLimiterFallback")public CompletableFuture<String> timeLimiterLocalFallbackExample() throws InterruptedException {return CompletableFuture.supplyAsync(()->{try {return externalApiService.callExternalApi(false);} catch (InterruptedException e) {throw new RuntimeException(e);}});}public CompletableFuture<String> timeLimiterFallback(Exception e) {return CompletableFuture.completedFuture("时间限制器回退:操作超时,本地返回");}

Step6、重试Retry

请求地址:/retry?shouldFail=true

效果: 因为我们设置的shouldFail=true,模拟第三方API会一直失败,所以系统重试三次后就会返回异常处理里面的内容;

状态:/actuator/retries

controller

    @GetMapping("/retry")public String retry(@RequestParam(defaultValue = "false") boolean shouldFail) throws InterruptedException {return resilience4JService.retryExample(shouldFail);}

service

    // 重试示例
//    @Retry(name = "retryApi", fallbackMethod = "retryFallback") // 局部异常@Retry(name = "retryApi") // 全局异常public String retryExample(boolean shouldFail) throws InterruptedException {return externalApiService.callExternalApi(shouldFail);}public String retryFallback(boolean shouldFail, Exception e) {return "重试回退: 太多重试错误";}

Step7、综合使用

--- 这一步优化

controller

    @GetMapping("/composite")public CompletableFuture<String> composite(@RequestParam(defaultValue = "false") boolean shouldFail) {return resilience4JService.compositeExample(shouldFail);}

service

注意:compositeApi的参数在application.yml中配置,已经暂时注释掉了,如果有需要开启即可。

    // 组合使用示例@CircuitBreaker(name = "compositeApi", fallbackMethod = "compositeFallback")@RateLimiter(name = "compositeApi")@Bulkhead(name = "compositeApi")@Retry(name = "compositeApi", fallbackMethod = "compositeFallback")@TimeLimiter(name = "compositeApi", fallbackMethod = "compositeFallback")public CompletableFuture<String> compositeExample(boolean shouldFail) {return CompletableFuture.supplyAsync(() -> {try {return externalApiService.callExternalApi(shouldFail);} catch (InterruptedException e) {throw new RuntimeException(e);}});}public CompletableFuture<String> compositeFallback(boolean shouldFail, Exception e) {return CompletableFuture.completedFuture("综合使用回退: " + e.getMessage());}

Sentinel

.........算了算了。..太多了。不写了。下次写。

瑞士白~~~~...

相关文章:

服务容错治理框架resilience4jsentinel基础应用---微服务的限流/熔断/降级解决方案

写在前文&#xff1a;hystrix停止维护&#xff0c;不做总结&#xff1b; 本文主要总结sentinel和resilience4j这两个框架&#xff1b;另外额外补充面试可能会问到的限流算法&#xff1b; 目录 限流算法 漏桶算法 计数器算法 令牌桶算法 resilience4j与sentinel resilie…...

信创系统图形界面开发指南:技术选择与实践详解

信创系统图形界面开发指南&#xff1a;技术选择与实践详解 &#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&…...

六、UI自动化测试06--PO设计模式

目录 一、PO 设计模式1. v1 版本1.1 v1.11.2 v1.2 2. v2 版本3. ⽅法封装套路4. v3 版本4.1 浏览器对象管理类的实现4.2 浏览器对象管理类的优化4.3 浏览器对象管理类的使⽤4.4 获取弹窗信息⽅法的封装 5. PO 设计模式6. v4 版本6.1 PO⻚⾯元素封装步骤6.2 测试⽤例的最终代码样…...

电子病历高质量语料库构建方法与架构项目(智能数据目录篇)

电子病历高质量语料库的构建是医疗人工智能发展的基础性工作,而智能数据目录作为数据治理的核心组件,能够有效管理这些语料资源。本文将系统阐述电子病历高质量语料库的构建方法与架构,特别聚焦于智能数据目录的设计与实现,包括数据目录的功能定位、元数据管理、构建步骤以…...

DeepSeek最新大模型发布-DeepSeek-Prover-V2-671B

2025 年 4 月 30 日&#xff0c;DeepSeek 开源了新模型 DeepSeek-Prover-V2-671B&#xff0c;该模型聚焦数学定理证明任务&#xff0c;基于混合专家架构&#xff0c;使用 Lean 4 框架进行形式化推理训练&#xff0c;参数规模达 6710 亿&#xff0c;结合强化学习与大规模合成数据…...

论文公式根据章节自动编号教程

目录 一、操作前提二、具体操作步骤 插入公式编号添加括号&#xff08;如需&#xff09; 问答 摘要&#xff1a; 在撰写论文等文档时&#xff0c;让公式根据章节自动编号能大幅提升排版效率。 一、操作前提 先将每一章标题设置为多级标题。可点击Word“多级列表” - “定义…...

「Mac畅玩AIGC与多模态10」开发篇06 - 使用自定义翻译插件开发智能体应用

一、概述 本篇介绍如何在 macOS 环境下,通过编写自定义 OpenAPI Schema,将无需认证的翻译服务接入 Dify 平台,并开发基于实时翻译的智能体应用。本案例培养单提参数 API 调用技巧,实现智能体的实时转换能力。 二、环境准备 1. 确认本地开发环境 macOS 系统Dify 平台已成…...

大连理工大学选修课——机器学习笔记(8):Boosting及提升树

Boosting及提升树 Boosting概述 Bootstrap强调的是抽样方法 不同的数据集彼此独立&#xff0c;可并行操作 Boosting注重数据集改造 数据集之间存在强依赖关系&#xff0c;只能串行实现 处理的结果都是带来了训练集改变&#xff0c;从而得到不同的学习模型 Boosting基本思…...

OpenHarmony - 小型系统内核(LiteOS-A)(十七)标准库

OpenHarmony - 小型系统内核&#xff08;LiteOS-A&#xff09;&#xff08;十七&#xff09; 二十一、标准库 OpenHarmony内核使用musl libc库&#xff0c;支持标准POSIX接口&#xff0c;开发者可基于POSIX标准接口开发内核之上的组件及应用。 标准库接口框架 图1 POSIX接口…...

vscode详细配置Go语言相关插件

文章目录 vscode详细配置Go语言1.插件介绍1.1 BetterCommments1.2GitGraph1.3Go1.4GoComment1.5goctl1.6Lowlight Go Errors1.7Markdown1.8Material Icon Theme1.9Preetier2.0Project Manager其它插件 2.settings.json文件 vscode详细配置Go语言 1.插件介绍 1.1 BetterCommme…...

如何解决服务器文件丢失或损坏的问题

当服务器文件丢失或损坏时&#xff0c;需采取系统化的恢复和预防措施。以下是分步骤解决方案&#xff1a; --- ### **一、紧急恢复措施** #### 1. **检查文件系统完整性** bash # 对未挂载的分区进行检查&#xff08;需先umount&#xff09; fsck -y /dev/sdX # 针对ext4文…...

【C++11】包装器:function 和 bind

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲C11——包装器&#xff1a;function和bind&#xff0c;对于每个包装器主要讲解&#xff1a; 原型基本语法使用示例 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;C学习笔记 &#x1f380…...

芯知识|小体积语音芯片方案WTV/WT2003H声音播放ic应用解析

在智能硬件设备趋向微型化的背景下&#xff0c;语音芯片方案厂家针对小体积设备开发了多款超小型语音芯片方案&#xff0c;其中WTV系列和WT2003H系列凭借其QFN封装设计、高性能与高集成度&#xff0c;成为微型设备语音方案的理想选择。以下从封装特性、功能优势及典型应用场景三…...

第三部分:特征提取与目标检测

像边缘、角点、特定的纹理模式等都是图像的特征。提取这些特征是许多计算机视觉任务的关键第一步&#xff0c;例如图像匹配、对象识别、图像拼接等。目标检测则是在图像中找到特定对象&#xff08;如人脸、汽车等&#xff09;的位置。 本部分将涵盖以下关键主题&#xff1a; …...

MySQL bin目录下的可执行文件

文章目录 MySQL bin目录下的可执行文件1.mysqldump2.mysqladmin3.mysqlcheck4.mysqlimport5.mysqlshow6.mysqlbinlog7.常用可执行文件 MySQL bin目录下的可执行文件 1.mysqldump mysqldump 是 MySQL 的数据库备份工具。对数据备份、迁移或恢复非常重要。 备份整个数据库&…...

第四部分:赋予网页健壮的灵魂 —— TypeScript(中)

目录 4 类与面向对象&#xff1a;构建复杂的组件4.1 类的定义与成员4.2 继承 (Inheritance)4.3 接口实现 (Implements)4.4 抽象类 (Abstract Class)4.5 静态成员 (Static Members) 5 更高级的类型&#xff1a;让类型系统更灵活5.1 联合类型 (|)5.2 交叉类型 (&)5.3 字面量类…...

Learning vtkjs之ImageMarchingCubes

体积 等值面处理 介绍 vtkImageMarchingCubes - 对体积进行等值面处理 给定一个指定的等值&#xff0c;使用Marching Cubes算法生成一个等值面。 效果 新建了一个球&#xff0c;对比一下原始的&#xff08;透明的&#xff09;和ISO的效果 核心代码 参数部分 const updat…...

【“星睿O6”AI PC开发套件评测】+ tensorflow 初探

因为本次我的项目计划使用 tensorflow&#xff0c;所以这篇文章主要想做一个引子&#xff0c;介绍如何在“星睿O6”上搭建 tensorflow 的开发环境和验证测试。本文主要分为几个部分&#xff1a; 在“星睿O6”上编译安装 tensorflow基于 MNIST 数据集的模型训练和评估 tensorf…...

通义灵码全面接入Qwen3:AI编程进入智能体时代,PAI云上部署实战解析

引言&#xff1a;AI编程的范式革命 2025年4月30日&#xff0c;阿里云通义灵码宣布全面支持新一代大模型Qwen3&#xff0c;并同步推出编程智能体功能&#xff0c;标志着AI辅助开发从“工具助手”向“自主决策智能体”的跃迁。与此同时&#xff0c;阿里云PAI平台上线Qwen3全系列…...

如何禁止AutoCAD这类软件联网

推荐二、三方法&#xff0c;对其他软件影响最小 一、修改Hosts文件 Hosts文件是一个存储域名与IP地址映射关系的文本文件&#xff0c;通过修改Hosts文件可以将AutoCAD的域名指向本地回环地址&#xff08;127.0.0.1&#xff09;&#xff0c;从而实现禁止联网的目的。具体步骤如…...

音视频项目在微服务领域的趋势场景题深度解析

音视频项目在微服务领域的趋势场景题深度解析 在互联网大厂Java求职者的面试中&#xff0c;经常会被问到关于音视频项目在微服务领域的应用场景的相关问题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我…...

100 个 NumPy 练习

本文翻译整理自&#xff1a;https://github.com/rougier/numpy-100 文章目录 关于 100 个 NumPy 练习相关链接资源关键功能特性 100 个 NumPy 练习题1、导入 NumPy 包并命名为 np (★☆☆)2、打印 NumPy 版本和配置信息 (★☆☆)3、创建一个大小为 10 的空向量 (★☆☆)4、如何…...

在Carla中构建自动驾驶:使用PID控制和ROS2进行路径跟踪

机器人软件开发什么是 P、PI 和 PID 控制器&#xff1f;比例 &#xff08;P&#xff09; 控制器比例积分 &#xff08;PI&#xff09; 控制器比例-积分-微分 &#xff08;PID&#xff09; 控制器横向控制简介CARLA ROS2 集成纵向控制横向控制关键要点结论引用 机器人软件开发 …...

Windows和 macOS 上安装 `nvm` 和 Node.js 16.16.0 的详细教程。

Windows和 macOS 上安装 nvm 和 Node.js 16.16.0 的详细教程。 --- ### 1. 安装 nvm&#xff08;Node Version Manager&#xff09; nvm 是一个 Node.js 版本管理工具&#xff0c;可以轻松安装和切换不同版本的 Node.js。 #### Windows 安装 nvm 1. **下载 nvm 安装包**&#x…...

day11 python超参数调整

模型组成&#xff1a;模型 算法 实例化设置的外参&#xff08;超参数&#xff09; 训练得到的内参调参评估&#xff1a;调参通常需要进行两次评估。若不使用交叉验证&#xff0c;需手动划分验证集和测试集&#xff1b;但许多调参方法自带交叉验证功能&#xff0c;实际中可省略…...

Linux C++ xercesc xml 怎么判断路径下有没有对应的节点

在Linux环境下使用Xerces-C库处理XML文件时&#xff0c;判断路径下是否存在对应的节点可以通过以下几个步骤实现&#xff1a; 加载XML文档 首先&#xff0c;你需要加载XML文档。这可以通过创建一个xercesc::DOMParser对象并使用它的parse方法来实现。 #include <xercesc/…...

罗技K580蓝牙键盘连接mac pro

罗技K580蓝牙键盘&#xff0c;满足了我们的使用需求。最棒的是&#xff0c;它能够同时连接两个设备&#xff0c;通过按F11和F12键进行切换&#xff0c;简直不要太方便&#xff01; 连接电脑 &#x1f4bb; USB连接 1、打开键盘&#xff1a;双手按住凹槽两边向前推&#xff0…...

Socket-UDP

Socket&#xff08;套接字 &#xff09;是计算机网络中用于实现进程间通信的重要编程接口&#xff0c;是对 TCP/IP 协议的封装 &#xff0c;可看作是不同主机上应用进程之间双向通信端点的抽象。以下是详细介绍&#xff1a; 作用与地位 作为应用层与传输层、网络层协议间的中…...

【游戏ai】从强化学习开始自学游戏ai-2 使用IPPO自博弈对抗pongv3环境

文章目录 前言一、环境设计二、动作设计三、状态设计四、神经网路设计五、效果展示其他问题总结 前言 本学期的大作业&#xff0c;要求完成多智能体PPO的乒乓球对抗环境&#xff0c;这里我使用IPPO的方法来实现。 正好之前做过这个单个PPO与pong环境内置的ai对抗的训练&#…...

LeRobot 项目部署运行逻辑(三)——机器人及舵机配置

Lerobot 目前的机器人硬件以舵机类型为主&#xff0c;并未配置机器人正逆运动学及运动学&#xff0c;遥操作映射以舵机关节角度为主 因此&#xff0c;需要在使用前需要对舵机各项参数及初始位置进行配置 目录 1 Mobile ALOHA 配置 2 Dynamixel 配置 2.1 配置软件 2.2 SDK …...

Ubuntu20.04安装NVIDIA Warp

Ubuntu20.04安装NVIDIA Warp 安装测试 Warp的gitee网址 Warp的github网址 写在前面&#xff1a;建议安装前先参考readme文件自检系统驱动和cuda是否支持&#xff0c;个人实测建议是python3.9&#xff0c;但python3.8.20也可以使用。 写在前面&#xff1a;后续本人可能会使用这…...

电子病历高质量语料库构建方法与架构项目(临床情景理解模块篇)

引言 随着人工智能技术在医疗健康领域的广泛应用,电子病历(Electronic Medical Records,EMR)作为临床医疗数据的重要载体,已成为医学研究和临床决策支持的关键资源。电子病历高质量语料库的构建为医疗人工智能模型的训练和应用提供了基础支撑,其中临床情境理解模块是连接…...

WPF性能优化举例

WPF性能优化集锦 一、UI渲染性能优化 1. 虚拟化技术 ​​ListView/GridView虚拟化​​: <ListView VirtualizingStackPanel.IsVirtualizing="True"VirtualizingStackPanel.VirtualizationMode="Recycling"ScrollViewer.IsDeferredScrollingEnabled=…...

【CUDA pytorch】

ev win10 3050ti 联想笔记本 nvcc --version 得到 PS C:\Users\25515> nvcc --version nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2022 NVIDIA Corporation Built on Tue_May__3_19:00:59_Pacific_Daylight_Time_2022 Cuda compilation tools, release …...

mac下载homebrew 安装和使用git

mac下载homebrew 安装和使用git 本人最近从windows换成mac&#xff0c;记录一下用homebrew安装git的过程 打开终端 command 空格&#xff0c;搜索终端 安装homebrew 在终端中输入下面命令&#xff0c;来安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githu…...

Elasticsearch入门速通01:核心概念与选型指南

一、Elasticsearch 是什么&#xff1f; 一句话定义&#xff1a; 开源分布式搜索引擎&#xff0c;擅长处理海量数据的实时存储、搜索与分析&#xff0c;是ELK技术栈&#xff08;ElasticsearchKibanaBeatsLogstash&#xff09;的核心组件。 核心能力&#xff1a; 近实时搜索&…...

应对过度处方挑战:为药物推荐任务微调大语言模型(Xiangnan He)

Abstract 药物推荐系统因其有潜力根据患者的临床数据提供个性化且有效的药物组合&#xff0c;在医疗保健领域备受关注。然而&#xff0c;现有方法在适应不同的电子健康记录&#xff08;EHR&#xff09;系统以及有效利用非结构化数据方面面临挑战&#xff0c;导致其泛化能力有限…...

41 python http之requests 库

Python 的requests库就像你的 "接口助手",用几行代码就能发送 HTTP 请求,自动处理复杂的网络交互,让你告别手动拼接 URL 和解析响应的痛苦! 一、快速入门:3 步搞定基本请求 1.1 安装库:一键开启助手功能 pip install requests 1.2 发送 GET 请求 import r…...

百度网盘golang实习面经

goroutine内存泄漏的情况&#xff1f;如何避免&#xff1f; goroutine内存泄漏基本上是因为异常导致阻塞, 可以导致阻塞的情况 1 死锁, goroutine 等待的锁发生了死锁情况 2 chan没有正常被关闭,导致读取读chan的goroutine阻塞 如何避免 1 避免死锁 2 正常关闭 3 使用context管…...

super_small_toy_tpu

super_small_toy_tpu 小狼http://blog.csdn.net/xiaolangyangyang 1、基础框图 2、源码下载&#xff1a; GitHub - dldldlfma/super_small_toy_tpu 3、安装iverilog、vvp、gtkwave windows安装&#xff1a;https://bleyer.org/icarus/ ubuntu安装&#xff1a;sudo ap…...

Redis缓存穿透、缓存击穿与缓存雪崩:如何在.NET Core中解决

在高并发的互联网系统中&#xff0c;缓存技术作为优化系统性能的重要手段&#xff0c;已被广泛应用。然而&#xff0c;缓存系统本身也存在一些常见的问题&#xff0c;尤其是 缓存穿透、缓存击穿 和 缓存雪崩。这些问题如果处理不当&#xff0c;可能导致系统性能严重下降&#x…...

驱动车辆诊断测试创新 | 支持诊断测试的模拟器及数据文件转换生成

一 背景和挑战 | 背景&#xff1a; 随着汽车功能的日益丰富&#xff0c;ECU和域控制器的复杂性大大增加&#xff0c;导致测试需求大幅上升&#xff0c;尤其是在ECU的故障诊断和性能验证方面。然而&#xff0c;传统的实车测试方法难以满足高频率迭代和验证需求&#xff0c;不仅…...

VS Code技巧2:识别FreeCAD对象

在使用VS Code阅读FreeCAD代码或者FreeCAD的工作台代码时&#xff0c;VS Code无法识别FreeCAD对象&#xff0c;会提示Import “FreeCAD” could not be resolved&#xff1a; 问题解决如下几步即可。 第一步&#xff1a;确认 FreeCAD 的 Python 环境路径 在FreeCAD的Python控制…...

泰迪杯特等奖案例学习资料:基于多模态融合与边缘计算的智能温室环境调控系统

(第十二届泰迪杯数据挖掘挑战赛特等奖案例解析) 一、案例背景与核心挑战 1.1 应用场景与行业痛点 在现代设施农业中,温室环境调控直接影响作物产量与品质。传统温室管理存在以下问题: 环境参数耦合性高:温度、湿度、光照、CO₂浓度等参数相互影响,人工调控易顾此失彼。…...

猿人学web端爬虫攻防大赛赛题第13题——入门级cookie

1. F12开发者模式 刷新第一页&#xff0c;仔细研究发现里面有三次请求名为13的请求&#xff0c;根据题目提示cookie关键字&#xff0c;所以主要留意请求和响应的cookie值。 三次请求都带了sessionid&#xff0c;说明存在session&#xff08;后面写代码要用session来写&#x…...

机器指标监控技术方案

文章目录 机器指标监控技术方案架构图组件简介Prometheus 简介核心特性适用场景 Grafana 简介核心特性适用场景 Alertmanager 简介核心特性适用场景 数据采集机器Node ExporterMySQL ExporterRedis ExporterES ExporterRocketMQ ExporterSpringcloud ExporterNacos 数据存储短期…...

数据库设计理论:从需求分析到实现的全流程解析

引言 在当今信息爆炸的时代&#xff0c;数据已成为企业和组织最宝贵的资产之一。如何有效地组织、存储和管理这些数据&#xff0c;是数据库设计需要解决的核心问题。一个优秀的数据库设计能够提高系统性能&#xff0c;确保数据一致性&#xff0c;降低维护成本&#xff0c;而糟…...

一文详解 Linux下的开源打印系统CUPS(Common UNIX Printing System)

文章目录 前言一、CUPS 简介二、CUPS 常用指令解析2.1 安装 CUPS2.2 启动/重启服务2.3 添加打印机&#xff08;核心操作&#xff09;2.4 设置默认打印机2.5 打印文件2.6 查看打印任务2.7 取消打印任务2.8 查看、移除已添加的打印机 三、调试与常见问题3.1 日志查看3.2 驱动问题…...

uniapp打包apk详细教程

目录 1.打apk包前提条件 2.获取uni-app标识 3.进入dcloud开发者后台 4.开始打包 1.打apk包前提条件 1.在HBuilderX.exe软化中&#xff0c;登录自己的账号 2.在dcloud官网&#xff0c;同样登录自己的账号。没有可以免费注册。 2.获取uni-app标识 获取方法&#xff1a;点…...

C++初阶-string类2

目录 1.迭代器 1.1普通迭代器的使用 1.2string::begin 1.3string::end 1.4const迭代器的使用 1.5泛型迭代器和const反向迭代器 1.6string::rbegin 1.6string::rend 1.7string::cbegin、string::cend、string::crbegin、string::crend 与begin/end、rbegin/rend的区别 …...