Spring Cloud LoadBalancer 简单介绍与实战

前言

本文为SpringCloud的学习笔记,如有错误,希望各位高手能指出,主要介绍SpringCloudLoadBalancer的基本概念和实战

文章目录

  • 前言
  • 什么是LoadBalancer
  • 负载均衡分类
    • 服务端负载均衡
    • 客户端负载均衡
    • 服务端负载均衡和客户端负载均衡的优缺点
  • 常见负载均衡策略
  • 为什么要学习Spring Cloud LoadBalancer
  • 如何使用?
    • 项目搭建
    • 使用随机策略
    • 使用Nacos的负载均衡策略策略
    • 自定义策略(IP Hash为例)
      • 编写自定义策略类
      • 封装自定义负载均衡
      • 全局配置自定义负载均衡配置类
  • 缓存

什么是LoadBalancer

❀ LoadBalancer是一种流量分发机制,专业中文叫法“负载均衡”,这种流量分发可以通过软件或者硬件来实现服务端系统资源的均衡利用,提高整体系统的高可用和性能。


负载均衡分类

※ 负载均衡可以分为服务端负载均衡和客户端负载均衡

对于服务器端负载均衡,被称为:反向代理
对于客户端负载均衡,则称为:正向代理


服务端负载均衡

顾名思义,服务端负载均衡就是在服务器层面实现流量分发,如下图所示:
在这里插入图片描述

实现服务器端负载均衡的均衡器有:Nginx、HAProxy、F5等


客户端负载均衡

在知道服务器负载均衡后,客户端负载均衡也容易理解,这是在客户端就直接实现流量分发,也就是说,在客户端就知道请求去往何处,如下图所示:
在这里插入图片描述

客户端负载均衡有:Ribbon、SpringCloudLoadBalancer


服务端负载均衡和客户端负载均衡的优缺点

服务端负载均衡:

  • 优点:

    • 简化客户端逻辑:客户端无需了解服务实例的具体细节,只需要请求负载均衡器即可。
    • 可动态调整负载均衡策略:通过配置负载均衡器,能够根据实际情况动态调整请求的分发规则。
    • 提供更好的可扩展性:负载均衡器可与其他服务治理组件整合,如服务注册中心、服务发现等。
    • 减轻客户端压力:负载均衡器可以在后端服务器之间平均分发请求,降低单个服务器压力。
  • 缺点:

    • 单点故障:负载均衡器本身可能成为系统的单点故障,当负载均衡器出现问题时,会导致整个系统不可用。

    • 需要独立的负载均衡器:搭建和管理一个独立的负载均衡器需要额外的成本和维护工作。

    • 中心化决策:负载均衡的决策是集中在负载均衡器,无法根据客户端的具体状态和需求做出决策。

客户端负载均衡:

  • 优点:

    • 根据状态选择: 可以根据客户端的状态和需求进行负载均衡策略选择。

    • 分散决策:分散了负载均衡的决策,可以更加灵活地适应不同的场景需求。

    • 提供更好的容错能力:当某个服务实例故障时,客户端可以自动切换到其他可用实例。

  • 缺点:

    • 客户端复杂性增加:客户端需要实现负载均衡算法和服务发现逻辑,增加了客户端的复杂性。

    • 全局视图的欠缺:没有全局视图,可能导致不同客户端之间的实例选择不一致,进而影响系统整体性能和一致性。

    • 客户端资源消耗:每个客户端需要额外的资源来处理负载均衡逻辑,可能导致资源浪费。

综合来看,服务端负载均衡更适用于大型系统和复杂架构,可以提供统一的处理策略和更好的可扩展性。而客户端负载均衡则更适用于轻量级系统和简单架构,可以提供更灵活和定制化的负载均衡策略。


常见负载均衡策略

  1. 轮询(Round Robin):轮询策略就是按照顺序把每个请求分发给服务端,依次循环。适用于后端服务器性能相近,且每个服务器处理时间相近的情况
  2. 随机选择(Random):把请求随机发给后端服务器,适用于后端服务器性能相近,且每个服务器处理时间相近的情况,但无法保证请求均与分发
  3. 最少链接(Least Connections):最少连接策略将请求分发给当前连接数最少的后端服务器,可以确保后端服务器连接均衡,需要维护连接计数器。需要注意的是,“最少连接数”只是一个估计值,在千变万化的网络环境下,连接数也在变化。
  4. IP 哈希(IP Hash):根据客户端IP地址进行哈希计算,根据哈希值将请求发送到对应服务器上。这种策略可以用于确保来自同一客户端的请求都会被发送到后端服务器,适用于会话保持的情况。
  5. 加权轮询(Weight Round Robin):给每个后端服务器分配一个权重值,然后按照权值比例来分发请求,这种策略可以用来处理服务器性能不均衡的情况。
  6. 加权随机(Weigh Random):与加权轮询类似,但是按照权重值来随机选择后端服务器。这也可以用来处理后端服务器性能不均衡的情况,但是分发更随机。
  7. 最短响应时间(Least Response Time):根据后端服务器的响应时间情况,分发请求到响应时间最短的服务器。这样可以确保客户端或者最快的响应,适用于低延迟的应用。

为什么要学习Spring Cloud LoadBalancer

作为早期版本中SpringCloud内置的负载均衡器Ribbon,在SpringCloud 2020.0.0中已经被移除,可以在 https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2020.0-Release-Notes中进行查看更新日志。

取而代之的是SpringCloud官方提供的Spring-Cloud-LoadBalancer负载均衡

但Spring Cloud LoadBalancer中仅提供了三种负载均衡策略:轮询、加权、自定义(Nacos的负载均衡算alibaba自定义)

可以通过Spring Cloud LoadBalancer的配置类LoadBalancerClientConfiguration查看底层配置

@Configuration(proxyBeanMethods = false
)
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;public LoadBalancerClientConfiguration() {}@Bean@ConditionalOnMissingBeanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty("loadbalancer.client.name");return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
// 以下忽略......
}

这段代码中,reactorServiceInstanceLoadBalancer()方法的返回类型ReactorLoadBalancer< T >就是策略的实现接口,具体实现类如下图所示:
在这里插入图片描述
值得我们注意的是,在这个方法中,默认返回了RoundRobinLoadBalancer这个类,也就说SpringCloudLoadBalancer默认使用轮询策略。


如何使用?

在项目中添加Spring Cloud OpenFeign、注册中心(Nacos)、在添加Spring Cloud LoadBalancer则会在接口调用时直接使用SpringCloudLoadBalance。


项目搭建

我们先构建一个多模块项目SpringCloud-LoadBalancer-demo,具体过程省略,详情可以到这篇文章下查看《Nacos 注册中心介绍与实操》

在这里插入图片描述
在Provider子模块中,我们创建一个简单controller类

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate ServletWebServerApplicationContext servletWebServerApplicationContext;@RequestMapping("/getid")public String getId(@RequestParam Integer id){return servletWebServerApplicationContext.getWebServer().getPort()+"-provider-"+id;}
}

随后我们启动两个相同的Provider服务并注册到Nacos中
在这里插入图片描述
在这里插入图片描述
对于Consumer,我们需要建立sevice接口和controller类,controller类调用service接口的方法,该方法会在注册中心中通过负载均衡(默认轮询)获取服务端信息,然后将请求发送到指定服务端请求数据。
在这里插入图片描述
Sevice代码

@Service
@FeignClient("nacos-provider")
public interface UserService {@RequestMapping("/user/getid")String getId(@RequestParam("id") Integer id); //@RequestParam("id") 不能省略必须全部带上
}
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/getid")public String getId(@RequestParam("id") Integer id){return userService.getId(id);}
}

启动类添加注解:@EnableFeignClients

@SpringBootApplication
@EnableFeignClients // 开启OpenFeign
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}

那么接下来启动Consumer验证底层默认策略是否为轮询

会发现在我们没有配置负载均衡策略的时候,每次访问都是两个服务端轮流使用
第一次访问:
在这里插入图片描述
第二次访问:
在这里插入图片描述


使用随机策略

创建随机策略配置类(不需要@configuration注解)

public class RandomLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty("loadbalancer.client.name");return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

细心的同学就已经发现了,这个方法跟上面提到的LoadBalancerClientConfiguration .reactorServiceInstanceLoadBalancer()方法实现很像。这是因为官方文档中就是这么告诉我们如果要使用其他策略就需要这样做,复制一下方法体,修改返回的策略对象。

官方文档链接:https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer
在这里插入图片描述

当然如果只是写一个配置类还不够,我们还需要到启动类(全局配置)或者服务类(局部配置)中去启用它

在这里插入图片描述全局配置:

@SpringBootApplication
@EnableFeignClients // 开启OpenFeign
@LoadBalancerClients(defaultConfiguration = RandomLoadBalancerConfig.class)
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}

这时再去访问http://localhost:8080/user/getid?id=1时就会发现,我们不断刷新,它访问的值就完全随机了。(不知道怎么做动态图,不方便演示T_T)

在这里插入图片描述 局部配置

@Service
@FeignClient("nacos-provider")
@LoadBalancerClient(value = "nacos-provider", configuration = RandomLoadBalancerConfig.class)
public interface UserService {@RequestMapping("/user/getid")String getId(@RequestParam("id") Integer id); //@RequestParam("id") 不能省略必须全部带上
}

可能是SpringCloud版本问题,局部配置不生效,使用的任然是轮询策略,做了解即可


使用Nacos的负载均衡策略策略

@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerConfig.class)
public class NacosLoadBalancerConfig {@Resourceprivate NacosDiscoveryProperties nacosDiscoveryProperties;@Beanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty("loadbalancer.client.name");return new NacosLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name, nacosDiscoveryProperties);}
}

与其他两个官方儿子不一样,Nacos的负载均衡器还需要额外数据信息在这里插入图片描述
启动类添加注解

@SpringBootApplication
@EnableFeignClients // 开启OpenFeign
//@LoadBalancerClients(defaultConfiguration = RandomLoadBalancerConfig.class)
@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerConfig.class)
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
}

我们会发现Nacos中使用的不是轮询,翻阅底层实现,会发现他是权重策略,所以为了验证这个,我们到Nacos注册中心中去修改一下服务端权重
在这里插入图片描述
这个时候我们再去访问,就可以发现它会大部分请求都使用53922这个端口的服务(无动图不方便演示,读者可以自己实操体验一下)

局部配置NacosNacos策略是生效的,可以自行测试


自定义策略(IP Hash为例)

要实现自定义策略需要三个步骤

  1. 编写自定义策略类
  2. 封装自定义策略类
  3. 全局或者局部使用自定义配置类

编写自定义策略类

回到我们下面这张图
在这里插入图片描述

不难发现,ReactorLoadBalancer< T >是我们负载均衡器的实现上层骨架,这个就是设计模式中的“模板方法模式”,所有人都必须按照骨架进行开发,那么我们自定义策略类也需要如此,但我们去实现的接口是他的子接口ReactorServiceInstanceLoadBalancer,重写它的两个choose方法。

MyLoadBalancer实现

public class MyLoadBalancer implements ReactorServiceInstanceLoadBalancer {private static final Log log = LogFactory.getLog(MyLoadBalancer.class);private final String serviceId;private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;public MyLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {this.serviceId = serviceId;this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;}public Mono<Response<ServiceInstance>> choose(Request request) {// 提供备选服务列表ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);// 选择服务实例return supplier.get(request).next().map((serviceInstances) -> {return this.processInstanceResponse(supplier, serviceInstances);});}private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {// 从备选列表中选择一个具体的服务实例Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());}return serviceInstanceResponse;}private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {// 实例为空if (instances.isEmpty()) {if (log.isWarnEnabled()) {log.warn("No servers available for service: " + this.serviceId);}return new EmptyResponse();} else { // 服务不为空// 获取Request对象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String ipAddress = request.getRemoteAddr();System.out.println("用户IP"+ipAddress);int hash = ipAddress.hashCode();int index = hash%instances.size();ServiceInstance instance = (ServiceInstance)instances.get(index);return new DefaultResponse(instance);}}
}

代码看起来多,但是你如果看一下官方两个亲儿子的源码就会发现,其实只需要复制一下,修改getInstance这段核心代码就可以了
在这里插入图片描述


封装自定义负载均衡

构建Config类,使用同样配方进行封装

public class MyLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty("loadbalancer.client.name");return new MyLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

全局配置自定义负载均衡配置类

启动类

@SpringBootApplication
@EnableFeignClients // 开启OpenFeign
//@LoadBalancerClients(defaultConfiguration = RandomLoadBalancerConfig.class)
//@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerConfig.class)
@LoadBalancerClients(defaultConfiguration = MyLoadBalancerConfig.class)
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}

实际结果,只会访问固定一个端口


缓存

Spring Cloud LoadBalancer在获取实例时有两种选择
1.即使获取:每次从注册中心得到最新健康的实例,效果好,但是得一直询问,系统开销比较大
2.缓存服务列表:每次得到服务列表之后,缓存一段时间,这样能保证性能,同时也能兼容一定的及时性

Spring Cloud LoadBalancer中默认开始缓存服务列表
Spring Cloud LoadBalancer默认缓存重要特性有两项

  1. 缓存的过期时间为35S
  2. 缓存保存个数为256个

我们可以通过以下配置改变这些配置

Spring:cloud:loadbalancer:cache:ttl:35scapacity: 1024# enable: false # 开启缓存

END
希望对你有帮助

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

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

相关文章

评测|PolarDB MySQL 版 Serverless

评测&#xff5c;PolarDB MySQL 版 Serverless 目录 一、测试背景 1.1、云原生数据库 PolarDB Serverless新架构概念 1.2、Serverless资源弹性扩缩触发条件 二、PolarDB的Serverless能力与同类型产品进行对比 三、动态弹性升降资源的能力测试 3.1、测试资源 3.2、测试一…

ubuntu22.04在线安装redis,可选择版本

安装脚本7.0.5版本 在线安装脚本&#xff0c;默认版本号是7.0.5&#xff0c;可以根据需要选择需要的版本进行下载编译安装 sudo apt-get install gcc -y sudo apt-get install pkg-config -y sudo apt-get install build-essential -y#安装redis rm -rf ./tmp.log systemctl …

freeRTOS下载链接(sourceForge)

FreeRTOS Real Time Kernel (RTOS) download | SourceForge.net 文件名&#xff1a;FreeRTOSv202212.00.exe 双击后会自动变成这个样子的&#xff1a; 文件夹大小&#xff1a;506M 可以看到跟那个教程里面的文件结构是一模一样的&#xff0c;所以很可能是同一个最新版本的文件…

Linux(Centos)上使用crontab实现定时任务(定时执行脚本)

场景 Windows中通过bat定时执行命令和mysqldump实现数据库备份&#xff1a; Windows中通过bat定时执行命令和mysqldump实现数据库备份_mysqldump bat-CSDN博客 上面讲windows中使用bat实现定时任务的方式&#xff0c;如果是在linux上可以通过crontab实现。 cron是服务名称。…

怎样提升伦敦银买卖技巧?

如果投资者想提升伦敦银的买卖技巧&#xff0c;可以学习一些有用的技术分析方法。所谓技术分析&#xff0c;就是通过对行情过往价格和相关交易数据进行收集&#xff0c;用图表的方式解读白银市场&#xff0c;进而预测行情未来主线走势、判断价格细节变化、寻找重要支撑点阻力点…

TikTok Shop 与英国皇家邮政合作:为卖家提供“Click and Drop”服务

11 月 21 日&#xff0c;TikTok Shop 宣布与皇家邮政 建立新的合作伙伴关系 &#xff0c;为平台上的商家推出 Click & Drop。此次合作将使各种规模的商家能够通过将皇家邮政的 Click & Drop 与其 TikTok Shop 帐户集成来改善其履行体验并更有效地发出订单&#xff0c;…

科普:多领域分布式协同仿真

分布式协同仿真是一种在分布式计算环境中进行协同工作的仿真方法。使用该方法进行协同仿真时&#xff0c;仿真任务将被分发到多个计算节点上&#xff0c;并且这些节点可以同时工作以模拟完整的系统行为。分布式协同仿真已被广泛应用于工程、科学和军事领域&#xff0c;以便更好…

医保线上购药系统:代码驱动的医疗创新

医保线上购药系统&#xff0c;这是一个融合技术和医疗的创新典范。本文将通过简单的技术代码示例&#xff0c;为您揭示这一系统是如何通过技术驱动医疗创新&#xff0c;为用户提供更智能、便捷的健康管理体验的。 1. 前端界面开发 使用React框架&#xff0c;我们可以轻松构建…

深度探究数据要素市场,企业为什么要参与数据资产化建设

我国正在发展数字经济&#xff0c;培育数字要素市场&#xff0c;推进数据市场化。在十四五数字经济发展规划中就已经将数据要素列为数字经济深化发展的核心引擎。今天和大家分享关于数据要素的前世今生&#xff0c;您将了解以下知识点&#xff1a; 1.什么是数据要素&#xff1f…

可视化工作流管理流程及工具

Leangoo领歌是一款永久免费的专业的敏捷开发管理工具&#xff0c;提供端到端敏捷研发管理解决方案&#xff0c;涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。 Leangoo领歌上手快、实施成本低&#xff0c;可帮助企业快速落地敏捷&#xff0c;提质增效、缩短周期、加速创新…

广告屏LED屏断电检测远程控制开关方案应用钡铼技术S270

广告屏LED屏断电检测&#xff1a; 广告屏和LED屏在商业和公共场所的广泛应用中扮演着重要角色&#xff0c;但由于断电问题可能导致广告屏无法正常显示&#xff0c;进而影响广告宣传效果和客户体验。而S270作为一种高效稳定的远程控制开关&#xff0c;可以实现广告屏LED屏的断电…

Git 与 Maven:企业级版本管理与版本控制规范设计

一、背景 当今&#xff0c;许多开发人员熟悉 GitFlow 工作流程&#xff0c;但往往忽略了 GitFlow 如何与 Maven 版本控制结合&#xff0c;尤其是在管理 snapshot 和 release 版本时的最佳实践。本文旨在整合 GitFlow 工作流程与 Maven 版本管理&#xff0c;提出一个统一的企业…

案例012:Java+SSM+uniapp基于微信小程序的科创微应用平台设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

虾皮知虾数据分析软件:优化您的电商经营

在当今竞争激烈的电商市场&#xff0c;了解市场动态、分析竞争对手和产品趋势是成功经营的关键。虾皮知虾数据分析软件是一款强大的工具&#xff0c;为电商卖家提供了全面的数据采集和分析功能。本文将介绍虾皮知虾数据分析软件的特点和功能&#xff0c;以及如何利用它来优化您…

读懂毛京波的营销,也就读懂了路特斯的提速转变

“尽管我们交付还不到一年时间&#xff0c;但是今天Emeya一发布&#xff0c;我们的三车主又诞生了&#xff0c;他有Emira、Eletre&#xff0c;马上又定了Emeya&#xff0c;说明他对路特斯还是非常认可的&#xff0c;”路特斯集团CEO冯擎峰欣喜地说道&#xff0c;一个产品能不能…

基于51单片机电子钟闹钟LCD1602显示proteus仿真设计

基于51单片机的LCD1602电子钟闹钟proteus仿真设计 基于51单片机的LCD1602电子钟闹钟proteus仿真设计功能介绍&#xff1a;仿真图&#xff1a;原理图&#xff1a;设计报告&#xff1a;程序&#xff1a;器件清单&#xff1a;资料清单&&下载链接&#xff1a; 基于51单片机…

16.Python 多进程和多线程

进程是应用程序正在执行的实体&#xff0c;当程序执行时&#xff0c;也就创建了一个主线程。进程在创建和执行需要占用一定的资源&#xff0c;如内存、文件、I/O设备等。 线程是CPU使用的基本单元&#xff0c;由主线程创建&#xff0c;并使用这个进程的资源&#xff0c;因此线…

【JavaEE初阶】认识线程、创建线程

1. 认识线程&#xff08;Thread&#xff09; 1.1 概念 1) 线程是什么 一个线程就是一个 "执行流". 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 "同时" 执行着多份代码. 举例&#xff1a; 还是回到我们之前的银⾏的例⼦中。之前我们主要描…

Python开源项目之人工智能老照片修复算法学习

文章目录 前言项目环境搭建conda虚拟环境创建激活环境Pytorch安装Synchronized-BatchNorm-PyTorch repository安装Global目录Synchronized-BatchNorm-PyTorch项目部署检测预处理模型下载下载脸部增强模型文件下载依赖完整部署后项目结构 项目使用验证一下总结关于Python技术储备…

比较2个点的3种结构在不规则平面上的占比

2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 3 3 3 x 3 3 2 2 2 1 2 2 2 2 2 1 2 2 在平面上有一个点x&#xff0c;再增加一个点,11的操作把平面分成了3部分2a1&#xff0c;2a2&#xff0c;2a3&#xff0c;3部分的比值是 2a1 2a2 2a3 5 25 …