Spring Boot - 利用Resilience4j-Circuitbreaker实现断路器模式_防止级联故障

文章目录

  • Pre
  • Resilience4j概述
  • Resilience4j官方地址
  • Resilience4j-Circuitbreaker
  • 应用场景
  • 微服务演示
    • Address service
      • POM
      • Model
      • Repository
      • Service
      • Controller
      • Data Init
      • Properties
      • 测试
    • Order service
      • Model
      • Repository
      • Service
      • Set Up
      • Properties
      • 测试
  • 探究断路器
    • 调用order-service API 2次
    • 关闭address-service,调用order-service API 3
    • 等待5秒,刷新执行器
    • 继续调用 order-service API 3 次
    • 运行address-service,然后继续调用order-service API 3次
  • 小结

在这里插入图片描述


Pre

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级


Resilience4j概述

Resilience4J 是一个针对 Java 8 应用程序的轻量级容错和弹性库。它设计用于在分布式系统中的服务之间提供弹性和容错性。Resilience4J 的名字来源于它提供的核心功能,即让系统(服务)能够“弹性”(resilient)地应对各种失败情况,包括网络问题、第三方服务故障等。

Resilience4J 提供了以下功能:

  1. 断路器(Circuit Breaker):当检测到服务异常或超时,断路器会打开,阻止进一步的请求发送到该服务。一段时间后(通常是秒级),断路器会进入半开状态,允许一个测试请求通过以检查服务是否恢复。如果请求成功,断路器关闭;如果失败,断路器会再次打开。
  2. 限流(Rate Limiter):限制进入系统的请求速率,防止系统过载。这可以通过令牌桶算法或滑动窗口算法实现。
  3. 隔离(Isolation):通过信号量或线程池隔离不同的服务调用,防止一个服务的失败影响到其他服务。
  4. 超时(Timeouts):为服务调用设置超时时间,超过时间后会触发超时异常。
  5. 重试(Retry):在遇到特定异常时自动重试服务调用,可以配置重试次数和间隔。
  6. 缓存(Caching):提供缓存机制,以避免重复执行计算密集型或远程调用。

Resilience4J 的一大特点是它的轻量级特性,它只使用了 Vavr 库(一个函数式编程库),没有其他外部库依赖。这使得它在集成到现有系统时非常方便,且性能开销小。

Resilience4J 设计上易于配置,支持通过代码、配置文件或运行时参数进行配置。它也支持通过 actuator 模块与 Spring Boot 的监控和管理特性集成。

由于 Resilience4J 的这些特性和优势,它在现代分布式系统和微服务架构中得到了广泛应用,尤其是在需要高可用性和弹性的环境中。


Resilience4j官方地址

https://resilience4j.readme.io/

在这里插入图片描述

https://github.com/resilience4j/resilience4j

在这里插入图片描述


Resilience4j-Circuitbreaker

Resilience4j中的CircuitBreaker是一个核心工具,用于保护分布式系统免受故障的影响。

其工作原理主要通过一个有限状态机实现,包括CLOSED(关闭)、OPEN(打开)和HALF-OPEN(半开)三种状态。

Resilience4j 是一个为Java 8和函数式编程设计的轻量级容错库。它的主要目的是帮助开发者在分布式系统中实现弹性和容错性。

Resilience4j 提供了多种容错机制,包括断路器(CircuitBreaker)、限流器(RateLimiter)、重试(Retry)、隔离策略(Bulkhead)和超时控制(TimeLimiter)等。其中,CircuitBreaker 是 Resilience4j 的一个重要组成部分。

CircuitBreaker,即断路器,其设计原理来源于电路中的断路器,当电流超过设定值时,断路器会自动断开,以保护电路免受过大电流的损害。在软件系统中,断路器用于保护系统免受某个组件或服务故障的影响。

Resilience4j 的 CircuitBreaker 实现原理如下:

  1. 断路器的状态:CircuitBreaker 具有三种正常状态:CLOSED(关闭)、OPEN(打开)和 HALFOPEN(半开),以及两个特殊状态:DISABLED(禁用)和 FORCEDOPEN(强制打开)。这些状态通过有限状态机进行管理。

  2. 打开和关闭逻辑:当被保护的服务或资源发生故障或长时间不可用时,断路器会迅速切换到 OPEN 状态,阻止更多的请求发送到该服务或资源。在 OPEN 状态下,系统会定期发送测试请求,以检查故障是否已经解决。如果测试请求成功,断路器会切换到 HALFOPEN 状态,允许一个请求发送到该服务或资源。如果这个请求成功,断路器会切换到 CLOSED 状态,否则会重新切换到 OPEN 状态。

  3. 故障率计算:为了判断是否打开断路器,需要收集一定数量的请求数据。在 Resilience4j 中,需要至少填充一个环形缓冲区(Ring Bit Buffer),才能开始计算故障率。环形缓冲区的大小决定了需要多少次请求才能进行故障率的计算。

  4. 环形缓冲区:Resilience4j 使用环形缓冲区来存储请求状态的数据结构,这与 Hystrix 使用的滑动窗口不同。环形缓冲区使用位集合(BitSet)实现,每个位代表一个请求的状态(成功或失败)。环形缓冲区的大小决定了能够存储的请求数量。例如,一个大小为 10 的缓冲区可以存储 1024 个请求状态。

  5. 配置选项:Resilience4j 提供了丰富的配置选项,如故障率阈值、打开状态下的等待时间、半开状态下允许的最大请求数等,开发者可以根据需求进行灵活配置。

通过上述原理,Resilience4j 的 CircuitBreaker 能够有效地保护分布式系统免受故障的影响,提高系统的可用性和健壮性。


应用场景

服务 A 调用服务 B,但不幸的是,服务 B 不可用或无法响应。因此,服务 A 可能会等待服务 B 的响应或处理遇到的异常。后续针对服务 B 的请求也会遇到类似的挑战,从而导致糟糕的用户体验。

在这种情况下,断路器可以通过在特定时间内停止请求发送,等待超时结束,启用有限数量的请求来检查服务 B 是否正常工作。如果这些请求成功,微服务就可以继续正常运行。如果没有,它将再次开始超时。

在这里插入图片描述

断路器具有三种状态:Closed、Open 和 Half_Open。

  • 闭合是断路器的初始状态。当微服务运行和交互顺利时,断路器就关闭了。它持续监控配置时间段内发生的故障数量。如果失败率超过指定的阈值,其状态将变为Open状态。如果没有,它将重置失败计数和超时时间
  • 在Open状态下,断路器会阻塞微服务之间的交互流程。请求调用将会失败,并且会抛出异常。 Open 状态保持直到超时结束,然后更改为 Half_Open 状态。
  • 在Half_Open状态下,断路器将允许有限数量的请求通过。如果失败率大于指定阈值,则再次切换到Open状态。否则为Closed状态。

微服务演示

在这里插入图片描述

有 2 个服务,名为地址服务和订单服务

在这里插入图片描述

  • 在购买之前,购物者希望查看订单的详细信息。他们向订单服务发送请求。
  • 订单服务使用邮政编码来调用地址服务以获取送货地址详细信息。
  • 收到送货地址详细信息后,订单服务会更新订单信息,然后将其发送回购物者。

Address service

首先构建地址服务,因为它是一个依赖服务.

在这里插入图片描述

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.edu</groupId>
    <artifactId>address-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>address-service</name>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


Model

package com.edu.addressservice.model;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "addresses")
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String postalCode;
    private String state;
    private String city;
}


Repository

package com.edu.addressservice.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.edu.addressservice.model.Address;

@Repository
public interface AddressRepository extends JpaRepository<Address, Integer> {
    Optional<Address> findByPostalCode(String postalCode);
}

Service

public interface AddressService {
    Address getAddressByPostalCode(String postalCode);
}
@Service
public class AddressServiceImpl implements AddressService {
    @Autowired
    private AddressRepository addressRepository;
    public Address getAddressByPostalCode(String postalCode) {
        return addressRepository.findByPostalCode(postalCode)
                .orElseThrow(() -> new RuntimeException("Address Not Found: " + postalCode));
    }
}

Controller

package com.edu.addressservice.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.edu.addressservice.model.Address;
import com.edu.addressservice.service.AddressService;

@RestController
@RequestMapping("addresses")
public class AddressController {
    @Autowired
    private AddressService addressService;
    @GetMapping("/{postalCode}")
    public Address getAddressByPostalCode(@PathVariable("postalCode") String postalCode) {
        return addressService.getAddressByPostalCode(postalCode);
    }
}


Data Init

@PostConstruct注解的方法。 Spring 将在初始化 bean 属性并填充数据后调用该方法。

package com.edu.addressservice.config;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import com.edu.addressservice.model.Address;
import com.edu.addressservice.repository.AddressRepository;

import jakarta.annotation.PostConstruct;

@Configuration
public class DataSetup {
    @Autowired
    private AddressRepository addressRepository;
    @PostConstruct
    public void setupData() {
        addressRepository.saveAll(Arrays.asList(
                Address.builder().id(1).postalCode("1000001").state("SD").city("JN")
                        .build(),
                Address.builder().id(2).postalCode("1100000").state("JS").city("NJ").build(),
                Address.builder().id(3).postalCode("2100001").state("ZJ").city("HZ")
                        .build()));
    }
}


Properties

server:
  port: 9090
spring:
  application:
    name: address-service
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: create-drop
  datasource:
    url: jdbc:h2:mem:address-db
    username: admin
    password: 1111
    driverClassName: org.h2.Driver
  h2:
    console:
      enabled: true


测试

运行并访问链接http://localhost:9090/addresses/1000001,预期响应应如下所示

在这里插入图片描述

这样就完成了地址服务的构建。


Order service

重点关注是如何配置断路器,并通过执行器监控其状态的。

在这里插入图片描述


Model

public interface Type {
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "orders")
public class Order implements Type {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    private String orderNumber;
    private String postalCode;
    private String shippingState;
    private String shippingCity;
}
@Data
public class Failure implements Type {
    private final String msg;
}

Repository

package com.edu.orderservice.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.edu.orderservice.model.Order;

@Repository
public interface OrderRepository extends JpaRepository<Order, Integer> {
    Optional<Order> findByOrderNumber(String orderNumber);
}


Service

业务逻辑都在这里了。

  • 从“orders”表中检索订单信息
  • 调用外部服务(地址服务)以获取送货地址信息
  • 使用送货地址详细信息更新订单信息,然后返回

如何调用外部API---------------------> Spring 提供的 RestTemplate

package com.edu.orderservice.service;

import com.edu.orderservice.model.Type;

public interface OrderService {
    Type getOrderByPostCode(String orderNumber);
}

package com.edu.orderservice.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.edu.orderservice.dto.AddressDTO;
import com.edu.orderservice.model.Failure;
import com.edu.orderservice.model.Order;
import com.edu.orderservice.model.Type;
import com.edu.orderservice.repository.OrderRepository;
import com.edu.orderservice.service.OrderService;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private RestTemplate restTemplate;
    private static final String SERVICE_NAME = "order-service";
    private static final String ADDRESS_SERVICE_URL = "http://localhost:9090/addresses/";

    @Override
    @CircuitBreaker(name = SERVICE_NAME, fallbackMethod = "fallbackMethod")
    public Type getOrderByPostCode(String orderNumber) {
        Order order = orderRepository.findByOrderNumber(orderNumber)
                .orElseThrow(() -> new RuntimeException("Order Not Found: " + orderNumber));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<AddressDTO> entity = new HttpEntity<>(null, headers);
        ResponseEntity<AddressDTO> response = restTemplate.exchange(
                (ADDRESS_SERVICE_URL + order.getPostalCode()), HttpMethod.GET, entity,
                AddressDTO.class);
        AddressDTO addressDTO = response.getBody();
        if (addressDTO != null) {
            order.setShippingState(addressDTO.getState());
            order.setShippingCity(addressDTO.getCity());
        }
        return order;
    }

    private Type fallbackMethod(Exception e) {
        return new Failure("Address service is not responding properly");
    }
}

@CircuitBreaker 属性

  • name”被分配为“order-service”,表名“order-service”实例的每个配置都适用于该方法。
  • fallbackMethod”属性,目的是在依赖服务(地址服务)未正确响应时调用降级方法。

Set Up

@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
package com.edu.orderservice.config;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import com.edu.orderservice.model.Order;
import com.edu.orderservice.repository.OrderRepository;

import jakarta.annotation.PostConstruct;

@Configuration
public class DataSetup {
    @Autowired
    private OrderRepository orderRepository;
    @PostConstruct
    public void setupData() {
        orderRepository.saveAll(Arrays.asList(
                Order.builder().id(1).orderNumber("0c70c0c2").postalCode("1000001").build(),
                Order.builder().id(2).orderNumber("7f8f9f15").postalCode("1100000").build(),
                Order.builder().id(3).orderNumber("394627b2").postalCode("2100001").build()));
    }
}


Properties

server:
  port: 1010
spring:
  application:
    name: order-service
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: create-drop
  datasource:
    url: jdbc:h2:mem:order-db
    username: root
    password: 123
    driverClassName: org.h2.Driver
  h2:
    console:
      enabled: true
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health
  health:
    circuitbreakers:
      enabled: true
resilience4j:
  circuitbreaker:
    instances:
      order-service:
        sliding-window-type: COUNT_BASED
        failure-rate-threshold: 50
        minimum-number-of-calls: 5
        automatic-transition-from-open-to-half-open-enabled: true
        wait-duration-in-open-state: 5s
        permitted-number-of-calls-in-half-open-state: 3
        sliding-window-size: 10
        register-health-indicator: true

配置中是针对 Resilience4j 库的配置

下面是对 order-service 断路器实例每个配置项的解释:

  • 滑动窗口类型: COUNT_BASED:这指定了用于跟踪失败的滑动窗口是基于失败的调用次数。Resilience4j 支持两种类型的滑动窗口:COUNT_BASED(基于次数)和 TIME_BASED(基于时间)。
  • 故障率阈值: 50:这设置了断路器打开的故障率阈值。在这种情况下,如果故障率达到 50%,则断路器将打开,并阻止对服务的进一步请求。
  • 最小调用次数: 5:这设置了在计算故障率之前必须执行的调用次数。如果小于 5 次调用,则断路器不会因故障率而打开。
  • 自动从打开状态过渡到半开放状态: true:这配置了断路器在指定的等待周期后自动从打开状态过渡到半开放状态。在半开放状态下,允许有限数量的请求通过到服务。
  • 打开状态下的等待时间: 5s:这是断路器在打开状态下持续的秒数,在此之后它会过渡到半开放状态。
  • 半开放状态下的允许调用次数: 3:这设置了在半开放状态下允许的调用次数。如果在期间有超过 3 次调用失败,则断路器将回到打开状态。
  • 滑动窗口大小: 10:这配置了用于跟踪请求和失败的滑动窗口的大小。滑动窗口的大小必须大于计算故障率所需的最小调用次数。
  • 注册健康指标: true:这个标志指示是否为断路器注册健康指标。健康指标用于提供关于组件健康状况的信息,包括断路器的状态。

综上所述,这些配置定义了 order-service 断路器的行为。断路器将监控故障率和调用次数,以确定何时打开和何时过渡到半开放状态,为系统提供一种自我保护机制,以防止级联失败。


测试

依次运行address-service和order-service,访问链接http://localhost:1010/orders?orderNumber=0c70c0c2

在这里插入图片描述


如果地址服务未正确响应(服务已关闭),我们将收到以下响应

在这里插入图片描述

这样完成了订单服务的构建 。


探究断路器

两个服务确保都已运行,访问链接 http://localhost:1010/actuator/health 查看断路器详细信息
在这里插入图片描述

我们可以看到以下几个关键配置:

  • bufferedCalls(缓冲调用次数)为0,这意味着从order-service到address-service没有发起任何API调用。
  • failedCalls(失败调用次数)也为0,这表示所有调用都成功了,没有失败的调用。
  • failureRate(失败率)为-1.0%,这是一个异常的值,因为失败率不可能是负数。通常,失败率应该是成功率的一部分,即0%表示100%的成功率。这里的情况可能是因为计算失败率时使用了0作为分母,导致了负数的产生。
  • state(状态)为"CLOSED"(关闭),这表明circuitBreaker(断路器)目前是关闭的,没有触发熔断机制。

调用order-service API 2次

调用order-service API 2次http://localhost:1010/orders?orderNumber=0c70c0c2

然后刷新actuator链接
在这里插入图片描述

  • “bufferedCalls”: 2, // Total number of API calls now is 2

关闭address-service,调用order-service API 3

关闭address-service,调用order-service API 3次http://localhost:1010/orders?orderNumber=0c70c0c2,然后刷新执行器链接

在这里插入图片描述

我们注意到Circuit Breaker被触发。原因是“failureRate”现在大于“failure-rate-threshold”

  • “status”: “CIRCUIT_OPEN”, // CircuitBreaker is triggered
  • “failureRate”: “60.0%”, // this rate now is greater than “failureRateThreshold”
  • “bufferedCalls”: 5, // Total number of API calls from order-service to address-service
  • “failedCalls”: 3, // Number of failed API calls from order-service to address-service

等待5秒,刷新执行器

在这里插入图片描述

HALF_OPEN状态下,允许““permitted-number-of-calls-in-half-open-state”请求(我们将其值配置为3),然后再次计算失败率,如果失败率仍然大于“failure-rate-threshold”,断路器将再次被触发。


继续调用 order-service API 3 次

继续调用 order-service API 3 次 http://localhost:1010/orders?orderNumber=0c70c0c2,然后刷新执行器链接

在这里插入图片描述

  • “status”: “CIRCUIT_OPEN”, // // CircuitBreaker is triggered again

运行address-service,然后继续调用order-service API 3次

运行address-service,然后继续调用order-service API 3次http://localhost:1010/orders?orderNumber=0c70c0c2,刷新执行器链接
在这里插入图片描述

断路器已关闭 。


小结

Resilience4j的circuit breaker模式特别有用,它能够在服务调用失败达到一定次数后,自动断开电路,避免进一步的调用,从而保护应用程序不受故障服务的拖累。当服务恢复后,电路会重新闭合,允许正常的调用再次发生。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[已解决]前端使用el-upload,后端使用文件上传阿里云报错:异常信息:java.lang.NullPointerException: null

前端使用el-upload&#xff0c;后端使用文件上传阿里云报错&#xff1a; 报错原因&#xff1a;前端image参数未传进去 解决方法&#xff1a;在el-upload添加属性 name"image" 文件传进去了&#xff01;

Spring Boot Aop 执行顺序

Spring Boot Aop 执行顺序 1. 概述 在 spring boot 项目中&#xff0c;使用 aop 增强&#xff0c;不仅可以很优雅地扩展功能&#xff0c;还可以让一写多用&#xff0c;避免写重复代码&#xff0c;例如&#xff1a;记录接口耗时&#xff0c;记录接口日志&#xff0c;接口权限&…

Java 抽象类

例如这样&#xff1a; 除非子类也是抽象类&#xff1b; Java的类是单继承&#xff0c;但是接口是多继承&#xff1b; 抽象类的特点&#xff1a; 例如&#xff1a; //2、抽象类里面可以有抽象方法&#xff0c;或者普通方法&#xff0c;但是有抽象方法的类必须是抽象类 抽象类可…

python 抽象接口和协议总结

通过实现特殊方法&#xff0c;自定义数据类型可以表现得跟内置类型一样&#xff0c;从而让我们写出更具表达力的代码——或者说&#xff0c;更具 Python 风格的代码。 功能协议接口__add__*__mul__str()先查找是否实现 __str__ 协议&#xff0c;没有查找是否实现 __repr__ boo…

机器人导纳控制实现框架

Safe, Stable and Intuitive Control for Physical Human-Robot Interaction - 知乎关于文章《Safe, Stable and Intuitive Control for Physical Human-Robot Interactio》的简记。 Safe, Stable and Intuitive Control for Physical Human-Robot Interaction目的根据力导数作…

计算机找不到msvcp120.dll的修复方法,总结五种可靠的方法

在计算机使用过程中&#xff0c;遭遇“找不到msvcp120.dll”这一问题的困扰是许多用户都可能遇到的情况。这一特定的系统文件msvcp120.dll&#xff0c;作为Microsoft Visual C Redistributable Package的重要组成部分&#xff0c;对于运行某些应用程序至关重要。当系统提示无法…

【办公类-21-03】20240119 提取不连续的男女学号 set()和list法

背景需求&#xff1a;了解班级幼儿性别比例 查看点名册&#xff0c;发现中4班最初的学号是按照先男后女的方式排列&#xff0c;但是随着幼儿转出&#xff0c;空出一些学号&#xff0c;于是新插班的孩子就插入空的学号&#xff0c;空格插完了&#xff0c;就排在学号尾部。 我想…

postman导入https证书

进入setting配置中Certificates配置项 点击“Add Certificate”,然后配置相关信息 以上配置完毕&#xff0c;如果测试出现“SSL Error:Self signed certificate” 则将“SSL certificate verification”取消勾选

Jmeter后置处理器——JSON提取器

目录 1、简介 2、使用步骤 1&#xff09;添加线程组 2&#xff09;添加http请求 3&#xff09; 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式&#xff0c;允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…

【AI】ChatGPT和文心一言那个更好用

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《自然语言处理的发展》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景自我介绍面试题…

【算法理论】期末复习-选填

算法的五个特征 1.有效性 算法必须在有限的时间能够完成&#xff0c;甚至用纸和笔完成 2.确定性 算法的每一步能够清楚的定义. 3.有限性 算法能够在有限的步骤完成 4.Input 算法有0个或者多个输入 5.Output 算法有一个或者多个输出 满足有效性&#xff0c;确定性&am…

adb 配对+无线连接

配对 打开手机开发者选项-无线调试-使用配对码配对设备 出现ip端口和配对码后&#xff0c;电脑输入命令&#xff1a; adb pair ip:端口 eg:adb pair 192.168.137.244:39683 提示输入配对码&#xff1a;就按照手机上的输入。 此时配对成功 连接 再使用命令adb connect ip:port…

IDEA项目启动报错之Command too long

使用IDEA最新的版本2023-3月份社区版本&#xff0c;启动之前没问题的项目突然报错如下&#xff1a; Error running VipServiceApplication: Error running // VipServiceApplication.Command line is too long. Shorten the command line via // JAR manifest or via a // clas…

IPFoxy运营干货|谷歌广告Google Ads如何选择最佳关键词?

投放谷歌广告需要多少个步骤和什么准备工作&#xff0c;本文将来讲述&#xff0c;主要分5个内容&#xff1a;一、投放前竞对研究&#xff1b;二、投放前广告账户设置&#xff1b;三、建立广告系列&#xff1b;四、建立广告组&#xff1b;五、广告长期策略。 一、投放前竟对研究…

RabbitMQ的基本使用,进行实例案例的消息队列

目录 一、介绍 1. 概述 2. 作用 3. 工作原理 二、RabbitMQ安装部署 1. 安装 2. 部署 3. 增加用户 三、实现案例 1. 项目创建 2. 项目配置 3. 生产者代码 4. 消费者代码 四、测试 每篇一获 一、介绍 1. 概述 RabbitMQ 是一种开源的消息代理和队列服务器&#x…

【RocketMQ每日一问】RocketMQ nameserver的作用是什么?

Name Server 在 Apache RocketMQ 集群中扮演着以下几个重要作用&#xff1a; 服务注册与发现&#xff1a; Name Server 负责管理和协调整个集群&#xff0c;维护集群中所有 Broker 的信息&#xff0c;包括 Broker 的 IP 地址、端口号、存储容量等。当 Producer 和 Consumer 需…

内存分析CE寻找天龙八部人物状态及基址

扫描类型为未知的数值首次扫描 通过改变角色状态 扫描类型变动的数值和未变动的数值扫描地址 选择3FCBD25C为人物状态地址 0站立 2走路 6打坐 7打怪 找基址 鼠标右键找出是什么访问了这个地址 查看第一个的详细信息 与02 和 00 进行判断&#xff08;走路和站立&#…

Architecture Lab:part A 【实现sum_list/rsum_list/copy_block/熟悉Y86-64指令】

Architecture Lab 对应CS:APP的Chap 4——处理器体系结构。Part A要实现三个函数&#xff0c;分别为sum_list/rsum_list/copy_block。建议先得到x86-64指令&#xff0c;然后再转换为Y86-64指令。 准备工作 在misc目录下&#xff0c;键入以下命令用来生成汇编代码。命令执行完…

Linux快速部署文件服务器

参考文档&#xff1a; Linux命令之nohup详解 - 掘金 【Linux】ps -ef|grep详解-CSDN博客 有个简单想法&#xff0c;我的一些文件放在机器某个目录下面&#xff0c;可以简单提供团队内部人员浏览和下载功能&#xff0c;节约时间&#xff0c;用最简单方法实现。 注&#xff1a;…

MyBatisPlus学习笔记五-插件功能

0、插件功能 MyBatisPlus提供的内置拦截器有下面这些 1、分页插件 2、通用分页实体 3、通用分页实体-强化 需求&#xff1a; 在PageQuery中定义方法&#xff0c;将PageQuery对象转为MyBatisPlus中的Page对象在PageDTO中定义方法&#xff0c;将MyBatisPlus中的Page结果转为Page…
最新文章