微服务之负载均衡器

news2025/1/18 3:26:19

1、负载均衡介绍

负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。

根据负载均衡发生位置的不同, 一般分为服务端负载均衡和客户端负载均衡。

服务端负载均衡指的是发生在服务提供者一方,例如Nginx,通过Nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务 器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配。

客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请 求。例如spring cloud中的ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载 均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均 衡算法分配。

常见的负载均衡算法

自定义公共接口

package com.example.consumer.loadbalance;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

/**
 * @author
 * @ClassName LoadBalance
 * @addres www.boyatop.com
 */
public interface LoadBalance {
    /**
     * 负载均衡算法 给我多个地址 负载均衡 取出一个地址返回使用
     */
    ServiceInstance getInstances(String serviceId);
}

1)轮询算法

轮询算法实现思路:

例如在集合中 多个接口地址

[192.168.110.1:8080,192.168.110.2:8081]

0              1

第一次访问:1%2=1

第二次访问:2%2=0

第三次访问:3%2=1

第四次访问:4%2=0

[192.168.110.1:8080,192.168.110.2:8081,192.168.110.2:8082]

  0                 1               3

第一次访问:1%3=1

第二次访问:2%3=2

第三次访问:3%3=0

第四次访问:4%3=1

第五次访问:5%3=2第六次访问:6%3=0

package com.example.consumer.loadbalance;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 轮询算法
 *
 * @author
 * @ClassName RoundLoadBalance
 * @addres www.boyatop.com
 */
@Component
public class RoundLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;
    //记录第几次访问
    private AtomicInteger atomicCount = new AtomicInteger(0);

    @Override
    public ServiceInstance getInstances(String serviceId) {
        //1.根据服务的名称 获取 该服务集群地址列表
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        //2.判断是否null
        if (instances == null || instances.size() == 0) {
            return null;
        }
        //3.使用负载均衡算法
        int index = atomicCount.incrementAndGet() % instances.size();// 0+1
        return instances.get(index);
    }
}

2)随机算法

package com.example.consumer.loadbalance;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;

/**
 * 随机算法
 *
 * @author
 * @ClassName RandomLoadBalance
 * @addres www.boyatop.com
 */
@Component
public class RandomLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;

    @Override
    public ServiceInstance getInstances(String serviceId) {
        //1.根据服务的名称 获取 该服务集群地址列表
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        //2.判断是否null
        if (instances == null || instances.size() == 0) {
            return null;
        }
        // 生成随机 范围
        Random random = new Random();
        //3  0 1 2
        int index = random.nextInt(instances.size());
        return instances.get(index);
    }
}

3)故障转移算法

 @RequestMapping("/orderToMember3")
    public String orderToMember3() {
    /**
     *模拟其中的服务器宕机
     */
//    ServiceInstance serviceInstance = randomLoadBalance.getInstances("producer");
        List<ServiceInstance> instances = discoveryClient.getInstances("producer");
        //ServiceInstance serviceInstance = instances.get(0);
        for (int i = 0; i <instances.size(); i++) {
            ServiceInstance serviceInstance = instances.get(i);
            // 会员服务的ip和端口
            String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
            //调用的过程当中可能会出现服务宕机的情况  此刻应该实现故障转移机制
            try {
                //将获取请求服务的结果换成获取服务访问成功的对象  目的:验证服务是否宕机
                ResponseEntity<String> response = restTemplate.getForEntity(memberUrl, String.class);
                if (response == null) {
                    continue;
                }
                return "订单服务调用会员服务:" + response.getBody();
            }catch (Exception e){
                log.error("<e:{}>", e);
            }
        }
        return "fail";
    }

4)权重算法

[192.168.110.1:8080,192.168.110.1:8081]

Index=0=192.168.110.1:8080

Index=1=192.168.110.1:8081

权重算法如何 比例:

1:1

第一次访问 192.168.110.1:8080

第二次访问 192.168.110.1:8081

轮询机制 默认权重1:1

2:1

[192.168.110.1:8080,192.168.110.1:8081]

权重比例 2:1

Index=0 192.168.110.1:8080 权重=2

Index=1 192.168.110.1:8081 权重=1

2(index=0):1(index=1)

第一次访问 192.168.110.1:8080

第二次访问 192.168.110.1:8080

第三次访问 192.168.110.1:8081

第四次访问 192.168.110.1:8080

第五次访问 192.168.110.1:8080

第六次访问 192.168.110.1:8081

Index=0 192.168.110.1:8080 权重=2

Index=1 192.168.110.1:8081 权重=1

2(index=0):1(index=1)

权重的底层实现逻辑

【192.168.110.1:8080,192.168.110.1:8080

192.168.110.1:8081】

第一次访问1%3=1  ===192.168.110.1:8080

第二次访问2%3=2  ===192.168.110.1:8081

第三次访问3%3=0  ===192.168.110.1:8080

第四次访问4%3=1  ===192.168.110.1:8080

第五次访问5%3=2  ===192.168.110.1:8081

第六次访问6%3=0  ===192.168.110.1:8080

第七次访问7%3=1  ===192.168.110.1:8080

第八次访问8%3=1  ===192.168.110.1:8081

package com.example.consumer.loadbalance;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author
 * @ClassName WeightLoadBalance
 * @addres www.boyatop.com
 */
@Component
public class WeightLoadBalance implements LoadBalance {
    @Autowired
    private DiscoveryClient discoveryClient;
    private AtomicInteger countAtomicInteger = new AtomicInteger(0);

    @Override
    public ServiceInstance getInstances(String serviceId) {
        // 1.根据服务的id名称 获取该接口多个实例
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        if (instances == null) {
            return null;
        }
        /**
         * 192.168.75.1:8080 权重比例 2
         * 192.168.75.1:8081  权重比例 1
         * [192.168.75.1:8080,192.168.75.1:8080,192.168.75.1:8081]
         */
        ArrayList<ServiceInstance> newInstances = new ArrayList<>();
        // 循环遍历该服务名称 对应的多个实例
        instances.forEach((service) -> {
            // 获取该服务实例对应的权重比例
            Double weight = Double.parseDouble(service.getMetadata().get("nacos.weight"));
            for (int i = 0; i < weight; i++) {
                newInstances.add(service);
            }
        });
        // 线程安全性 i++
        return newInstances.get(countAtomicInteger.incrementAndGet() % newInstances.size());
    }
}
@Autowired
private WeightLoadBalance weightLoadBalance;
@RequestMapping("/orderToMember4")
public String orderToMember4() {

    /**
     *使用权重的方式
     */

    //1.根据服务的名称 获取 该服务集群地址列表
    //List<ServiceInstance> instances = discoveryClient.getInstances("producer");
    // 如何服务实例的获取权重比例呢?
    ServiceInstance serviceInstance = weightLoadBalance.getInstances("producer");
    // 会员服务的ip和端口
    String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
    return "订单服务调用会员服务:" + restTemplate.getForObject(memberUrl, String.class);
}

2、Ribbon(第一代)

1)Ribbon负载均衡介绍及实现

Spring Cloud Ribbon是基于Netflix Ribbon 实现的一套客户端的负载均衡工具,Ribbon 客户端组件提供一系列的完善的配置,如超时,重试等。通过Load Balancer获取到服务提 供的所有机器实例,Ribbon会自动基于某种规则(轮询,随机)去调用这些服务。Ribbon也可以实现我们自己的负载均衡算法

RestTemplate 添加@LoadBalanced注解

让RestTemplate在请求时拥有客户端负载均衡的能力

@Configuration
public class RestConfig {
    @Bean
    @LoadBalanced //开启负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

调用实现

//springcloud中Ribbon负载均衡的使用
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @RequestMapping("/orderToMember6")
    public String orderToMember6() {
        ServiceInstance serviceInstance = loadBalancerClient.choose("producer");//默认采用轮询机制
        String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
        return "订单服务调用会员服务:" + restTemplate.getForObject(memberUrl, String.class);
//        return "订单服务调用会员服务:" + restTemplate.getForObject("http://producer/getMember", String.class);
    }

2)Ribbon底层实现原理

SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求

基本流程如下:

拦截我们的RestTemplate请求http://userservice/user/1

RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-service

DynamicServerListLoadBalancer根据user-service到eureka拉取服务列表

eureka返回列表,localhost:8081、localhost:8082

IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081

RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求

3)Ribbon负载均衡策略

Ribbon内置了七种负载均衡规则,每种规则都有其特定的应用场景和策略。以下是这些规则的详细介绍:

RoundRobinRule(轮询策略)

    • 策略描述:这是Ribbon的默认负载均衡策略。通过简单的轮询服务列表来选择服务器。在没有可用服务的情况下,RoundRobinRule最多会轮询10轮,若最终没有找到可访问的服务,则返回NULL。
    • 特点:每个服务器依次被调用,确保每个服务器都能得到相等的负载。
    • 实现说明:轮询index,选择index对应位置的server

AvailabilityFilteringRule(可用性筛选策略)

    • 策略描述:先过滤掉非健康的服务实例,比如连接失败的服务,以及并发数过高的服务,然后再从剩余的服务中选择连接数较小的服务实例。
    • 特点:忽略无法连接的服务器,以及并发数过高的服务器,确保选择的服务都是可用的且负载较低的。
    • 参数配置:
      • 可以通过niws.loadbalancer..connectionFailureCountThreshold属性配置连接失败的次数。
      • 可以通过.ribbon.ActiveConnectionsLimit属性设定最高并发数。
    • 实现说明:使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的 运行状态

WeightedResponseTimeRule(权重策略)

    • 策略描述:为每个服务器赋予一个权重值,服务器的响应时间越长,该权重值就越少。这个规则会随机选择服务器,但权重值会影响服务器的选择。
    • 特点:响应快的服务器权重更高,被选中的概率也更大。
    • 实现说明:一个后台线程定期的从status里面 读取评价响应时间,为每个server 计算一weight。Weight的计算也 比较简单responsetime减去每个server自己平均的responsetime是  server的权重。当刚开始运行,没  有形成statas时,使用roubine策略 选择server

ZoneAvoidanceRule(区域回避策略)

    • 策略描述:根据服务所在区域(zone)的性能和服务的可用性来选择服务实例。如果在一个区域内有多台服务实例,并且区域内服务可用,那么只会在区域内进行选择;如果区域内服务不可用,才会选择其他区域的服务。
    • 特点:优先选择同区域的服务实例,以提高访问速度和可用性。
    • 实现说明:使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选 择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server), Availability Predicate用于过滤掉连 接数过多的Server。

BestAvailableRule(最佳可用策略)

    • 策略描述:忽略那些处于“短路”状态的服务器,并选择并发数较低的服务器。
    • 特点:确保选择的服务都是可用的,并且并发数较低,以提供最佳的服务性能。
    • 实现说明:逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server

RandomRule(随机策略)

    • 策略描述:随机选择一个可用的服务器。
    • 特点:随机性较强,适用于对服务器性能要求不高的场景。
    • 实现说明:在index上随机,选择index对应位 置的server

RetryRule(重试策略)

    • 策略描述:在一个配置的时间段内,如果选择的服务器不可用,则一直尝试选择一个可用的服务器。
    • 特点:具有重试机制,确保在服务器不可用时能够继续提供服务。
    • 实现说明:在一个配置时间段内当选择server 不成功,则一直尝试使用subRule 的方式选择一个可用的server

4)自定义负载均衡策略

通过定义IRule实现可以修改负载均衡规则,有两种方式:

① 代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:

@Bean
public IRule randomRule(){
    return new RandomRule();
}

② 配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:

userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

5)饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。

而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:

ribbon:
  eager-load:
    enabled: true
    clients: userservice

3、Loadbalancer(第二代)

Spring Cloud LoadBalancer是由SpringCloud官方提供的一个开源的、简单易用的客户端负载均衡器,它包含在SpringCloud-commons中用它来替换了以前的Ribbon组件。相比较于Ribbon,SpringCloud LoadBalancer不仅能够支持RestTemplate,还支持WebClient(WeClient是Spring Web Flux中提供的功能,可以实现响应式异步请求)

导入依赖

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

Loadbalancer提供的的负载均衡策略

  • RandomLoadBalancer - 随机策略
  • RoundRobinLoadBalancer - 轮询策略(默认)

算法切换

@Configuration // 标记为配置类
@LoadBalancerClient(value = "producer", configuration = RestTemplateConfig.class) // 使用负载均衡器客户端注解,指定服务名称和配置类
public class RestTemplateConfig {
 
    @Bean // 定义一个Bean
    @LoadBalanced // 使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    public RestTemplate restTemplate() {
        return new RestTemplate(); // 返回一个新的RestTemplate实例
    }
 
    @Bean // 定义一个Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, // 注入环境变量
                                                            LoadBalancerClientFactory loadBalancerClientFactory) { // 注入负载均衡器客户端工厂
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); // 获取负载均衡器的名称
 
        // 创建并返回一个随机负载均衡器实例
        return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

4、Ribbon和Loadbalancer的比较

Ribbon

1. 定义和用途

  • Ribbon是一个客户端负载均衡器,它是一个Java库,可以在客户端应用程序中使用。
  • 通过在客户端应用程序中维护服务实例列表,并使用负载均衡算法来选择要请求的服务实例,从而实现负载均衡。

2. 特点和优势

  • 适用于客户端负载均衡,将负载均衡逻辑集成到消费方进程中。
  • 消费者通过Ribbon来获取到服务提供方的地址。
  • Ribbon提供了多种负载均衡算法,如轮询、随机、加权轮询等。
  • 它还可以进行故障检查,检测服务器的健康状态,并自动从故障服务器中移除。

3. 与微服务的关系

  • 在微服务架构中,Ribbon常被用于Spring Cloud等Java微服务框架中,以提供客户端负载均衡和高可用支持。

LoadBalancer

1. 定义和用途

  • LoadBalancer是一个服务器端负载均衡器,它是一个独立的服务,可以在服务器集群中运行。
  • 通过接收客户端请求,并使用负载均衡算法来选择要处理请求的服务器实例,从而实现负载均衡。

2. 特点和优势

  • 适用于服务器端负载均衡,如常见的负载均衡工具有nginx、LVS,硬件上F5等集中式负载均衡设施。
  • 能够处理大量的并发请求,并根据服务器的负载情况动态分配请求。
  • 可以实现故障处理、实例健康检查、SSL转换、跨区域负载均衡等高级功能。

3. 与微服务的关系

  • 在微服务架构中,LoadBalancer通常被部署在服务提供者之前,作为客户端和服务提供者之间的代理。
  • 它可以根据配置的策略将请求分发到不同的服务实例上,从而确保服务的高可用性和可扩展性。

总结

  • Ribbon和LoadBalancer在微服务架构中都扮演着重要的角色,但它们的应用场景和实现方式有所不同。
  • Ribbon更侧重于客户端负载均衡,通过在客户端应用程序中集成负载均衡逻辑来实现;而LoadBalancer则更侧重于服务器端负载均衡,作为一个独立的服务来处理客户端请求。

5、loadbalancer本地负载均衡客户端 VS Nginx服务端负载均衡区别

Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求,即负载均衡是由服务端实现的。

loadbalancer本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

应用场景的:

Nginx属于服务器负载均衡,应用于Tomcat/Jetty服务器等,而我们的本地负载均衡器,应用于在微服务架构中rpc框架中:openfeign、dubbo等。

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

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

相关文章

第十五届蓝桥杯物联网试题(国赛)

好&#xff0c;很好&#xff0c;国赛直接来个阅读理解&#xff0c;我猛做4个小时40分钟&#xff0c;cpu都干冒烟了&#xff0c;也算是勉强做完吧&#xff0c;做的很仓促&#xff0c;没多检查就交了&#xff0c;方波不会&#xff0c;A板有个指示灯没做&#xff0c;其他应该都还凑…

C语言详解(文件操作)2

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

【python】flask 框架

python flask 框架 flask是一个轻量级的python后端框架 (Django, tornado, flask) 官网&#xff1a;欢迎来到 Flask 的世界 — Flask中文文档(3.0.x) 安装&#xff1a;pip install Flask -i https://pypi.douban.com 常识&#xff1a; http,默认端口号为80; https,默认端口号…

攻防世界---misc---embarrass

1、下载附件是一个数据包 2、用wireshark分析 3、ctrlf查找字符 4、 flag{Good_b0y_W3ll_Done}

[Algorithm][动态规划][完全背包问题][零钱兑换][零钱兑换Ⅱ][完全平方数]详细讲解

目录 1.零钱兑换1.题目链接2.算法原理详解3.代码实现 2.零钱兑换 II1.题目链接2.算法原理详解3.代码实现 3.完全平方数1.题目链接2.算法原理详解3.代码实现 1.零钱兑换 1.题目链接 零钱兑换 2.算法原理详解 思路&#xff1a; 确定状态表示 -> dp[i][j]的含义 dp[i][j]&am…

Python学习笔记速成版

数据容器 列表的方法-总览 具体操作 元组 定义 相关操作 注意事项 特点 字符串 总览 常用操作 特点 序列 定义 切片操作 Set集合 总览 定义 常用操作 注意事项 字典 总览 定义 常用操作 获取 嵌套 其他操作 summary 通用操作 字符串大小比较 函数进阶 多个返回值 多种传…

关闭windows11磁盘地址栏上的历史记录

关闭windows11的磁盘地址栏上的历史记录 windows11打开磁盘后访问某一个磁盘路径后会记录这个磁盘路径&#xff0c;而且有时候会卡住这个地址栏&#xff08;关都关不掉&#xff09;&#xff0c;非常麻烦。 如下图所示&#xff1a; 关闭地址栏历史记录 按下windows键打开开…

#15松桑前端后花园周刊-Turborepo 2.0、ESLint v9.4.0、重新学习promise、CSS gap

⚡️行业动态 ESLint 推出了一个新的 ESLint 配置迁移器 ESLint 用户没有升级到 ESLint v9.x 的最大原因之一是迁移配置文件似乎很困难和复杂。因此 Eslint 推出eslint/migrate-config支持将. eslintrc 文件迁移到 eslint.config.js&#xff0c;以帮助用户提高配置文件的速度。…

Qt——升级系列(Level Five):显示类控件、输入类控件、多元素控件、容器类控件、布局管理器

显示类控件 Label QLabel 可以⽤来显⽰⽂本和图⽚. 核⼼属性如下&#xff1a; 属性 说明 text QLabel 中的⽂本 textFormat ⽂本的格式. • Qt::PlainText 纯⽂本 • Qt::RichText 富⽂本(⽀持 html 标签) • Qt::MarkdownText markdown 格式 • Qt::AutoText 根…

MySQL—多表查询—练习(2)

一、引言 接着上篇博客《 MySQL多表查询——练习&#xff08;1&#xff09;》继续完成剩下的案例需求。 二、案例 &#xff08;0&#xff09;三张表&#xff08;员工表、部门表、薪资等级表&#xff09; 员工表&#xff1a;emp 部门表&#xff1a;dept 薪资等级表&#xff1a;…

[Leetcode]同时进行正向和逆向迭代匹配解决回文链表问题

题目链接:234. 回文链表 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 题解&#xff1a; currentNode 指针是先到尾节点&#xff0c;由于递归的特性再从后往前进行比较。frontPointer 是递归函数外的指针。若 currentNode.val ! frontPointer.val 则返回 false。…

从零开始搭建Electron项目(二)之例程解析

本专栏&#xff0c;前面学习了怎么下载例程并运行。 这里解析例程的构成 从零开始搭建Electron项目之运行例程-CSDN博客文章浏览阅读22次。最好的学习方式就是&#xff1a;给一段能够运行的代码示例。本文给出了例程资源&#xff0c;以及运行的步骤。在国内开发electron有一点特…

leetcode刷题记录35-419. 甲板上的战舰

问题描述 给你一个大小为 m x n 的矩阵 board 表示甲板&#xff0c;其中&#xff0c;每个单元格可以是一艘战舰 X 或者是一个空位 . &#xff0c;返回在甲板 board 上放置的 战舰 的数量。 战舰 只能水平或者垂直放置在 board 上。换句话说&#xff0c;战舰只能按 1 x k&#x…

LW-DETR:实时目标检测的Transformer, Apache-2.0 开源可商用,论文实验超 YOLOv8

LW-DETR&#xff1a;实时目标检测的Transformer&#xff0c; Apache-2.0 开源可商用&#xff0c;论文实验超 YOLOv8 LW-DETR 架构实例化高效训练高效推理 目的与解法拆解ViT编码器和DETR解码器多级特征图聚合变形交叉注意力窗口注意力和全局注意力 论文&#xff1a;https://arx…

C语言:结构体数组

结构体数组 介绍定义结构体定义结构体数组初始化结构体数组访问和修改结构体数组的元素遍历结构体数组 示例高级用法动态分配结构体数组使用 malloc 动态分配使用 calloc 动态分配 结构体数组作为函数参数结构体数组与指针多维结构体数组使用 typedef 简化结构体定义结构体数组…

【EDA】SSTA中最慢路径与最快路径统计计算

假设&#xff08;X1&#xff0c;X2&#xff09;为二元高斯随机向量&#xff0c;均值&#xff08;μ1&#xff0c;μ2&#xff09;&#xff0c;标准差&#xff08;σ1&#xff0c;σ2&#xff09;&#xff0c;相关系数ρ 定义&#xff1a;Xmax&#xff08;X1&#xff0c;X2&…

Keil软件仿真的使用

一、软件的初始化设置 初始设置可以按照下图&#xff0c;这里我使用的是STM32F103C8T6&#xff0c;所以单片机型号为STM32F103C8&#xff0c;这个设置在Debug目录下。然后进行时钟的设置&#xff0c;我们板上晶振为8M&#xff0c;这里将时钟改为8. 或许有人想问如果是别的型号单…

JavaScript基础用法(变量定义、输入输出、转义符、注释和编码规范)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

基于ensp的园区网络搭建综合实验

核心技术介绍 1、虚拟局域网&#xff08;VLAN&#xff09; 2、链路聚合&#xff08;E-trunk&#xff09; 3、多生成树协议&#xff08;MSTP&#xff09; 4、VLANIF三层逻辑接口 5、虚拟路由冗余协议&#xff08;VRRP&#xff09; 6、开放式最短路径优先&#xff08;OSPF&…

C语言:(动态内存管理)

目录 动态内存有什么用呢 malloc函数 开辟失败示范 free函数 calloc函数 realloc函数 当然realooc也可以开辟空间 常⻅的动态内存的错误 对NULL指针的解引⽤操作 对动态内存开辟的空间越界访问 对⾮动态开辟内存使⽤free释放 使⽤free释放⼀块动态开辟内存的⼀部分 …