Spring Cloud Netfix Hystrix(断路器)

news2024/11/29 4:38:59

一、灾难性雪崩

造成灾难性雪崩效应的原因,可以简单归结为下述三种:

  1. 服务提供者(Application Service)不可用。如:硬件故障、程序BUG、缓存击穿、并发请求量过大等。

  2. 重试加大流量。如:用户重试、代码重试逻辑等。

  3. 服务调用者(Application Client)不可用。如:同步请求阻塞造成的资源耗尽等。

雪崩效应最终的结果就是:服务链条中的某一个服务不可用,导致一系列的服务不可用,最终造成服务逻辑崩溃。这种问题造成的后果,往往是无法预料的。

二、Hystrix简介 

在Spring Cloud中解决灾难性雪崩效应就是通过Spring Cloud Netflix Hystrix实现的。

Hystrix [hɪst'rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。本文所说的Hystrix(中文:断路器)是Netflix开源的一款容错框架,同样具有自我保护能力。

通俗解释:Hystrix就是保证在高并发下即使出现问题也可以保证程序继续运行的一系列方案。作用包含两点:容错和限流。

在Spring cloud中处理服务雪崩效应,都是在服务调用方(Application Client)实现,需要依赖hystrix组件。

三、降级

降级是指,当请求超时、资源不足等情况发生时进行服务降级处理,不调用真实服务逻辑,而是使用快速失败(fallback)方式直接返回一个托底数据,保证服务链条的完整,避免服务雪崩。

(1)导入依赖

    <!-- 容灾处理依赖。 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

(2)编写启动类

/**
 * EnableHystrix - 开启Hystrix功能。netflix hystrix包提供
 */
@SpringBootApplication
@EnableHystrix
public class HystrixRestTemplateApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixRestTemplateApp.class, args);
    }
}

(3)使用

@Service
public class HystrixRestTemplateServiceImpl implements HystrixRestTemplateService {
    @Autowired
    private RestTemplate restTemplate;
    private final String baseUrl = "http://app-service";

    /**
     * 增加注解 HystrixCommand
     *  注解属性 fallbackMethod - 降级方法的名称
     * @return
     */
    @Override
    @HystrixCommand(fallbackMethod = "downgrade")
    public String test() {
        String url = baseUrl + "/test";
        System.out.println("准备访问远程服务 : /test");
        String result = restTemplate.getForObject(url, String.class);
        System.out.println("远程服务返回:" + result);
        return result;
    }

    /**
     * 降级方法。除方法名称外,其他和具体的服务方法签名一致
     * 降级方法的返回结果,就是托底数据
     */
    public String downgrade(){
        System.out.println("降级方法运行。");
        return "服务器忙,请稍后重试";
    }
}

四、熔断

当一定时间内,异常请求比例(请求超时、网络故障、服务异常等)达到阀值时,启动熔断器,熔断器一旦启动,则会停止调用具体服务逻辑,通过fallback快速返回托底数据,保证服务链的完整。

熔断有自动恢复机制,如:当熔断器启动后,每隔5秒,尝试将新的请求发送给Application Service,如果服务可正常执行并返回结果,则关闭熔断器,服务恢复。如果仍旧调用失败,则继续返回托底数据,熔断器持续开启状态。

降级是出错了返回托底数据,而熔断是出错后如果开启了熔断将会一定时间不在访问application service。

(1)导入依赖

    <!-- 容灾处理依赖。 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

(2)编写启动类

/**
 * EnableHystrix - 开启Hystrix功能。netflix hystrix包提供
 * EnableCircuitBreaker - 开启熔断器|断路由|断路器。spring circuitbreaker提供
 *
 * 这两个注解都是让Spring可以识别Hystrix的注解。
 */
@SpringBootApplication
@EnableHystrix
@EnableCircuitBreaker
public class HystrixRestTemplateApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixRestTemplateApp.class, args);
    }
}

(3)使用

注解属性含义解释

  1. CIRCUIT_BREAKER_ENABLED "circuitBreaker.enabled"; 是否开启熔断策略。默认值为true。

  2. CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD "circuitBreaker.requestVolumeThreshold"; 单位时间内(默认10s内),请求超时数超出则触发熔断策略。默认值为20次请求数。通俗说明:单位时间内容要判断多少次请求。

  3. EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS execution.isolation.thread.timeoutInMilliseconds 设置单位时间,判断circuitBreaker.requestVolumeThreshold的时间单位,默认10秒。单位毫秒。

  4. CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS "circuitBreaker.sleepWindowInMilliseconds"; 当熔断策略开启后,延迟多久尝试再次请求远程服务。默认为5秒。单位毫秒。这5秒直接执行fallback方法,不在请求远程application service。

  5. CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE "circuitBreaker.errorThresholdPercentage"; 单位时间内,出现错误的请求百分比达到限制,则触发熔断策略。默认为50%。

  6. CIRCUIT_BREAKER_FORCE_OPEN "circuitBreaker.forceOpen"; 是否强制开启熔断策略。即所有请求都返回fallback托底数据。默认为false。

  7. CIRCUIT_BREAKER_FORCE_CLOSED "circuitBreaker.forceClosed"; 是否强制关闭熔断策略。即所有请求一定调用远程服务。默认为false。

/**
 * 测试熔断,强化降级。
 * 注解属性 commandProperties - 具体的容灾配置参数。
 *  类型是HystrixProperty[], HystrixProperty类型是名值对。
 *  名 - 是具体的配置参数名,字符串类型,可以从HystrixPropertiesManager中查看,也可以
 *       使用其中的静态常量。
 *  值 - 参数值,字符串类型。
 */
@Override
@HystrixCommand(fallbackMethod = "circuitBreakerDowngrade", commandProperties = {
    @HystrixProperty(name = HystrixPropertiesManager
                     .EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,
                     value = "5000"), // 统计周期,默认10秒
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_ENABLED,
                     value = "true"), // 是否开启熔断,默认true
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,
                     value = "2"), // 统计周期内,错误几次,开启熔断, 默认20
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,
                     value = "50"), // 统计周期内,错误百分比达到多少,开启熔断, 默认50
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,
                     value = "3000"), // 开启熔断后,多少毫秒不访问远程服务,默认5000毫秒
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_FORCE_OPEN,
                     value = "false"), // 是否强制开启熔断器, 默认false
    @HystrixProperty(name = HystrixPropertiesManager
                     .CIRCUIT_BREAKER_FORCE_CLOSED,
                     value = "false") // 是否强制关闭熔断器, 默认false
})
public String circuitBreaker() {
    String url = baseUrl + "/test";
    System.out.println("准备访问远程服务,地址是:" + url);
    String result = restTemplate.getForObject(url, String.class);
    System.out.println("远程返回结果是:" + result);
    return result;
}

/**
 * 熔断降级方法
 */
public String circuitBreakerDowngrade(){
    System.out.println("熔断降级触发");
    return "网站建设中";
}

 五、请求缓存

Hystrix为了降低访问服务的频率,支持将一个请求与返回结果做缓存处理。如果再次请求的URL没有变化,那么Hystrix不会请求服务,而是直接从缓存中将结果返回。这样可以大大降低访问服务的压力。 可以利用spring cache。实现请求缓存。

(1)导入依赖

    <!-- 容灾处理依赖。 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

    <!-- 边路缓存依赖 -->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2)配置缓存地址

spring:
  redis:
    host: ip地址

(3)在启动器上添加@EnableCaching注解,开启请求缓存的功能

@SpringBootApplication
@EnableHystrix
@EnableCircuitBreaker
//启动Spring Caching
@EnableCaching
public class HystrixRestTemplateApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixRestTemplateApp.class, args);
    }
}

(4)使用

/**
 * 测试请求缓存。
 * 使用Spring Cache技术实现,访问Redis,做缓存处理。
 * Spring Cache是spring-context.jar提供的技术。可以访问多种缓存服务器。
 * 包括redis。
 * 想使用Spring Cache技术,访问缓存服务,需要提供以下依赖:
 *  1. spring-context.jar,直接或间接。
 *  2. 要访问的缓存服务器客户端依赖。如:访问Redis需要Spring Data Redis依赖
 * 使用Spring Cache技术后,查询逻辑的流程是:
 *  1. 访问缓存,查看是否有缓存的结果。如果有直接返回,不执行当前方法。
 *  2. 如果缓存中没有结果,则执行方法。
 *  3. 方法返回结果,会被Spring Cache技术自动保存到缓存服务器中。
 *  4. 方法结束,返回给调用者。
 *  注解: Cacheable
 *  属性:
 *    cacheNames - 缓存中key的前缀
 *    key - 缓存中key的后缀。可以使用表达式赋值。字面值用单引号标记。方法参数变量
 *          使用#参数名标记,可以使用字符串拼接符号 +
 *    完整的缓存key是 前缀 + :: + 后缀
 */
@Override
@HystrixCommand(fallbackMethod = "downgrade")
@Cacheable(key = "'client'",cacheNames = "com:bjsxt")
public String test() {
    String url = baseUrl + "/test";
    System.out.println("准备访问远程服务 : /test");
    String result = restTemplate.getForObject(url, String.class);
    System.out.println("远程服务返回:" + result);
    return result;
}

/**
     * 降级方法。除方法名称外,其他和具体的服务方法签名一致
     * 降级方法的返回结果,就是托底数据
     */
public String downgrade(){
    System.out.println("降级方法运行。");
    return "服务器忙,请稍后重试";
}

六、请求合并

增加请求合并处理后:一段时间范围内的所有请求合并为一个请求。大大的降低了Application Service 负载。

(1)依赖同其他一样

(2)使用

注解属性含义

@HystrixCollapser 进行请求合并

batchMethod:处理请求合并的方法

scope:合并请求的请求作用域。可选值有global和request。

global:代表所有的请求线程都可以等待可合并。

常用 ​ request:代表一个请求线程中的多次远程服务调用可合

timerDelayInMilliseconds:等待时长,默认10毫秒。

maxRequestInBatch:最大请求合并数量。

    /**
     * 是一个批处理逻辑。是做请求合并处理的方法。
     * 注意,Hystrix中,请求合并处理,具体方法,不是单处理方法。
     * 当前方法,不会执行。由Hystrix通过代理封装后执行。
     * 增加一个额外的批处理方法逻辑。
     *
     * 注解 HystrixCollapser - 代表当前的方法,是一个要合并的方法。
     * 属性:
     *  batchMethod - 批处理方法名称。
     *  scope - 有效范围。
     *   可选值:
     *     com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL
     *     全局有效。可以合并多个客户端的请求。
     *     com.netflix.hystrix.HystrixCollapser.Scope.REQUEST 默认值
     *     请求内有效,只能合并一个请求中的多次远程调用。必须配合指定的框架才能生效。
     *     在当前方法中,会抛出异常。
     *  collapserProperties - 合并约束,类似HystrixCommand注解中的commandProperties
     *   类型是HystrixProperty[]
     * @param id
     * @return
     */
    @Override
    @HystrixCollapser(batchMethod = "getUsersByIds",
            scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
            collapserProperties = {
                    @HystrixProperty(name =
                            HystrixPropertiesManager.MAX_REQUESTS_IN_BATCH,
                            value = "2"), // 最多合并多少个请求
                    @HystrixProperty(name =
                            HystrixPropertiesManager.TIMER_DELAY_IN_MILLISECONDS,
                            value = "500") // 最多等待多少毫秒
            }
    )
    public Future<User> getUserById(Integer id) {
        System.out.println("根据主键查询用户方法,Service实现类型中的Override实现");
        return null;
    }

    /**
     * 批处理方法。编写访问远程批处理服务的逻辑。
     * 使用注解HystrixCommand修饰。
     *
     * 问题:
     *  使用RestTemplate访问远程服务的时候,如果服务返回结果是集合。
     *  集合的泛型是自定义类型。因为SpringMVC的@ResponseBody是把Java对象转换成JSON返回,
     *  RestTemplate不知道返回的JSON对应的具体Java类型是什么,
     *  所以使用最通用的类型,Map转换。
     *  远程服务返回的是List<User>,SpringMVC注解ResponseBody处理后,返回的是字符串
     *  [{"id":1,"name":"姓名1","age":20}, {...}]
     *  RestTemplate转换上述JSON格式字符串,[]使用List集合处理。
     *  {"id":1,"name":"姓名1","age":20}是什么类型?使用通用类型Map处理。
     *  JSON对象是属性名id、name、age是map的key。属性值1、姓名1、20是map的value。
     *
     *  手工使用Jackson实现转换处理。
     *
     * 定义要求:
     *  1. 访问修饰符是public
     *  2. 返回值的类型是远程服务的返回类型。
     *  3. 方法命名,随意。不重复即可。
     *  4. 参数表,是List集合类型,泛型是要合并的方法参数类型。名称和要合并的方法参数名一致
     *  5. 抛出异常,不能抛出范围超过要合并的方法的异常类型。
     * @param id
     * @return
     */
    @HystrixCommand
    public List<User> getUsersByIds(List<Integer> id){
        ObjectMapper mapper = new ObjectMapper();

        String url = baseUrl + "/batch";
        System.out.println("准备访问远程服务,地址是:" + url + " , 参数是:" + id);
        List<LinkedHashMap> result =
                restTemplate.postForObject(url, id, List.class);
        List<User> users = new ArrayList<>(result.size());
        for(LinkedHashMap userMap : result){
            try {
                // 把Map转换成JSON格式字符串
                String userJson = mapper.writeValueAsString(userMap);
                // 把JSON格式字符串转换成User类型对象
                User user = mapper.readValue(userJson, User.class);
                // 把处理后的User类型对象,保存到返回结果集合中
                users.add(user);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("查询结果数量是:" + result.size());
        System.out.println("查询的用户集合是:" + result);
        return users;
    }

(4)控制器单元方法

/**
 * 根据主键查询用户。
 * 具体实现逻辑,调用远程服务eureka-client-app-service批处理查询实现。
 * 合并当前的请求。把多次请求参数主键,合并成一个集合参数List<Integer>。
 * 一次性访问远程服务,返回的批处理查询结果,拆分后,返回给客户端。
 * @param id
 * @return
 */
@RequestMapping("/getUserById")
public User getUserById(Integer id){
	Future<User> future = service.getUserById(id);
	System.out.println("控制器执行 - getUserById()");
	try {
		return future.get();
	} catch (InterruptedException e) {
		e.printStackTrace();
	} catch (ExecutionException e) {
		e.printStackTrace();
	}
	// 发生了异常。返回null。
	return null;
}

七、线程池隔离

当使用线程池隔离。不同接口有着自己独立的线程池,即使某个线程池都被占用,也不影响其他线程。

java.util.concurrent.Semaphore用来控制可同时并发的线程数。通过构造方法指定内部虚拟许可的数量。每次线程执行操作时先通过acquire方法获得许可,执行完毕再通过release方法释放许可。如果无可用许可,那么acquire方法将一直阻塞,直到其它线程释放许可。

(1)依赖同上

(2)使用

注解属性说明

/**
 * 测试线程池隔离。 也可以提供降级、熔断等处理逻辑。
 * 访问远程服务/getNoParams测试。
 * 当前方法,使用独立的线程池。和其他方法隔离。
 * 提供注解HystrixCommand
 *  groupKey - 分组唯一值。默认使用当前类型的类名。代表一个独立接口的唯一命名。
 *   一般都使用类型的名称定义。是使用 字母 ,数字 ,_ 组成的字符串。
 *  commandKey - 命令唯一值。默认使用当前方法名称。代表一个独立接口中的命令唯一命名。
 *   一般使用方法名称定义。是使用 字母 ,数字 ,_ 组成的字符串
 *  threadPoolKey - 隔离的线程池命名中缀。默认使用groupKey的值。
 *   定义后,线程池命名是 "hystrix-" + threadPoolKey。
 *   池中的线程命名是 "hystrix-" + threadPoolKey + 数字编号(从1开始,自然数递增)
 *  threadPoolProperties - 定义隔离线程池的配置信息。如:线程池容量,线程存活时间等。
 *   类型是HystrixProperty[]
 * @return
 */
@Override
@HystrixCommand(groupKey = "MyFirstThread",
		commandKey = "thread",
		threadPoolKey = "pool-name",
		threadPoolProperties = {
		@HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE,
				value = "3"), // 线程池容量
		@HystrixProperty(name = HystrixPropertiesManager.KEEP_ALIVE_TIME_MINUTES,
				value = "5"), // 线程空闲时,最大存活时间是多少分钟
		@HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE,
				value = "5"), // 线程池占满时,最多由多少个请求阻塞等待
		@HystrixProperty(name = HystrixPropertiesManager
				.QUEUE_SIZE_REJECTION_THRESHOLD,
				value = "5") // 当阻塞队列MAX_QUEUE_SIZE占满时,可以由多少个
							 // 请求同时阻塞等待后续处理。
		}
)
public String thread() {
	String url = baseUrl + "/test";
	System.out.println("当前方法使用的线程名称是:" +
			Thread.currentThread().getName());
	String result =
			restTemplate.getForObject(url, String.class);
	System.out.println("远程返回:" + result);
	return result;
}

 八、信号量隔离

采用信号量隔离技术,每接收一个请求,都是服务自身线程去直接调用依赖服务,信号量就相当于一道关卡,每个线程通过关卡后,信号量数量减1,当为0时不再允许线程通过,而是直接执行fallback逻辑并返回,说白了仅仅做了一个限流。

(1)依赖同上

(2)使用

注解属性说明

/**
 * 测试信号量隔离
 * 就是定义一个阈值,设定同时处理的请求上限。当处理的请求达到阈值时,
 * 后续请求,降级处理。
 *
 * 使用注解 HystrixCommand 修饰
 *  commandProperties - 描述隔离方案和信号量隔离阈值
 *
 * @return
 */
@Override
@HystrixCommand(fallbackMethod = "downgrade",
		commandProperties = {
		@HystrixProperty(name = HystrixPropertiesManager
				.EXECUTION_ISOLATION_STRATEGY,
				value = "SEMAPHORE"), // 隔离方案。默认线程池隔离。 THREAD | SEMAPHORE
		@HystrixProperty(name = HystrixPropertiesManager
				.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,
				value = "2"), // 最大信号量
		@HystrixProperty(name = HystrixPropertiesManager
				.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,
				value = "1000") // 超时时间。信号量隔离中无效,线程池隔离中有效。默认1秒
		}
)
public String semaphore() {
	String url = baseUrl + "/test";
	System.out.println("远程地址是:" + url + " , 线程名称是:" +
			Thread.currentThread().getName());
	String result = restTemplate.getForObject(url, String.class);

	try {
		Thread.sleep(800);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}

	System.out.println("远程返回:" + result);
	return result;
}

九、线程池隔离和信号量隔离分析

(1)区别

线程池隔离信号量隔离
线程请求线程和调用远程服务的线程不是同一个线程请求线程和调用远程服务的线程是同一个线程
开销较大(包括排队、调度、上下文等开销)很低(无线程切换)
异步支持不支持
并发支持支持(线程池容量上限)支持(信号量阈值上限)
传递Header无法传递Http Header可以传递Http Header
支持超时支持超时不支持超时

(2)选择

 什么时候选择线程池隔离

​    <font color='red'>请求并发量大,并且耗时较长</font>(如计算量级大、访问其他服务、访问数据库等),使用线程池隔离可以保证容器线程池(Tomcat线程池)利用率更好,不会因为远程服务调用的原因,导致线程处于等待、阻塞等状态,可以实现快速失败返回。

什么时候选择信号量隔离

​    <font color='red'>请求并发量大,并且耗时较短</font>(如计算量级小、访问缓存等),使用信号量隔离可以保证快速返回,不会因为线程切换而导致不必要的损耗。且因为这种服务返回快速,并不会长时间占用容器线程(Tomcat线程),提高了服务的整体性能。

十、 Openfeign的容灾处理

当使用OpenFeign调用远程服务超时会出现500错误。可使用Hystrix来实现容灾处理。

在OpenFeign启动器依赖中,默认包含Hystrix核心类库,但不包含Hystrix启动器中的全部资源,所以可实现Hystrix容灾处理方案,但不能实现Hystrix其他扩展处理(如@EnableHystrix注解就不包含在默认资源中)。

(1)导入依赖

openfeign自带hystrix依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2)编写配置文件

在application.yml配置中增加下述配置:默认情况下OpenFeign的hystrix是不开启的,需要手动开启。

feign:
  hystrix:
    enabled: true

(3)编写启动类

@SpringBootApplication
@EnableHystrix
@EnableFeignClients
@EnableCircuitBreaker
public class HystrixRestTemplateApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixRestTemplateApp.class, args);
    }
}

(4)编写Feign接口

@FeignClient(name = "app-service", fallback = FeignHystricServiceFallback.class)
public interface FeignHystricService {
    @PostMapping("/test")
    String test();
}

(5)编写Feign接口的实现类,做为降级方法

@Component
public class FeignHystricServiceFallback implements FeignHystricService {
    @Override
    public String test() {
        System.out.println("执行方法,出现服务降级,返回托底数据");
        String result = "因为Provider连接不上了,返回托底数据";
        return result;
    }
}

(6)OpenFeign中的熔断配置

hystrix: # hystrix 容灾配置
  command: # hystrix 命令配置,就是具体的容灾方案
    default: # 默认环境,相当于全局范围,后续的配置,参考HystrixPropertiesManager中的常量配置
      circuitBreaker: # 熔断配置, 常用。 其他配置不常用。
        enabled: true
        requestVolumeThreshold: 2
        sleepWindowInMilliseconds: 2000
        errorThresholdPercentage: 50

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

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

相关文章

手记:把代码上传到Gitee等远程仓库的过程记录及常见问题

很久没用git了&#xff0c;指令都有点生疏了&#xff0c;今天上传了一些代码到码云上&#xff0c;先把过程记录下来供使用git的朋友参考。没有用图形化界面&#xff0c;因为只有熟悉指令才能真正的理解领会。 步骤一&#xff1a; 1、安装git&#xff1b;安装后可以使用指令git…

打造一个投资组合管理的金融强化学习环境

原创文章第120篇&#xff0c;专注“个人成长与财富自由、世界运作的逻辑&#xff0c; AI量化投资”。 今天继续金融强化学习环境。 网上的金融学习环境不少&#xff0c;但都太过于“业余”&#xff0c;或者离像样的投资还差得太远。我一直觉得投资组合应该是必要的&#xff0…

怎么恢复已删除的全部数据,不小心删除的数据怎么恢复,删除的文件还能找回吗

怎么恢复已删除的全部数据&#xff1f;一般来讲&#xff0c;当文件被删除后&#xff0c;都会暂时被放置在回收站的位置&#xff0c;如果我们想找回相应的丢失数据&#xff0c;具体该如何操作呢&#xff1f; 一、当回收站没有被清空 这是最简单的一种恢复误删数据的方法&#…

前端入门--JavaScript篇

JavaScript基础 文章目录JavaScript基础JavaScript是什么JavaScript的使用方式JavaScript的运行过程JS的语法三种语言的注释输入输出JS中的变量JS中基本的数据类型number类型string字符串undefined类型null类型运算符数组数组的创建数组的使用数组新增元素函数对象之前学过了HT…

缓存的设计

文章目录1. 缓存的更新机制1.1 被动更新1.2 主动更新1.2.1 Cache Aside Pattern &#xff08;更新数据库&#xff0c;再删除缓存&#xff09;1.2.2 更新数据库&#xff0c;更新缓存1.2.3 先删除缓存&#xff0c;在更新数据库1.3 Read/Write Through Pattern1.4 Write Behind Ca…

【Linux】权限管理

文章目录一、shell 命令以及运行原理二、Linux的用户权限1、权限概念引入2、用户分类3、用户切换4、用户提权三、Linux 权限管理1、文件访问者的角色划分2、文件类型和访问权限a、文件类型(后缀理解 file 指令讲解)b、文件访问权限四、文件访问权限的更改1、chmod 指令(对拥有…

STM32CubeMX串口通讯

串口的简单介绍 RS-232与TTL 根据通讯使用的电平标准不同&#xff0c;串口通讯可分为 TTL 标准及 RS-232 标准。而STM32的串口是TTL电平标准的。如果需要使用到RS-232则需要一个电平转换芯片。 单工通信、半双工通信和全双工通信 讲到串口&#xff0c;我们还需要具备这些基…

嵌入式分享合集113

一、 模拟输入信号的保护电路问题 四种模拟输入信号的保护电路的实现方法。 近由于工作的需要&#xff0c;涉及到了模拟输入信号的保护电路问题。结合以往的工作实践以及网络文献资料的查找。现在就保护电路作一简单的说明。 电源钳位保护 上述电路存在可靠性的问题。如果输…

JavaScript_DOM

JavaScript_DOM 概述 简单说就是用来操作HTML的方法&#xff0c;详情看官方文档。 对于我们只需要会使用下面的这个Element对象就可以了。 获取 Element对象 HTML 中的 Element 对象可以通过 Document 对象获取&#xff0c;而 Document 对象是通过 window 对象获取。 Doc…

焱融科技为国家重点实验室打造海量高性能存储

中国科学院大气物理研究所大气科学和地球流体力学数值模拟国家重点实验室&#xff08;英文缩写 LASG&#xff09;是国家级重点实验室。LASG 主要研究方向为地球气候系统模式的研发与应用&#xff1b;天气气候动力学理论、气候系统变化规律及其异常发生机制&#xff1b;天气气候…

排行榜谁最稳?

在 RedMonk 编程语言排行榜中&#xff0c;前端JavaScript 编程语言从2015年开始便稳居榜首&#xff0c;可以说是所有编程语言中最稳定的一个。 01 JavaScript 常年居于榜首原因 JavaScript 编程语言可以常年居于排行榜榜首位置&#xff0c;和它是前端工程师使用的唯一编程语言…

【树莓派】刷机、基础配置及多种方式登录

目录一、树莓派刷机二、树莓派登录1、HDMI线连接显示器登录2、串口方式登录&#xff08;1&#xff09;USB-TTL模块连接树莓派串口&#xff08;2&#xff09;修改系统配置&#xff0c;启用串口&#xff08;3&#xff09;用secureCRT登录树莓派3、网络方式登录&#xff08;1&…

基于51单片机霍尔传感器测速(仿真+源程序)

资料编号&#xff1a;196 下面是该资料仿真演示视频&#xff1a; 196-基于51单片机霍尔传感器测速&#xff08;仿真源程序全套资料&#xff09;功能简介&#xff1a; 51单片机计数测速转速测量&#xff0c;在仿真中等价于测量外部脉冲频率&#xff1b;如果修改输入脉冲的频率&…

前端小白科普:小程序组件与插件有啥区别?怎么用?

一直以为小程序组件和小程序插件是一回事&#xff0c;只是措辞不一样&#xff0c;导致造成乌龙&#xff0c;其实完全是两回事&#xff0c;插件是可以直接提供服务的&#xff0c;组件是给开发者提供的轮子&#xff0c;不能直接提供服务。 先看看微信是如何定义小程序插件的&…

[附源码]计算机毕业设计springboot健身房信息管理

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Flutter 离线数据方案 Flutter_Data 包

Flutter 离线数据方案 Flutter_Data 包 原文 https://levelup.gitconnected.com/flutter-offline-first-with-flutter-data-62bad61097be 前言 通过离线优先来改善您的用户体验 Flutter Data 是一个让你的应用程序先离线的软件包。 离线时&#xff0c;它在设备上使用 Hive 存储…

DirectX12 - Triangle Culling and Winding Order(三角形的剔除与绕序)

这里是SunshineBooming&#xff0c;GPU公司一枚小小的Driver工程师&#xff0c;主要工作是写DirectX12 Driver&#xff0c;我会持续更新这个DX12 Spec系列&#xff0c;可能比较冷门&#xff0c;但是都是干货和工作中的心得体会&#xff0c;有任何GPU相关的问题都可以在评论区互…

Chapter9.2:线性系统的状态空间分析与综合(下)

此系列属于胡寿松《自动控制原理题海与考研指导》(第三版)习题精选&#xff0c;仅包含部分经典习题&#xff0c;需要完整版习题答案请自行查找&#xff0c;本系列属于知识点巩固部分&#xff0c;搭配如下几个系列进行学习&#xff0c;可用于期末考试和考研复习。 自动控制原理(…

GJB 5000B二级-LD领导作用

概要:GJB 5000B将GJB 5000A三级中的LD领导作用划分为二级内容,将组织类目标下沉至二级 借鉴GJB 9001C中的领导作用,结合各个行业优秀的实践,将5000A中的共用目标、实践进行了提炼、总结最终形成GJB 5000B中的领导作用实践域。 目的:进一步强化上层的领导作用,由高层、中层…

DOPE修饰岩藻多糖 Fucoidan-DOPE 岩藻多糖-二油酰基磷脂酰乙醇胺

DOPE修饰岩藻多糖 Fucoidan-DOPE 岩藻多糖-二油酰基磷脂酰乙醇胺 中文名称&#xff1a;岩藻多糖-二油酰基磷脂酰乙醇胺 英文名称&#xff1a;Fucoidan-DOPE 别称&#xff1a;DOPE修饰岩藻多糖&#xff0c;DOPE-岩藻多糖 外观:固体或粘性液体&#xff0c;取决于分子量 PEG分…