深入理解服务发现:从基础到实践

news2025/1/9 1:15:49

随着微服务架构的广泛应用,服务发现已经成为了一个不可或缺的组成部分。服务发现是微服务架构中的一个关键问题,它涉及到如何管理和协调在一个分布式系统中的大量服务。本文将深入探讨服务发现的基本概念、工作原理和实践应用。我们将首先介绍服务发现的基本概念和工作原理,然后通过实际案例来展示服务发现在实践中的应用,最后我们将探讨服务发现的挑战和未来发展趋势。希望通过本文,读者能够对服务发现有一个全面和深入的理解


文章目录

        • 1、服务发现简介
          • 1.1、微服务架构的基本概念
          • 1.2、服务发现的基本概念
          • 1.3、服务发现在微服务架构中的重要性
        • 2、服务发现的工作原理
          • 2.1、服务注册
          • 2.2、服务查找
          • 2.3、负载均衡
          • 2.4、服务监测
          • 2.5、健康检查
          • 2.6、动态更新
          • 2.7、各种协议的优缺点
        • 3、服务发现的实现
          • 3.1、服务发现提供者实现
          • 3.2、服务发现消费者实现
          • 3.3、服务发现注册中心实现
          • 3.4、Java实现注册中心简单案例
        • 4、服务发现的实际应用案例
          • 4.1、服务发现开源软件-Eureka
          • 4.2、服务发现开源软件-Etcd
          • 4.3、服务发现开源软件-ZooKeeper
          • 4.4、服务发现开源软件-Nacos
          • 4.5、服务发现开源软件-K8s
          • 4.6、服务发现的未来发展趋势


1、服务发现简介
1.1、微服务架构的基本概念

微服务架构是一种将单一应用程序划分为一组小的服务的架构风格。每个服务都运行在其自身的进程中,服务之间通过轻量级的机制(通常是HTTP资源API)进行通信。这些服务都围绕业务能力构建,并且可以通过全自动部署机制独立地进行部署。此外,这些服务可以用不同的编程语言编写,并使用不同的数据存储技术。
img

1.2、服务发现的基本概念

服务发现是分布式系统中的一个关键组件,它的主要功能是跟踪系统中所有服务的网络位置。在微服务架构中,由于服务数量众多且位置可能频繁变动,因此需要服务发现机制来动态地查找和监控服务。

服务发现通常包括服务注册和服务查找两个主要过程。服务注册是指服务启动时将自己的网络地址注册到服务注册中心;服务查找是指当一个服务需要调用另一个服务时,通过查询服务注册中心来获取被调用服务的网络地址。

通过服务发现,各个服务无需关心其他服务的具体位置,只需要知道服务的名称即可进行通信,大大提高了系统的灵活性和可扩展性。

1.3、服务发现在微服务架构中的重要性

在微服务架构中,服务发现的重要性主要体现在以下几个方面:

  1. 系统解耦:通过服务发现,各个服务无需关心其他服务的具体位置,只需要知道服务的名称即可进行通信,这大大降低了服务之间的耦合度。
  2. 提高可扩展性:由于服务的位置信息由服务发现系统管理,因此当需要增加或减少服务实例时,只需要在服务发现系统中进行更新即可,无需修改调用服务的代码。
  3. 提高可用性:服务发现系统通常会对服务进行健康检查,当某个服务出现故障时,可以快速将其从服务列表中移除,防止调用方调用到故障的服务。
  4. 负载均衡:服务发现系统可以配合负载均衡器使用,根据服务的负载情况动态地调整服务的调用。

因此,服务发现在微服务架构中起着至关重要的作用。


2、服务发现的工作原理

服务发现的工作原理主要包括两个步骤:服务注册和服务查找

2.1、服务注册

服务注册:当一个服务(例如,一个微服务实例)启动时,它会将自己的网络地址(如IP地址和端口号)以及其他可能的信息(如服务名称、版本号等)发送到服务注册中心。服务注册中心负责存储和维护这些信息,以便其他服务在需要与该服务通信时,可以通过查询服务注册中心来获取该服务的网络地址。这种机制使得服务之间可以动态地发现和通信,提高了系统的灵活性和可扩展性。

image-20230927154742592

2.2、服务查找

服务查找:服务查找是服务发现过程中的另一个重要步骤。当一个服务(例如,一个微服务实例)需要调用另一个服务时,它会向服务注册中心请求被调用服务的网络地址。服务注册中心会返回被调用服务的地址,然后调用方就可以直接与被调用服务进行通信。这种机制使得服务之间可以动态地发现和通信,提高了系统的灵活性和可扩展性。

2.3、负载均衡

服务注册中心也需要具备负载均衡的能力。在大型的分布式系统中,服务注册中心可能需要处理大量的服务注册和查找请求,如果所有的请求都由一个服务注册中心处理,可能会成为系统的瓶颈。因此,通常会部署多个服务注册中心实例,并通过负载均衡机制将请求分发到不同的实例上,以提高系统的处理能力和可用性。

此外,服务注册中心还需要提供一种机制,使得当一个服务有多个实例时,可以根据一定的策略(如轮询、随机、根据负载情况等)选择一个实例返回给调用方,这也是一种负载均衡的方式。

因此,服务注册中心不仅需要管理服务的注册和查找,还需要具备负载均衡的能力,以确保系统的高可用性和高性能。

2.4、服务监测

服务监测:服务注册中心需要对注册的服务进行监测,包括服务的可用性、响应时间、错误率等指标。这些监测数据可以用于分析服务的运行状况,及时发现和解决问题。

其中,服务的可用性检测通常通过健康检查(Health Check)来实现:

2.5、健康检查

健康检查:服务注册中心通常会定期对注册的服务进行健康检查,检查服务是否仍然可用。健康检查通常是通过向服务发送一个简单的请求,如 HTTP 的 HEAD 请求,如果服务正常响应,则认为服务是健康的;如果服务无法响应,或者响应错误,那么服务注册中心会认为服务不健康,将其从服务列表中移除,防止其他服务调用到不可用的服务。

2.6、动态更新

服务发现注册中心的动态更新是指,当服务的状态发生变化(如服务上线、下线、故障等)时,服务注册中心能够实时地更新服务的状态信息。

具体来说,动态更新主要包括以下几个方面:

  1. 服务注册:当新的服务实例启动时,它会将自己的网络地址和其他必要信息注册到服务注册中心,服务注册中心会将这些信息添加到服务列表中。
  2. 服务注销:当服务实例停止时,它会将自己从服务注册中心注销,服务注册中心会将该服务从服务列表中移除。
  3. 服务更新:如果服务的网络地址或其他信息发生变化,服务可以更新在服务注册中心的注册信息。
  4. 健康检查:服务注册中心会定期对服务进行健康检查,如果发现服务无法正常响应,会将该服务标记为不可用,或者从服务列表中移除。

通过这种动态更新机制,服务注册中心能够实时地反映系统中服务的最新状态,从而使得服务之间能够动态地发现和通信,提高系统的灵活性和可用性。

2.7、各种协议的优缺点

服务发现可以使用各种协议,包括 HTTP、RPC、DNS 等,各种协议都有其优缺点:

HTTP:

  • 优点:HTTP 是一种通用的、基于文本的协议,易于理解和调试,可以通过各种工具和库进行处理,适用于各种语言和平台;
  • 缺点:HTTP 的性能可能不如二进制协议,特别是在大规模的服务发现场景下。此外,HTTP 是一种无状态的协议,不适合需要长连接的场景

RPC(如 gRPC、Thrift):

  • 优点:RPC 通常比 HTTP 更轻量级,性能更高。许多 RPC 框架都提供了服务发现的功能,可以与 RPC 通信紧密集成,使用起来更方便;
  • 缺点:RPC 需要特定的客户端库,不如 HTTP 通用。此外,一些 RPC 协议可能不易通过网络防火墙

DNS:

  • 优点:DNS 是一种基于域名的服务发现协议,可以直接使用操作系统的 DNS 解析功能,无需额外的客户端库。此外,DNS 可以很好地支持负载均衡和故障转移;
  • 缺点:DNS 的更新延迟较高,不适合频繁变动的环境。此外,DNS 不支持服务的元数据,如服务的版本、状态等。

以上是服务发现使用各种协议的一些优缺点,具体选择哪种协议取决于系统的具体需求和环境。


3、服务发现的实现
3.1、服务发现提供者实现

服务发现的服务提供者实现主要包括以下几个步骤:

  1. 启动时注册:当服务启动时,它会将自己的信息(如服务名称、地址、端口等)注册到服务注册中心。这通常是通过调用服务注册中心的 API 来实现的。

  2. 定期发送心跳:为了让服务注册中心知道服务仍然可用,服务需要定期向服务注册中心发送心跳。如果服务注册中心在一段时间内没有收到服务的心跳,它会认为该服务已经下线。

  3. 健康检查:服务可能会提供一个健康检查的接口,让服务注册中心可以检查服务的健康状态。如果服务的健康状态发生变化,服务需要更新在服务注册中心的注册信息。

  4. 关闭时注销:当服务关闭时,它需要将自己从服务注册中心注销,以防止其他服务尝试调用已经不可用的服务。

以下是一个使用 Spring Cloud 和 Eureka 实现的服务提供者的例子:

@SpringBootApplication
@EnableEurekaClient
public class ServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceProviderApplication.class, args);
    }
}

在这个例子中,@EnableEurekaClient 注解启用了 Eureka 客户端,这使得服务在启动时自动注册到 Eureka 服务器,并定期发送心跳。服务的其他信息(如服务名称、地址、端口等)可以在配置文件中设置。

3.2、服务发现消费者实现

服务发现的服务消费者实现主要包括以下几个步骤:

  1. 查询服务:当服务消费者需要调用其他服务时,它首先需要查询服务注册中心,获取服务提供者的信息。这通常是通过调用服务注册中心的 API 来实现的。

  2. 负载均衡:如果有多个服务提供者提供相同的服务,服务消费者需要选择其中一个进行调用。这通常是通过负载均衡算法(如轮询、随机、最少连接等)来实现的。

  3. 错误处理:如果服务调用失败(如网络错误、服务不可用等),服务消费者需要进行错误处理。这可能包括重试、回退、熔断等策略。

以下是一个使用 Spring Cloud 和 Eureka 实现的服务消费者的例子:

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }

    @Autowired
    private DiscoveryClient discoveryClient;

    public void doSomething() {
        List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");
        if (!instances.isEmpty()) {
            ServiceInstance instance = instances.get(0); // 这里简单地取第一个实例,实际应用中可能需要使用负载均衡算法
            // 使用 instance.getHost() 和 instance.getPort() 获取服务地址和端口,然后进行服务调用
        }
    }
}

在这个例子中,@EnableDiscoveryClient 注解启用了服务发现客户端,这使得服务可以查询 Eureka 服务器获取服务提供者的信息。doSomething 方法中,我们首先通过 discoveryClient.getInstances 方法获取服务提供者的信息,然后进行服务调用。

服务发现的服务消费者实现主要包括以下几个步骤:

  1. 查询服务:当服务消费者需要调用其他服务时,它首先需要查询服务注册中心,获取服务提供者的信息。这通常是通过调用服务注册中心的 API 来实现的。

  2. 负载均衡:如果有多个服务提供者提供相同的服务,服务消费者需要选择其中一个进行调用。这通常是通过负载均衡算法(如轮询、随机、最少连接等)来实现的。

  3. 错误处理:如果服务调用失败(如网络错误、服务不可用等),服务消费者需要进行错误处理。这可能包括重试、回退、熔断等策略。

以下是一个使用 Spring Cloud 和 Eureka 实现的服务消费者的例子:

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }

    @Autowired
    private DiscoveryClient discoveryClient;

    public void doSomething() {
        List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");
        if (!instances.isEmpty()) {
            ServiceInstance instance = instances.get(0); // 这里简单地取第一个实例,实际应用中可能需要使用负载均衡算法
            // 使用 instance.getHost() 和 instance.getPort() 获取服务地址和端口,然后进行服务调用
        }
    }
}

在这个例子中,@EnableDiscoveryClient 注解启用了服务发现客户端,这使得服务可以查询 Eureka 服务器获取服务提供者的信息。doSomething 方法中,我们首先通过 discoveryClient.getInstances 方法获取服务提供者的信息,然后进行服务调用。

3.3、服务发现注册中心实现

服务发现的注册中心实现主要包括以下几个步骤:

  1. 接收服务注册:注册中心需要提供一个接口,让服务提供者可以将自己的信息(如服务名称、地址、端口等)注册到注册中心。

  2. 存储服务信息:注册中心需要将服务提供者的信息存储起来,以便服务消费者查询。这通常需要使用某种数据库或内存数据结构来实现。

  3. 提供服务查询:注册中心需要提供一个接口,让服务消费者可以查询服务提供者的信息。

  4. 接收服务心跳:注册中心需要接收服务提供者的心跳,以了解服务提供者的存活状态。如果在一段时间内没有收到服务提供者的心跳,注册中心会认为该服务已经下线。

  5. 提供服务注销:注册中心需要提供一个接口,让服务提供者在关闭时可以将自己从注册中心注销。

以下是一个使用 Spring Boot 和 HTTP 实现的简化的服务注册中心的例子:

@SpringBootApplication
@RestController
public class RegistryCenterApplication {
    private Map<String, String> services = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        SpringApplication.run(RegistryCenterApplication.class, args);
    }

    @PostMapping("/register")
    public void register(@RequestParam String serviceName, @RequestParam String serviceAddress) {
        services.put(serviceName, serviceAddress);
    }

    @GetMapping("/discover")
    public String discover(@RequestParam String serviceName) {
        return services.get(serviceName);
    }
}

在这个例子中,我们使用一个 ConcurrentHashMap 来存储服务信息,/register 接口用于服务注册,/discover 接口用于服务查询。这只是一个非常简化的例子,实际的服务注册中心会更复杂,需要处理并发、网络通信、错误处理、服务健康检查等问题。

3.4、Java实现注册中心简单案例

实现一个完整的服务注册中心涉及到的内容较多,包括网络编程、多线程编程、错误处理等,以下是一个简化的例子,使用 Spring Boot 和 HTTP 实现服务注册、服务查找和健康检查的功能。

首先,我们定义一个 ServiceInstance 类来表示服务实例:

public class ServiceInstance {
    private String serviceName;
    private String host;
    private int port;

    // 构造函数、getter 和 setter 省略
}

然后,我们定义一个 ServiceRegistry 类来实现服务注册和发现的功能:

import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ServiceRegistry {
    private Map<String, ServiceInstance> services = new ConcurrentHashMap<>();

    public void register(ServiceInstance instance) {
        services.put(instance.getServiceName(), instance);
    }

    public ServiceInstance discover(String serviceName) {
        return services.get(serviceName);
    }
}

接下来,我们定义一个 RegistryController 类来处理 HTTP 请求:

import org.springframework.web.bind.annotation.*;

@RestController
public class RegistryController {
    private final ServiceRegistry registry;

    public RegistryController(ServiceRegistry registry) {
        this.registry = registry;
    }

    @PostMapping("/register")
    public void register(@RequestBody ServiceInstance instance) {
        registry.register(instance);
    }

    @GetMapping("/discover/{serviceName}")
    public ServiceInstance discover(@PathVariable String serviceName) {
        return registry.discover(serviceName);
    }
}

最后,我们可以定义一个定时任务来进行服务健康检查:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class HealthCheckTask {
    private final ServiceRegistry registry;

    public HealthCheckTask(ServiceRegistry registry) {
        this.registry = registry;
    }

    @Scheduled(fixedRate = 60000)
    public void healthCheck() {
        // 对 registry 中的每个服务进行健康检查,如果检查失败,移除该服务
    }
}

这只是一个简化的例子,实际的服务注册中心会更复杂。例如,处理并发可能需要使用锁或其他并发控制机制;网络通信可能需要使用更复杂的协议,如 TCP、UDP 或 HTTP/2;错误处理可能需要考虑各种网络错误、超时、服务故障等情况。


4、服务发现的实际应用案例
4.1、服务发现开源软件-Eureka

Eureka 是 Netflix 开源的一款提供服务注册和发现的产品,它是 Spring Cloud 生态系统中的一部分,主要用于实现微服务架构中的服务治理功能。Eureka 的主要特点包括:

  1. 简单易用:Eureka 提供了简单易用的注解和配置属性,开发者可以很方便地将 Eureka 集成到 Spring Cloud 项目中;

  2. 服务注册与发现:Eureka Server 提供了服务注册功能,各个微服务节点启动后,会在 Eureka Server 中进行注册。Eureka Client 可以从 Eureka Server 中获取注册信息,实现服务发现;

  3. 客户端负载均衡:Eureka Client 内置了负载均衡器,可以很好地控制请求到各个服务节点的分发;

  4. 高可用:Eureka Server 可以配置为高可用模式,通过互相注册的方式,形成一个服务注册中心集群;

  5. 自我保护:在网络分区故障发生(延迟、卡顿、服务未正常下线等)时,Eureka Server 会保护服务注册表中的信息,不会立即将服务注册信息删除,使得微服务仍可用。

4.2、服务发现开源软件-Etcd

Etcd 是由 CoreOS 开发基于 Go 语言实现的,是一个开源的、高可用的分布式键值存储系统,用于共享配置和服务发现。Etcd 的主要特点包括:

  1. 简单易用:Etcd 的安装和配置都非常简单,提供了 HTTP API 进行交互,使用起来也很方便;
  2. 键值对存储:Etcd 是一个键值对存储系统,数据存储在分层组织的目录中,就像在标准文件系统中一样;
  3. 变更监测:Etcd 可以监测特定的键或目录的变化,并对值的更改做出反应,这对于实现动态配置更新和服务发现非常有用;
  4. 高性能:根据官方提供的 benchmark 数据,Etcd 的单实例支持每秒 2k+ 的读操作,可以满足大多数应用的需求;
  5. 高可用和一致性:Etcd 使用 Raft 算法,实现了分布式系统数据的可用性和一致性。即使部分节点发生故障,Etcd 仍能保证数据的可用性和一致性
4.3、服务发现开源软件-ZooKeeper

ZooKeeper 是 Apache 的一个开源项目,它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper 的主要特点包括:

  1. 简单易用:ZooKeeper 的模型是一个树形的目录结构,非常类似于文件系统。它提供了一组简单的 API,如创建节点、删除节点、读取节点数据、设置节点数据等,使用起来非常方便;
  2. 变更通知:ZooKeeper 支持 Watcher 机制,客户端可以在一个节点上注册一个 Watcher,当节点的数据发生变化时,Watcher 会得到通知。这对于实现配置动态更新、服务发现等功能非常有用;
  3. 高性能:ZooKeeper 采用了一种叫做 ZAB 的协议来保证高可用和一致性,它可以处理大量的读和稳定的写操作;
  4. 高可用和一致性:ZooKeeper 通过复制机制,将数据复制到各个工作节点上,只要半数以上的节点存活,ZooKeeper 就能正常服务。同时,ZooKeeper 保证了客户端能读到的数据都是最新的。
  5. 顺序一致性:ZooKeeper 保证了从同一个客户端发起的事务请求,最终将会按照发起的顺序在 ZooKeeper 中被应用。
4.4、服务发现开源软件-Nacos

Nacos 是阿里巴巴开源的一款易于使用的平台,用于管理、发现和配置微服务。Nacos 提供了一组简单的 API 来实现服务的注册、发现和健康检查。Nacos 的主要特点包括:

  1. 简单易用:Nacos 提供了一套简单易用的 API 和界面,使得开发者可以方便地管理和操作服务。

  2. 服务注册与发现:Nacos 提供了服务注册中心,支持服务的动态注册和发现,支持 DNS 和 HTTP 两种服务发现方式。

  3. 动态配置服务:Nacos 提供了动态配置服务,支持配置的版本管理、配置更新推送等功能,使得应用可以在运行时动态地获取和更新配置。

  4. 高可用和一致性:Nacos 通过内置的集群模式和数据持久化,保证了服务注册和配置信息的高可用和一致性。

  5. 支持微服务架构:Nacos 提供了与 Spring Cloud、Dubbo 等微服务框架的集成支持,使得开发者可以方便地构建微服务架构。

4.5、服务发现开源软件-K8s

Kubernetes(简称 K8s)是 Google 开源的一款容器编排平台,用于自动化部署、扩展和管理容器化应用程序。Kubernetes 的主要特点包括:

  1. 简单易用:Kubernetes 提供了一套丰富且易用的 API 和命令行工具,使得开发者可以方便地管理和操作容器。

  2. 服务发现与负载均衡:Kubernetes 可以自动为容器分配 IP 地址和 DNS 名称,并且可以在容器之间进行负载均衡。

  3. 自动部署与回滚:Kubernetes 可以根据预定义的策略自动部署和更新应用,如果新版本的应用出现问题,还可以自动回滚到旧版本。

  4. 横向扩展:Kubernetes 可以根据 CPU 使用率或其他预定义的指标自动扩展应用。

  5. 自我修复:Kubernetes 可以自动替换、杀死、重启不健康的容器,保证服务的可用性。

  6. 密钥与配置管理:Kubernetes 可以管理和保护敏感信息,如密码、OAuth 令牌、SSH 密钥等,并且可以在不重建镜像的情况下更新应用配置。

因此,Kubernetes 是一个非常适合用于构建和运行分布式系统的容器编排平台。

4.6、服务发现的未来发展趋势

服务发现作为微服务架构中的关键组件,其未来的发展趋势可能包括以下几个方面:

  1. 自动化:随着云计算和容器技术的发展,服务的部署和扩缩容越来越自动化,服务发现也需要支持自动化,能够自动感知服务的变化并更新服务的状态;

  2. 多云和混合云:越来越多的企业选择使用多云或混合云环境,服务发现需要能够跨越多个云平台和数据中心,提供统一的服务视图;

  3. 安全:随着微服务的广泛应用,服务之间的通信安全越来越重要,服务发现需要能够支持服务的身份验证和授权,防止未授权的服务访问;

  4. 规模化:随着微服务数量的增加,服务发现需要能够支持大规模的服务管理,提供高效的服务查询和更新能力;

  5. 标准化:目前服务发现的实现方式各异,缺乏统一的标准,未来可能会出现一些服务发现的标准或规范,以促进不同的服务发现系统之间的互操作性;

  6. 集成性:服务发现可能会与其他的系统管理和监控工具更紧密地集成,提供更全面的服务管理能力。

以上是对服务发现未来发展趋势的一些预测,具体的发展情况还需要根据技术和市场的变化来观察。

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

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

相关文章

怎么使用 Go 语言操作 Apache Doris

Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以极速易用的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的查询结果&#xff0c;不仅可以支持高并发的点查询场景&#xff0c;也能支持高吞吐的复杂分析场景。基于此&#xf…

为什么 Lettuce 会带来更长的故障时间?

作者&#xff1a;杨博东&#xff08;凡澈&#xff09; 本文详述了阿里云数据库 Tair/Redis 将使用长连接客户端在非预期故障宕机切换场景下的恢复时间从最初的 900s 降到 120s 再到 30s的优化过程&#xff0c;涉及产品优化&#xff0c;开源产品问题修复等诸多方面。 一、背景 …

【数据结构】排序算法(一)—>插入排序、希尔排序、选择排序、堆排序

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.直接插入排序 2.希尔排序 3.直接选择排…

力扣:112. 路径总和(Python3)

题目&#xff1a; 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

用css画一个半圆弧(以小程序为例)

一、html结构 圆弧的html结构是 两个块级元素嵌套。 <View classNamewrap><View className"inner">{/* 图标下的内容 */}</View></View>二、css样式&#xff1a;原理是两个半圆叠在一起&#xff0c;就是一个半圆弧。那么&#xff0c;如何画一…

【小白专属03】SpringBoot实现增删改查

目录 前言 一、新建Controller层 二、使用PostMan测试接口 前言 上节回顾 上一节我们SpringBoot集成了MybatisPlus。MybatisPlus是一个Mybatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 本节介绍 这一节&#x…

基于微信小程序的明星应援小程序设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

DirectX12_Windows_GameDevelop_0:启程之旅

前言 今天是2023年9月28日&#xff0c;明天就是中秋节了&#xff0c;先祝福大家中秋快乐&#xff01;时光飞逝&#xff0c;岁月如梭&#xff0c;大学四年一晃而逝&#xff0c;眨眼间我们即将毕业。毕业不是意味着要面对社会的险恶&#xff0c;也不是意味着要当打工社畜&#x…

cesium在vue中引入报错解决;cesium在vue中初始化地球

第一步&#xff1a; npm install cesium 第二步&#xff1a; 找到node_modules/cesium/Build/Cesium 文件夹&#xff0c;把这个 Cesium 文件夹复制一份到项目的 public 文件夹下 第三步&#xff1a; 在public文件夹下的index.html 文件中&#xff0c;head 标签里面&#…

51单片机实训项目之产品数量计数器

/********************************************************************************* * 【实验平台】&#xff1a; QX-MCS51 单片机开发板 * 【外部晶振】&#xff1a; 11.0592mhz * 【主控芯片】&#xff1a; STC89C52 * 【编译环境】&#xff1a; Keil μVisio3 * 【程序…

BiMPM实战文本匹配【上】

引言 今天来实现BiMPM模型进行文本匹配&#xff0c;数据集采用的是中文文本匹配数据集。内容较长&#xff0c;分为上下两部分。 数据准备 数据准备这里和之前的模型有些区别&#xff0c;主要是因为它同时有字符词表和单词词表。 from collections import defaultdict from …

3 OpenCV两张图片实现稀疏点云的生成

前文&#xff1a; 1 基于SIFT图像特征识别的匹配方法比较与实现 2 OpenCV实现的F矩阵RANSAC原理与实践 1 E矩阵 1.1 由F到E E K T ∗ F ∗ K E K^T * F * K EKT∗F∗K E 矩阵可以直接通过之前算好的 F 矩阵与相机内参 K 矩阵获得 Mat E K.t() * F * K;相机内参获得的方式…

spring6-IOC容器

IOC容器 1、IoC容器1.1、控制反转&#xff08;IoC&#xff09;1.2、依赖注入1.3、IoC容器在Spring的实现 2、基于XML管理Bean2.1、搭建子模块spring6-ioc-xml2.2、实验一&#xff1a;获取bean①方式一&#xff1a;根据id获取②方式二&#xff1a;根据类型获取③方式三&#xff…

Zilliz@阿里云:大模型时代下Milvus Cloud向量数据库处理非结构化数据的最佳实践

大模型时代下的数据存储与分析该如何处理?有没有已经落地的应用实践? 为探讨这些问题,近日,阿里云联合 Zilliz 和 Doris 举办了一场以《大模型时代下的数据存储与分析》为主题的技术沙龙,其中,阿里云对象存储 OSS 上拥有海量的非结构化数据,Milvus(Zilliz)作为全球最有…

华为摄像头智能安防监控解决方案

云时代来袭&#xff0c;数字化正在从园区办公延伸到生产和运营的方方面面&#xff0c;智慧校园&#xff0c;柔性制造&#xff0c;掌上金融和电子政务等&#xff0c;面对各种各样的新兴业态的涌现&#xff0c;企业需要构建一张无所不联、随心体验、业务永续的全无线网络&#xf…

多线程锁-线程锁知识概述、乐观锁和悲观锁

3. 说说Java"锁"事 3.1 从轻松的乐观锁和悲观锁开讲 悲观锁&#xff1a; 认为自己在使用数据的时候一定有别的线程来修改数据&#xff0c;因此在获取数据的时候会先加 锁&#xff0c;确保数据不会被别的线程修改&#xff0c;synchronized和Lock的实现类都是悲观锁…

【通意千问】大模型GitHub开源工程学习笔记(2)

使用Transformers来使用模型 如希望使用Qwen-chat进行推理,所需要写的只是如下所示的数行代码。请确保你使用的是最新代码,并指定正确的模型名称和路径,如Qwen/Qwen-7B-Chat和Qwen/Qwen-14B-Chat 这里给出了一段代码 from transformers import AutoModelForCausalLM, Aut…

正点原子lwIP学习笔记——WebServer实验

1. WebServer简介 Web Server就是提供Web服务的Server&#xff0c;主要功能是&#xff1a;存储、处理和传递网页给客户端&#xff0c;他只需支持HTTP协议、HTML文档格式以及URL&#xff0c;与客户端的网络浏览器配套。 其中&#xff0c;HTTP的协议就是基于TCP进一步实现的&…

零代码编程:用ChatGPT批量修改文件夹名称中的大小写

一个文件夹下面有很多个子文件夹&#xff0c;要把文件夹中的大写数字全部重命名为小写数字&#xff0c;比如将二 三 四&#xff0c;改成&#xff1a; 2 34 在ChatGPT中输入提示词如下&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个文件夹重命名的任务。具体步骤如…

芯片测试方案之如何测试芯片EN输入阈值?

在电源管理芯片的设计中&#xff0c;除了常规的VIN、VOUT以及GND端口之外&#xff0c;还会有SW、EN、FB等芯片独有的特殊端口引脚&#xff0c;这些引脚或负责电源开关的输入&#xff0c;或负责电路的反馈电压/电流&#xff0c;这些引脚在芯片的工作中有着极其重要的作用&#x…