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

[Spring] Eureka SpringCloud LoadBalance

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (93平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 服务注册与服务发现---Eureka
    • 1.1 背景
      • 1.1.1 问题描述
      • 1.1.2 解决思路
      • 1.1.3 什么是注册中心
      • 1.1.4 CAP理论
      • 1.1.5 常见的注册中心
    • 1.2 Eureka介绍
    • 1.3 搭建Eureka Server
    • 1.4 服务注册
      • 1.4.1 引入eureka-client依赖
      • 1.4.2 完善配置文件
      • 1.4.3 启动服务
    • 1.5 服务发现
      • 1.5.1 引入依赖
      • 1.5.2 完善配置文件
      • 1.5.3 修改远程调用代码
      • 1.5.4 启动服务
  • 2. 负载均衡---LoadBalance
    • 2.1 负载均衡介绍
      • 2.1.1 问题描述
      • 2.1.2 什么是负载均衡
      • 2.1.3 负载均衡的一些实现
        • 服务端负载均衡
        • 客户端负载均衡
    • 2.2 Spring Cloud LoadBalancer
      • 2.2.1 快速上手
        • 使用Spring Cloud LoadBalancer实现负载均衡
        • 测试负载均衡
      • 2.2.2 常见的负载均衡策略
        • 自定义负载均衡策略
    • 2.3 服务部署
      • 2.3.1 准备数据
      • 2.3.2 服务构建打包
      • 2.3.3 在Linux操作系统上启动服务
      • 2.3.4 开放端口号
      • 2.3.5 测试

1. 服务注册与服务发现—Eureka

1.1 背景

1.1.1 问题描述

我们在上一个章节中可以看到,我们在使用RestTemplate向另一个服务发送请求的时候(在进行远程调用的时候),我们的URL是写死的.

String url = "http://127.0.0.1:9090/product/select?id"+ orderInfo.getProductId();//使用RestTemplate获取相应的对象

当我们的服务在更换主机或者是更换端口号的时候,我们的URL就需要改变,和这个服务相关的代码都需要修改,随之而来的就是各个项目的配置文件反复更新,各个项目的重新部署,非常的繁琐.

1.1.2 解决思路

我们先来使用生活中的场景引入:
我们在生活中,避免不了和各个机构(医院,学校,政府)打交道,我们就需要保存这些机构的电话号码.如果机构更换了电话号码,就需要通知各个使用方,但是这些机构的使用方的群体是巨大的,没有办法做到一一通知,那么如何处理呢?
机构的电话如果发生了变化,通知114即可.用户需要联系机构的时候,用户只需要首先拨打114查号台,然后再去联系各个机构.
114查号台的主要作用有两个:
号码注册: 服务方把电话上报给114
号码查询: 使用方通过114可以查询都爱对应的号码
在这里插入图片描述
和查号台是同样的道理
服务在启动/变更的时候,向注册中心报道,注册中心会记录应用和IP的关系.
调用方在调用的时候,先去注册中心获取服务方的IP地址,再去服务方进行调用.

1.1.3 什么是注册中心

在最初的架构体系中,集群的概念还不那么流行,且机器数量也比较少,此时直接使用DNS+Nginx就可以满足几乎所有服务的发现.相关的注册信息直接配置在Nginx.但是随着微服务的流行与流量的激增,机器规模逐渐变大,并且机器会有频繁的上下线行为,这种时候需要运维手动地去维护这个配置信息是⼀个很麻烦的操作.所以开发者们开始希望有这么一个东西,它能维护一个服务列表,哪个机器上线了,哪个机器宕机了,这些信息都会自动更新到服务列表上,客户端拿到这个列表,直接进行服务调用即可.这个就是注册中心.
注册中心主要有三种角色:

  • 服务提供者(server): 一次业务中,被其他微服务调用的服务,也就是提供接口给其他的微服务.
  • 服务消费者(client): 一次业务中,调用其他微服务的服务.也就是调用其他的微服务提供的接口.
  • 服务注册中心(registry): 用于保存Server的注册信息,当Server结点发生变更的时候,Registry会同步变更.服务与注册中心使用一定的机制进行通信,如果注册中心与某服务长时间无法通信,就会注销该实例.

他们直接的协作关系以及工作内容,我们可以用两个概念来描述:
服务注册: 服务提供者在启动的时候,向Registry注册自身服务,并向Registry定期发送自己的心跳汇报存活状态.
服务发现: 服务消费者从注册中心查询服务提供者的地址.并通过该地址调用服务者提供的接口.服务发现的一个重要的作用就是提供服务消费者的一个可用的服务列表.
在这里插入图片描述

1.1.4 CAP理论

我们在谈到注册中心的时候,我们就避不开CAP理论,CAP理论是分布式系统设计中最基础,也是最关键的理论.
在这里插入图片描述

  • 一致性: 一致性分为弱一致性和强一致性,CAP理论中的一致性指的是强一致性,强一致性指的是主节点和从节点(主库和从库),不论何时,对外提供的服务都是一致的.弱一致性指的是,在一开始,只有主库提供的数据是新数据,但是从库仍然提供的是旧数据,随着时间的推移,从库会和主库的数据进行同步,从库也会提供出正确的数据.
  • 可用性: 保证每个请求都有相应,但是响应的结果可能响应的是旧数据.
  • 分区容错性: 当网络出现异常的时候,系统仍然可以对外提供服务.

CAP理论告诉我们:== 一个分布式系统中不可能同时满足数据的一致性,服务的可用性和分区容错性这三个基本的要求,最多只能同时满足两个==.
在分布式系统中,系统之间的网络不能100%保证健康,服务又必须对外保证服务.因此我们必须保证分区容错性,那就只能在C和A中保证一个,也就是CP架构或者是AP架构.
正常情况:
在这里插入图片描述
网络异常:
在这里插入图片描述
CP架构: 为了保证分布式系统对外的数据一致性,于是选择不返回任何数据或者是不能及时返回数据.
AP架构: 为了保证分布式系统的可用性,结点2返回的是V0版本的旧数据.

1.1.5 常见的注册中心

  1. Eureka
    Eureka是Netflix开发的基于REST的服务发现框架,主要用于服务注册,管理,负载均衡和服务故障转移.官方声明在Eureka2.0版本停止维护,不建议使用.但是Eureka是SpringCloud服务注册/发现的默认实现,所以目前还是有很多公司在使用.CAP理论中,他使用的是AP架构.
  2. Nacos
    Nacos是SpringCloudAlibaba架构中重要的组件,除了服务注册,服务发现功能之外,Nacos还支持配置管理,流量管理,DNS,动态DNS等多种特性,包含Eureka的所有功能,还比他的功能更加强大.CAP理论中,AP架构和CP架构都支持,默认是AP架构.

1.2 Eureka介绍

Nacos我们后续介绍,我们首先来介绍Eureka.
Eureka官方文档: https://github.com/Netflix/eureka/wiki
Eureka主要分为两个部分:

  • Eureka Server: 作为注册中心的Server端,向微服务应用程序提供服务注册,发现,健康检查能力.
  • Eureka Client: 服务提供者,服务启动时,会向Eureka Server注册自己的信息,Eureka Server会存储这些信息.

关于如何完成服务注册发现和调用,主要分为以下的三个部分:

  1. 搭建Eureka Server
  2. 将order-service和product-service都注册到Eureka
  3. order-service远程调用的时候,从Eureka中获取到product-service的服务列表,然后进行交互.

1.3 搭建Eureka Server

Eureka-server是一个独立的微服务.

  1. 创建Eureka-server子模块
    在这里插入图片描述
  2. 引入Eureka-server依赖,构建项目插件,把该微服务构建为一个eureka的服务注册平台.
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  1. 完善启动类
    给这个项目编写一个启动类,并在启动类上添加@EnableEurekaServer注解,标志这个模块是一个Eureka服务注册平台,开启Eureka注册中心服务.
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServiceApplication.class,args);
    }
}
  1. 编写配置文件
server:
  port: 10010
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false # 表⽰是否从Eureka Server获取注册信息,默认为true.因为这是⼀个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这⾥设置为false
    register-with-eureka: false # 表⽰是否将⾃⼰注册到Eureka Server,默认为true.由于当前应⽤就是Eureka Server,故⽽设置为false.
    service-url:
# 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址.
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  1. 启动服务
    访问服务注册中心: http://127.0.0.1:10010/
    在这里插入图片描述
    可以看到Eureka-server已经启动成功了.

1.4 服务注册

接下来我们把product-service注册到eureka-service中.

1.4.1 引入eureka-client依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

1.4.2 完善配置文件

添加服务名称和eureka地址
添加服务名称,便于服务调用方可以通过服务名称来查找到服务.添加eureka地址便于服务注册方可以把服务注册到eureka中.

spring:
	application:
		name: product-service
	eureka:
		client:
			service-url:
				defaultZone: http://127.0.0.1:10010/eureka

1.4.3 启动服务

刷新注册中心:
我们看到产品注册服务已经被注册到了注册中心
在这里插入图片描述

1.5 服务发现

接下来我们修改order-service,==在远程调用的时候,从eureka-service中拉取product-service的服务信息,实现服务发现.

1.5.1 引入依赖

服务注册和服务发现都封装在一个eureka-client依赖中,所以服务发现时,也是引入eureka-client依赖.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

1.5.2 完善配置文件

服务发现也需要知道eureka地址,因此配置内容依然与服务注册一致,都是配置eureka信息.

spring:
	application:
	name: product-service
eureka:
	client:
	service-url:
	defaultZone: http://127.0.0.1:10010/eureka

1.5.3 修改远程调用代码

远程调用的时候,我们需要从eureka-service中获取product-service的列表(可能存在多个服务),并选择其中一个进行调用.

package com.jrj.order.service;

import com.jrj.order.mapper.OrderMapper;
import com.jrj.order.model.OrderInfo;
import com.jrj.order.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.List;

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;
    public OrderInfo selectOrder(Integer id){
        //获取到product-service的服务列表
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        //获取到服务列表中的第一个
        EurekaServiceInstance serviceInstance = (EurekaServiceInstance) instances.get(0);
        //从当前服务中获取到服务的URL
        URI uri = serviceInstance.getUri();
        OrderInfo orderInfo = orderMapper.selectOrderById(id);
        //把获取到的服务URL拼接到远程调用的URL中
        String url = uri + "/product/select?id=" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

1.5.4 启动服务

刷新注册中心
我们就可以看到order-service已经注册到eureka上了
在这里插入图片描述
访问接口http://127.0.0.1:8080/order/select?id=1,可以看到接口也调用成功了
在这里插入图片描述

2. 负载均衡—LoadBalance

2.1 负载均衡介绍

2.1.1 问题描述

观察上个章节的远程调用代码

//获取到product-service的服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
//获取到服务列表中的第一个
EurekaServiceInstance serviceInstance = (EurekaServiceInstance) instances.get(0);
  1. 根据应用名称获取了服务实例列表
  2. 从列表中选择了一个服务实例.

思考: 如果一个服务对应多个实例?流量是否可以合理的分配到多个实例呢?
现象观察:
我们再启动2个product-service实例
选中要启动的服务,右键选择复制配置.
在这里插入图片描述
弹出的框中,选择修改选项->添加虚拟机选项.
在这里插入图片描述
虚拟机选项中填写:-Dserver.port=9091,即在9091端口上再复制一个产品服务.
在这里插入图片描述
我们看到在idea的服务窗口上就会多出来2个启动配置,右键启动服务即可.
在这里插入图片描述
同样的操作,在9092端口上再开辟一个服务.之后启动订单服务和三个产品服务.我们看到product-service有3个示例.
在这里插入图片描述
在订单代码中添加日志,log.info(uri.toString());,之后访问订单服务,观察远程调用的端口.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们看到三次访问的接口都是9091端口.都是同一台主机,这不是我们想要的结果.我们启动了多个实例,我们希望的是可以分配到其他机器的负荷,那么如何实现呢?
解决方案:
我们可以使用取余发对实例调用的代码进行一定的修改.在其中引入自增原子类.

@Service
@Slf4j
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;
    //设置原子类
    private final AtomicInteger integer = new AtomicInteger(1);
    public OrderInfo selectOrder(Integer id){
        //获取到product-service的服务列表
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        //获取实例的时候采用取余的方式进行获取
        int index = integer.getAndIncrement() % instances.size();
        EurekaServiceInstance serviceInstance = (EurekaServiceInstance) instances.get(index);
        //从当前服务中获取到服务的URL
        URI uri = serviceInstance.getUri();
        log.info(uri.toString());
        OrderInfo orderInfo = orderMapper.selectOrderById(id);
        //把获取到的服务URL拼接到远程调用的URL中
        String url = uri + "/product/select?id=" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

之后向订单服务发送请求,观察日志:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们发现请求均匀地打到了每个实例上.

2.1.2 什么是负载均衡

负载均衡(Load Balance,简称LB),是高并发,高可用系统必不可少的关键组件.当服务流量增大时,通常会采用增加机器的方式进行扩容,负载均衡就是用来在多个机器或者其他资源中,按照⼀定的规则合理分配负载.

2.1.3 负载均衡的一些实现

上面的例子中,我们只是简单的对实例进行了轮训,但是真实的业务场景也会更加复杂,比如根据机器的配置进行负载分配,配置高的分配的流量高,配置低的分配流量低等.
服务多机部署的时候,开发人员都需要考虑负载均衡的实现,所以也出现了一些负载均衡器,来帮助我们实现负载均衡.
负载均衡分为服务端负载均衡和客户端负载均衡.

服务端负载均衡

在服务端进行负载均衡的算法分配.
比较有名的服务端负载均衡是Nginx.请求首先到达Nginx负载均衡器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问.
在这里插入图片描述

客户端负载均衡

在客户端进行负载均衡的算法分配
把负载均衡的功能以库的方式集成到客户端,而不再是由一台指定的负载均衡设备集中提供.
比如我们接下来要学习的Spring Cloud LoadBalancer就是一种客户端负载均衡
在这里插入图片描述
在上面的例子中,order-service就相当于客户端,而product-service就相当于服务器,订单服务首先从注册中心拉取服务实例列表,之后再决定如何进行负载均衡.
客户端负载均衡和服务端负载均衡最大的区别在于服务清单所存储的位置.

2.2 Spring Cloud LoadBalancer

2.2.1 快速上手

使用Spring Cloud LoadBalancer实现负载均衡
  1. 给RestTemplate这个Bean添加@LoadBalanced注解即可.因为我们在进行远程调用的时候就是通过RestTemplate这个Bean来进行调用的,所以我们就需要给他加上负载均衡.
@Configuration
public class BeanConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  1. 修改IP和端口为服务名称.在进行端口调用的时候,客户端负载均衡器会从注册中心中以服务名称自动拉取服务实例列表,并进行负载均衡分配.不需要像之前一样使用服务发现进行手动拉取.
@Service
@Slf4j
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RestTemplate restTemplate;
    //设置原子类
    public OrderInfo selectOrder(Integer id){
        OrderInfo orderInfo = orderMapper.selectOrderById(id);
        //把获取到的服务URL拼接到远程调用的URL中
        String url = "http://product-service/product/select?id=" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}
测试负载均衡

首先启动多个product-service实例,并重新启动order-service.
在这里插入图片描述
之后调用API接口.连续多次发送请求.我们看到三个服务实例都接收到了order-service的远程调用.
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2.2 常见的负载均衡策略

负载均衡策略是一种思想,无论是哪种负载均衡器,他们的负载均衡策略都是相似的.
Spring Cloud LoadBalancer仅支持两种负载均衡策略:轮询策略和随机策略.

  1. 轮询(Round Robin): 轮询策略是指服务器轮流处理用户的请求. 这是⼀种实现最简单, 也最常用的策略.
  2. 随机选择(Random):随机选择策略是指随机选择⼀个后端服务器来处理新的请求.
自定义负载均衡策略

Spring Cloud LoadBalancer默认的负载均衡策略是轮训策略,如果服务的消费者想要采用随机的负载均衡策略,下面就是实现方式:

  1. 定义随机算法对象(可以直接从SpringCloud官网复制),通过@Bean将其加入到Spring容器中.这里我们使用SpringCloud LoadBalancer提供的RandomLoadBalacer.
package com.jrj.order.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

public class CustomLoadBalancerConfiguration {
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

注意:

  1. 不用@Configuration注解
  2. 必须在组建的扫描范围之内
  1. 使用@LoadBalancerClient注解或者@LoadBalancerClients注解
    在RestTemplate配置类上方,使用这两个注解,可以对不同的服务提供方配置不同的客户端负载均衡的算法策略.
@Configuration
@LoadBalancerClient(name = "product-service",configuration = CustomLoadBalancerConfiguration.class)
public class BeanConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

name: 表示的是负载均衡对那个服务生效.
configuration: 表示的是使用的是那个负载均衡的策略.

2.3 服务部署

接下来我们学习如何把服务部署到Linux操作系统上.

2.3.1 准备数据

把sql脚本复制到Linux的MySQL中,修改项目配置文件中的数据库用户名和密码.

2.3.2 服务构建打包

  1. 对项目进行打包,需要对三个服务都分别进行打包:eureka-serveice,order-service,product-service
    在这里插入图片描述

2.3.3 在Linux操作系统上启动服务

首先把三个打包好的服务都上传到操作系统上.之后在后台启动服务.

#后台启动eureka-server, 并设置输出⽇志到logs/eureka.log
nohup java -jar eureka-server.jar >logs/eureka.log &
#后台启动order-service, 并设置输出⽇志到logs/order.log
nohup java -jar order-service.jar >logs/order.log &
#后台启动product-service, 并设置输出⽇志到logs/order.log
nohup java -jar product-service.jar >logs/product-9090.log &

之后再多启动两台product-service实例

#启动实例, 指定端⼝号为9091
nohup java -jar product-service.jar --server.port=9091 >logs/product-9091.log &
#启动实例, 指定端⼝号为9092
nohup java -jar product-service.jar --server.port=9092 >logs/product-9092.log &

2.3.4 开放端口号

在云服务器厂商的控制台上开放相应的端口号.

2.3.5 测试

  1. 访问eureka
    在这里插入图片描述
  2. 访问订单服务接口
    在这里插入图片描述
    远程调用成功.

http://www.kler.cn/a/506053.html

相关文章:

  • 【Excel】【VBA】双列排序:坐标从Y从大到小排列之后相同Y坐标的行再对X从小到大排列
  • 中国石油大学(华东)自动评教工具(涵盖爬虫的基础知识,适合练手)
  • zerotier搭建虚拟局域网,自建planet
  • day 27 日志文件(枚举,时间函数),目录io,多文件管理
  • React第二十二章(useDebugValue)
  • 【Rust自学】12.2. 读取文件
  • 《CPython Internals》阅读笔记:p177-p220
  • 初始C#.
  • V2X工具箱 - ADAS测试日志记录工具分享
  • 以太网实战AD采集上传上位机——FPGA学习笔记27
  • 《鸿蒙Next平台:决策树面对噪声数据的鲁棒性逆袭》
  • 《WebForms 数据库连接》
  • 电梯系统的UML文档03
  • 在JavaScript中生成和处理二维码
  • 使用 Charles 调试 Flutter 应用中的 Dio 网络请求
  • 7.User-Agent(用户代理)
  • 【数据分析实战】马来西亚吉隆坡景点评论分析:多维度游客体验与运营优化洞察
  • 第30章 汇编语言--- 性能优化技巧
  • STM32 FreeRTOS中断管理
  • 语音识别的预训练模型
  • 初始Java5
  • 49.字母异位词
  • 单芯片控制多个高性能伺服电机
  • 【Linux】多路转接select
  • PyTorch使用教程(1)—PyTorch简介
  • MongoDB 学习建模与设计思路--统计数据更新案例