微服务之负载均衡器

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等。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AWS S3存储桶中如何下载文件

AWS S3存储桶中如何下载文件 1.单个下载 AWS S3 控制台提供了下载单个文件的功能&#xff0c;但是不支持直接在控制台中进行批量下载文件。您可以通过以下步骤在 AWS S3 控制台上下载单个文件&#xff1a;   1.1登录 AWS 管理控制台。   1.2转到 S3 服务页面。   1.3单击…

使用 C# 学习面向对象编程:第 4 部分

C# 构造函数 第 1 部分仅介绍了类构造函数的基础知识。 在本课中&#xff0c;我们将详细讨论各种类型的构造函数。 属性类型 默认构造函数构造函数重载私有构造函数构造函数链静态构造函数析构函数 请注意构造函数的一些基本概念&#xff0c;并确保你的理解非常清楚&#x…

西门子PLC位逻辑指令学习(SCL语言)

R_TRIG 参数 功能 当CLK信号出现一个低电平到高电平的跳变时&#xff0c;输出Q导通一个周期。 实例 定义以下类型变量 "R_TRIG_DB"(CLK:"data".source,Q>"data".result); //当source输入出现低电平到高电平跳变&#xff0c;result信号…

《Brave New Words 》4.2 AI 与学生心理健康辅导的结合

Part IV Better Together 第四部分 携手共进 AI Meets Student Mental Health Coaching AI 与学生心理健康辅导的结合 Here’s the scenario: You’re minutes away from taking a final exam. You’ve studied, but your heart is racing and your mind has gone blank. Anxie…

MIPI A-PHY协议学习

一、说明 A-PHY是一种高带宽串行传输技术,主要为了减少传输线并实现长距离传输的目的,比较适用于汽车。同时,A-PHY兼容摄像头的CSI协议和显示的DSI协议。其主要特征: 长距离传输,高达15m和4个线内连接器; 高速率,支持2Gbps~16Gbps; 支持多种车载线缆(同轴线、屏蔽差分…

探索C++ STL的设计方式:将算法与数据结构分离

STL的设计 一、简介二、STL容器三、C数组四、用户定义的集合4.1、使用标准集合的typedef4.2、重用标准迭代器4.3、实现自己的迭代器 五、总结 一、简介 本文介绍STL的设计方式&#xff0c;以及如何设计自己的组件&#xff0c;使其能够充分利用STL的功能。 STL的设计旨在将算法…

多目标融合参数搜索

多目标融合 权重分类目人群。 trick normlize 不同Score之间含义、量级和分布差异较大&#xff1a;评分计算的不同部分的意义、范围和分布存在显著差异&#xff0c;这使得直接比较或融合它们的结果变得困难。显式反馈&#xff08;如点赞率&#xff09;存在用户间差异&#…

盘点四家企业软件巨头的Gen AI应用进程

文/明道云创始人任向晖 目前大部份行业分析还聚焦在Open AI&#xff0c;Langchain这些和Generative AI直接相关的企业和产品上。实际上&#xff0c;企业软件市场的感知和行动已经非常迅速。在此项技术进入公众视野18个月后&#xff0c;我们来盘点一下领先的企业软件应用是如何利…

Lua连接Redis客户端执行命令

该示例演示使用Redis连接池&#xff0c;及Redis执行命令与获取返回数据 require("api.website") local dkjson require("api.dkjson")-- 创建连接池 local pool redis_pool.new() -- 置连接池信息 pool:start("127.0.0.1",6379,"998866&…

C语言之argc、argv与main函数的传参

一 &#xff1a;谁给main函数传参 &#xff08;1&#xff09;调用main函数所在的程序的它的父进程给main函数传参&#xff0c;并且接收main函数的返回值 二 &#xff1a;为什么需要给main函数传参 &#xff08;1&#xff09;首先mian函数不传承是可以的&#xff0c;也就是说它的…

字符串拼接之char实现

目录 一、前言 二、memcpy函数用法 三、代码实现 一、前言 c中想到字符串拼接&#xff0c;我们都知道可以用c库中std::string的字符串中的简单加法进行拼接。示例&#xff1a; int main() {std::string str1 "hello";std::string str2 "World";std::…

OpenEuler系统学习

OpenEuler系统简介 什么是OpenEuler&#xff0c;个人理解就是&#xff1a;通过社区合作&#xff0c;打造统一和开放的操作系统。 官方是这么介绍的&#xff1a; 欧拉是数字基础设施的开源操作系统&#xff0c;可广泛部署于服务器、云计算、边缘计算、嵌入式等各种形态设备&a…

Vue 面试通杀秘籍

理论篇&#xff1a; 1. 说说对 Vue 渐进式框架的理解&#xff08;腾讯医典&#xff09; a) 渐进式的含义&#xff1a; 主张最少, 没有多做职责之外的事 b) Vue 有些方面是不如 React&#xff0c;不如 Angular.但它是渐进的&#xff0c;没有强主张&#xff0c; 你可以在原有…

Kimichat使用案例013:用kimichat批量识别出图片版PDF文件中的文字内容

文章目录 一、介绍二、具体操作三、信息识别一、介绍 图片版的PDF文件,怎么才能借助AI工具来提取其中全部的文字内容呢? 第一步:将PDF文件转换成图片格式 具体方法参见文章: Kimichat使用案例011:用kimichat将PDF自动批量分割成多个图片(零代码编程) 第二步:识别图片中…

Redis实战宝典:基础知识、实战技巧、应用场景及最佳实践全攻略

背景 在Java系统实现过程中&#xff0c;我们不可避免地会借助大量开源功能组件。然而&#xff0c;这些组件往往功能丰富且体系庞大&#xff0c;官方文档常常详尽至数百页。而在实际项目中&#xff0c;我们可能仅需使用其中的一小部分功能&#xff0c;这就造成了一个挑战&#…

重庆地区媒体宣传邀约资源整理

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 重庆地区媒体宣传邀约资源整理 一、主流媒体资源 电视台&#xff1a;重庆电视台&#xff1a;作为重庆地区最具影响力的电视媒体之一&#xff0c;拥有多个频道&#xff0c;涵盖新闻、综艺…

第2章 Rust初体验1/8:prelude:简化代码的自动标准库加载:猜骰子冷热游戏

讲动人的故事,写懂人的代码 在跑过Hello world程序后,三个人觉得这样还不过瘾,于是决定把那本Rust书里的猜数字游戏换个新面孔,变成“猜骰子冷热”游戏,然后一起动手实现一下。这样我们就能更深入地体验到Rust编程的乐趣啦。 (顺便说一句,如果你想找这本书的所有代码,…

Sklearn的安装和用法

安装sklearn相对简单&#xff0c;因为它是一个Python库&#xff0c;可以通过Python的包管理器pip来安装。 Windows、macOS和Linux通用步骤&#xff1a; 确保Python已安装&#xff1a; sklearn是基于Python的&#xff0c;所以首先确保你的计算机上安装了Python。推荐使用Pytho…

【图论应用】使用多路图(multigraph)对上海地铁站点图建模,并解决最短路径问题

文章目录 1 前言2 导包导入数据集3 创建多路图&#xff0c;导入节点和边信息3 绘制线路图4 计算最短路径 1 前言 最近正在学习图神经网络&#xff0c;先pick up了一些最基础的图论知识并学习了一些好玩的应用。 本文启发于B站视频&#xff08;BV1LY411R7HJ&#xff09;&#…

第1期JAVA社招面试经验月报

面经哥专注互联网社招面试经验分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥&#xff5c;面经哥整理了上月30篇面试经历&#xff0c;选取了较为热点高频的面试题供大家参考 基础知识类‍‍‍‍‍ 1、说下双亲委派原则以及类加…