微服务之负载均衡器

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 {@Autowiredprivate DiscoveryClient discoveryClient;//记录第几次访问private AtomicInteger atomicCount = new AtomicInteger(0);@Overridepublic ServiceInstance getInstances(String serviceId) {//1.根据服务的名称 获取 该服务集群地址列表List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);//2.判断是否nullif (instances == null || instances.size() == 0) {return null;}//3.使用负载均衡算法int index = atomicCount.incrementAndGet() % instances.size();// 0+1return 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 {@Autowiredprivate DiscoveryClient discoveryClient;@Overridepublic ServiceInstance getInstances(String serviceId) {//1.根据服务的名称 获取 该服务集群地址列表List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);//2.判断是否nullif (instances == null || instances.size() == 0) {return null;}// 生成随机 范围Random random = new Random();//3  0 1 2int 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 {@Autowiredprivate DiscoveryClient discoveryClient;private AtomicInteger countAtomicInteger = new AtomicInteger(0);@Overridepublic 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负载均衡的使用@Autowiredprivate 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: trueclients: 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 // 定义一个BeanReactorLoadBalancer<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.mzph.cn/diannao/27615.shtml

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

相关文章

学习了解JS的classlist

在JavaScript中&#xff0c;classList 是一个在DOM元素上用于操作元素类名的属性。它提供了一个比传统 className 属性更强大且更易于使用的方式来添加、移除和切换类名。 classList 不是一个函数&#xff0c;而是一个对象&#xff0c;它包含了几个方法&#xff0c;允许你以列…

Visual Studio 使用第三方库管理工具 vcpkg

一、介绍 Windows下开发C/C程序&#xff0c;少不了用开源的第三方库。比如线性代数和矩阵分析的库eigen&#xff0c;或者图像处理的OpenCV库。虽然这些库都是开源的&#xff0c;但是由于要编译debug和release版本的&#xff0c;32位以及64位的&#xff0c;如果像FFmpeg…

2022年5月起RabbitMQ社区停止了对CentOS7的支持

前言 CentOS 7 的 RabbitMQ RPM 软件包将于 2022 年 5 月停止使用&#xff0c;因为 CentOS 发行系列提供了过时版本的 OpenSSL 和 Linux 内核。 建议 CentOS 7 用户迁移到使用较新发行版的新集群 从 2022 年 5 月 1 日起&#xff0c;RabbitMQ 将停止对 CentOS 7 的支持。展望…

基于springboot实现校园组团平台系统项目【项目源码】计算机毕业设计

基于springboot实现校园组团平台系统的设计演示 SSM框架介绍 本课题程序开发使用到的框架技术&#xff0c;英文名称缩写是SSM&#xff0c;在JavaWeb开发中使用的流行框架有SSH、SSM、SpringMVC等&#xff0c;作为一个课题程序采用SSH框架也可以&#xff0c;SSM框架也可以&…

FullCalendar日历组件集成实战(14)

背景 有一些应用系统或应用功能&#xff0c;如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件&#xff0c;但功能比较简单&#xff0c;用来做数据展现勉强可用。但如果需要进行复杂的数据展示&#xff0c;以及互动操作如通过点击添加事件&#xff0…

每日一题——Python实现PAT乙级1028 人口普查 Keyboard(举一反三+思想解读+逐步优化)六千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 题目链接​编辑我的写法 专业点评 时间复杂度分析 空间复杂度分析 总结 我要更强…

解析Java中1000个常用类:Process类,你学会了吗?

在Java编程中,Process类是一个非常有用的工具,它允许开发者从应用程序内部启动和管理本地操作系统进程。 本文将详细探讨Java中Process类的用法,包括它的基本概念、常见操作、实际应用场景以及一些高级技巧。 一、Process类的基本概念 1.1 什么是Process类 在Java中,Pr…

Python基础教程(十八):MySQL - mysql-connector 驱动

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

碳化硅陶瓷膜良好的性能

碳化硅陶瓷膜是一种高性能的陶瓷材料&#xff0c;以其独特的物理和化学特性&#xff0c;在众多领域展现出了广泛的应用前景。以下是对碳化硅陶瓷膜的详细介绍&#xff1a; 一、基本特性 高强度与高温稳定性&#xff1a;碳化硅陶瓷膜是一种非晶态陶瓷材料&#xff0c;具有极高的…

ChatTTS

基于您的要求&#xff0c;我为您推荐一个开源项目——ChatTTS。 **项目名称&#xff1a;ChatTTS** ChatTTS是一个基于Python的自然语言处理项目&#xff0c;主要用于生成文本对话。该项目主要基于一种名为Text-to-Speech (TTS)的模型&#xff0c;可以模拟人类的语音对话。它提供…

从GAN到WGAN(02/2)

文章目录 一、说明二、GAN中的问题2.1 难以实现纳什均衡(Nash equilibrium)2.2 低维度支撑2.3 梯度消失2.4 模式坍缩2.5 缺乏适当的评估指标 三、改进的GAN训练四、瓦瑟斯坦&#xff08;Wasserstein&#xff09;WGAN4.1 什么是 Wasserstein 距离&#xff1f;4.2 为什么 Wassers…

mysql社区版可以用的聚类函数有哪些

MySQL社区版支持一系列聚类函数&#xff08;或称为聚合函数&#xff09;&#xff0c;这些函数用于对一组值执行计算并返回单个值。以下是MySQL中常用的一些聚类函数&#xff0c;并附带简要描述和相关数字或信息&#xff08;如适用&#xff09;&#xff1a; SUM() 功能&#x…

53.Python-web框架-Django开始第一个应用的多语言

针对上一篇的功能&#xff0c;本次仅对页面做了多语言&#xff0c;大家可以看看效果。 51.Python-web框架-Django开始第一个应用的增删改查-CSDN博客 目录 部门列表 新增部门 编辑部门 部门列表 源码 <!DOCTYPE html> {% load static %} {% load i18n %} <html …

JAVA开发 使用Apache PDFBox库生成PDF文件,绘制表格

1. 表格位置定点 2.执行效果展示&#xff08;截取PDF文件图片&#xff09; 3.执行代码 当我们使用Apache PDFBox库在PDF文件中创建带有表格的内容&#xff0c;需要遵循几个步骤。PDFBox本身并没有直接的API来创建表格&#xff0c;但我们可以通过定位文本、绘制线条和单元格矩形…

shell编程基础(第16篇:命令是什么?有哪些注意事项)

前言 前面我们已经使用过各种各样的命令&#xff0c;那么命令到底是什么呢&#xff1f;我们又该怎么理解该术语&#xff1f; 什么是命令&#xff1f; 命令是command的中文翻译&#xff0c;能在命令行中执行的是命令。因为早期的计算机只有文字界面&#xff0c;命令是程序&#…

高速公路智能管理系统:构建安全畅通的数字大动脉

随着城市化进程的加速和交通需求的增长&#xff0c;高速公路系统作为城市交通的重要组成部分&#xff0c;正承担着越来越多的交通运输任务。为了提升高速公路的安全性、便捷性和智能化管理水平&#xff0c;高速公路智能管理系统应运而生。本文将深入探讨高速公路智能管理系统的…

ExoPlayer 学习笔记

https://www.51cto.com/article/777840.html ExoPlayer支持多种媒体格式和流媒体协议的播放器 播放视频&#xff1a;player.play()暂停视频&#xff1a;player.pause()停止播放&#xff1a;player.stop() Media3 ExoPlayer | Android media | Android Developers implem…

双向链表详解及C++实现

一、引言 链表是一种常见的数据结构&#xff0c;它允许动态地分配内存空间&#xff0c;并通过指针&#xff08;或引用&#xff09;将数据元素连接在一起。双向链表作为链表的一种&#xff0c;除了拥有普通链表的特性外&#xff0c;每个节点还包含两个指针&#xff1a;一个指向…

Leetcode 剑指 Offer II 082.组合总和 II

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个可能有重复数字的整数数组 candidates 和一个目标数 tar…

能耗监控与管理平台

在当今社会&#xff0c;随着工业化、城市化的快速发展&#xff0c;能源消耗问题日益凸显&#xff0c;节能减排已成为全社会共同关注的焦点。在这个背景下&#xff0c;一款高效、智能的能耗监控与管理平台显得尤为重要。 一、HiWoo Cloud平台的概念 HiWoo Cloud是一款集数据采…