当前位置: 首页 > news >正文

Spring Cloud Netflix 系列:Eureka 经典实战案例和底层原理解析

文章目录

  • 前言
  • Eureka 简介
    • 架构设计
    • 工作流程
  • 项目 demo 构建
    • Eureka Server 的搭建
    • Eureka Client 的配置
      • 补充说明
    • 运行效果
  • 深入使用
    • `Eureka` 注册中心添加认证
    • `搭建 Eureka 集群实现高可用`
      • 双节点集群搭建
    • 运行效果
    • 补充说明
      • 为什么要配置 `不同host`
  • 原理解析
    • 服务注册、心跳续期详细流程
        • `Eureka Client` 失效驱逐
    • 集群模式下如何注册 & 集群同步
    • 自我保护模式
      • 作用
      • 工作原理
  • 参考文档
  • 个人简介
  • 个人简介

前言

  • 在微服务架构中,服务注册与发现 是基础组件。Spring Cloud Netflix 提供了强大的服务治理工具——Eureka,它通过注册中心的概念,帮助我们实现服务注册、发现与健康监控。本文将详细讲解 Eureka 的基本原理、服务注册与高可用流程、以及常见配置和用法。

Eureka 简介

  • EurekaSpring Netflix OSS 中服务发现与注册的核心组件,在 Spring Cloud 2022.0.x 版本开始,Spring Netflix OSS 组件(例如 Hystrix、Zuul)被正式移除。Spring 团队逐渐停止了对这些组件的支持,转而支持基于 Spring Cloud 的其他解决方案,比如 Spring Cloud Gateway、Resilience4j 等。但 Eureka 仍然支持,说明在设计上 Eureka 作为服务注册与发现仍占有一席之地。
  • Spring Cloud Release Notes 参考

架构设计

  • Eureka 是 Netflix 开源的服务发现组件,遵循 AP 模式设计,采用 Client/Server 模式。它分为 Eureka Server 和 Eureka Client 两部分:
Eureka Server:作为注册中心,维护所有服务的注册信息;
Eureka Client:服务提供者或消费者,通过 Eureka Server 注册或获取服务信息。

工作流程

  • 服务注册:服务启动后,会将自身信息(如 IP、端口、服务名称等)注册到 Eureka Server 上。
  • 服务续约:Eureka Client 会定期向 Eureka Server 发送心跳,续约租约。
  • 服务发现:服务消费者从 Eureka Server 获取注册表,并根据服务名称访问目标服务。
  • 服务剔除:当某服务不再发送心跳时,Eureka Server 在租约过期后将其移出注册列表。

项目 demo 构建

Eureka Server 的搭建

  • 创建一个 Spring Boot 项目,并引入 Spring Cloud Netflix Eureka Server 依赖

  • pom.xml 文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>eureka-server</artifactId><version>1.0.0</version><packaging>jar</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.0</version></parent><properties><spring-cloud.version>2021.0.1</spring-cloud.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies>
</project>
  • 配置文件 application.yml
server:port: 8761spring:application:name: eureka-servereureka:instance:hostname: localhost  # Eureka Server 的主机名,其他服务会通过这个地址注册instance-id: ${spring.application.name}:${server.port}  # 实例 ID,唯一标识一个服务实例client:register-with-eureka: true  # 是否将 Eureka Server 本身作为客户端注册到注册中心fetch-registry: false  # Eureka Server 不拉取服务注册表(只提供服务注册功能)service-url:defaultZone: http://localhost:8761/eureka/  # Eureka Server 地址,客户端注册所用server:enable-self-preservation: false  # 启用自我保护模式,防止服务实例因心跳丢失被剔除eviction-interval-timer-in-ms: 60000  # 清理失效服务的时间间隔,单位为毫秒
  • 启动类
package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

Eureka Client 的配置

  • pom.xml 文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>service-demo1</artifactId><version>1.0.0</version><packaging>jar</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.0</version></parent><properties><spring-cloud.version>2021.0.1</spring-cloud.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
</project>
  • 配置文件 application.yml
server:port: 8081spring:application:name: service-demo1eureka:client:service-url:defaultZone: http://localhost:8761/eureka/  # Eureka Server 地址,客户端注册所用fetch-registry: true  # 是否从 Eureka Server 拉取服务注册表,服务提供者通常设置为 trueregister-with-eureka: true  # 是否将自己注册到 Eureka Server,服务提供者需要设置为 trueregistry-fetch-interval-seconds: 30  # 注册表拉取间隔instance:hostname: localhostinstance-id: ${spring.application.name}:${server.port}  # 实例 ID,唯一标识一个服务实例prefer-ip-address: true  # 使用 IP 地址注册服务,通常设置为 truelease-renewal-interval-in-seconds: 30  # 心跳间隔lease-expiration-duration-in-seconds: 90  # 过期时间
  • 启动类
package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

补充说明

  • Spring Cloud & Spring Boot 版本依赖参考
  • 报错 com.netflix.discovery.AbstractDiscoveryClientOptionalArgs that could not be found. 解决方法:需要引入 spring-boot-starter-web
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

运行效果

深入使用

Eureka 注册中心添加认证

  • 添加 Spring Security 模块
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 修改配置文件 application.yml
spring:application:name: eureka-security-serversecurity: # 配置 Spring Security 登录用户名和密码user:name: adminpassword: 123456
  • 添加 Java 配置 WebSecurityConfig
默认情况下添加SpringSecurity依赖的应用每个请求都需要添加CSRF token才能访问。
Eureka客户端注册时并不会添加,所以需要配置/eureka/**路径不需要CSRF token。package org.example.config;@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().ignoringAntMatchers("/eureka/**");super.configure(http);}
}
  • 运行效果

搭建 Eureka 集群实现高可用

  • 服务的注册和发现都是通过注册中心实现,一旦注册中心宕机所有服务的注册和发现都会不可用,因此我们可以 搭建 Eureka 集群实现高可用,集群一方面可以实现高可用,另一方面也可以分担服务注册和发现的压力。

双节点集群搭建

  • 下面我们搭建一个双节点的注册中心集群:
  • 复制一份启动配置

  • 修改配置文件 application.yml 实现相互注册
# 配置 host 文件
127.0.0.1 localhost1
127.0.0.1 localhost2# eureka-server1server:port: 8761eureka:instance:hostname: localhost1  # Eureka Server 的主机名,其他服务会通过这个地址注册prefer-ip-address: false  # 使用 IP 地址注册服务,通常设置为 trueinstance-id: ${spring.application.name}:${server.port}  # 实例 ID,唯一标识一个服务实例client:register-with-eureka: true  # 将 Eureka Server 本身作为客户端注册到注册中心fetch-registry: false  # Eureka Server 不拉取服务注册表(只提供服务注册功能)service-url:defaultZone: http://admin:123456@localhost2:8762/eureka/# eureka-server2server:port: 8762eureka:instance:hostname: localhost2  # Eureka Server 的主机名,其他服务会通过这个地址注册prefer-ip-address: false  # 使用 IP 地址注册服务,通常设置为 trueinstance-id: ${spring.application.name}:${server.port}  # 实例 ID,唯一标识一个服务实例client:register-with-eureka: true  # 将 Eureka Server 本身作为客户端注册到注册中心fetch-registry: false  # Eureka Server 不拉取服务注册表(只提供服务注册功能)service-url:defaultZone: http://admin:123456@localhost1:8761/eureka/# 上面两个注册中心实现相互注册,并修改 eureka-client 配置
eureka:client:service-url:defaultZone: http://admin:123456@localhost:8761/eureka/,http://admin:123456@localhost:8762/eureka/  

运行效果

补充说明

为什么要配置 不同host

  • eureka 底层使用 isThisMyUrl 方法去重,如果获取到相同的 host 会被当做一个主机被去重,无法实现集群同步。
    /*** Checks if the given service url contains the current host which is trying* to replicate. Only after the EIP binding is done the host has a chance to* identify itself in the list of replica nodes and needs to take itself out* of replication traffic.** @param url the service url of the replica node that the check is made.* @return true, if the url represents the current node which is trying to*         replicate, false otherwise.*/public boolean isThisMyUrl(String url) {final String myUrlConfigured = serverConfig.getMyUrl();if (myUrlConfigured != null) {return myUrlConfigured.equals(url);}return isInstanceURL(url, applicationInfoManager.getInfo());}

原理解析

服务注册、心跳续期详细流程

  • Eureka Client 在启动完成后实例状态为变更 UP 状态,并尝试进行客户端注册,注册成功后定时进行心跳请求保持客户端状态;若第一次注册失败,后续定时心跳续期请求会返回 204 ,并重新尝试注册。
  • Eureka Client在发送注册、心跳等请求时,会向 Eureka Server 集群节点 serviceUrlList 顺序逐个去尝试,如果有一个请求成功了,就不再去向其他节点请求,最多只重试3次,超过3次直接抛出异常。
    # com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient#execute@Overrideprotected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {List<EurekaEndpoint> candidateHosts = null;int endpointIdx = 0;// 顺序尝试前 numberOfRetries 可以注册中心实例for (int retry = 0; retry < numberOfRetries; retry++) {EurekaHttpClient currentHttpClient = delegate.get();EurekaEndpoint currentEndpoint = null;if (currentHttpClient == null) {if (candidateHosts == null) {candidateHosts = getHostCandidates();if (candidateHosts.isEmpty()) {throw new TransportException("There is no known eureka server; cluster server list is empty");}}if (endpointIdx >= candidateHosts.size()) {throw new TransportException("Cannot execute request on any known server");}currentEndpoint = candidateHosts.get(endpointIdx++);currentHttpClient = clientFactory.newClient(currentEndpoint);}try {EurekaHttpResponse<R> response = requestExecutor.execute(currentHttpClient);if (serverStatusEvaluator.accept(response.getStatusCode(), requestExecutor.getRequestType())) {delegate.set(currentHttpClient);if (retry > 0) {logger.info("Request execution succeeded on retry #{}", retry);}return response;}logger.warn("Request execution failure with status code {}; retrying on another server if available", response.getStatusCode());} catch (Exception e) {logger.warn("Request execution failed with message: {}", e.getMessage());  // just log message as the underlying client should log the stacktrace}// Connection error or 5xx from the server that must be retried on another serverdelegate.compareAndSet(currentHttpClient, null);if (currentEndpoint != null) {quarantineSet.add(currentEndpoint);}}throw new TransportException("Retry limit reached; giving up on completing the request");}# org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient#register@Overridepublic EurekaHttpResponse<Void> register(InstanceInfo info) {String urlPath = serviceUrl + "apps/" + info.getAppName();HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers),Void.class);return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();}
  • 从上面的设计中我们可以看出,为了避免注册中心实例单点压力过大,我们在配置 service-url 应该尽可能把所有地址都配置上,且顺序应该保持随机。
Eureka Client 失效驱逐
  • Eureka Service 会定时遍历遍历注册表中的实例,找出超过租约期的实例并将其从注册表中移除。若已启用自我保护模式,则停止驱逐,直到恢复心跳,自我保护模式关闭。
    # com.netflix.eureka.registry.AbstractInstanceRegistry#evict(long)public void evict(long additionalLeaseMs) {logger.debug("Running the evict task");// 判断自我保护模式是否启动:防止由于网络分区或临时的网络中断等非正常情况导致 Eureka 大规模地将实例误认为已失效并驱逐,避免影响系统的整体可用性。if (!isLeaseExpirationEnabled()) {logger.debug("DS: lease expiration is currently disabled.");return;}// We collect first all expired items, to evict them in random order. For large eviction sets,// if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it,// the impact should be evenly distributed across all applications.List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>();for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) {Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue();if (leaseMap != null) {for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) {Lease<InstanceInfo> lease = leaseEntry.getValue();if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {expiredLeases.add(lease);}}}}// To compensate for GC pauses or drifting local time, we need to use current registry size as a base for// triggering self-preservation. Without that we would wipe out full registry.// 即使关闭自我保护模式,若不将 renewalPercentThreshold 设置为 0 ,实例也会分批过期,避免网络原因造成服务难以恢复int registrySize = (int) getLocalRegistrySize();int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());int evictionLimit = registrySize - registrySizeThreshold;int toEvict = Math.min(expiredLeases.size(), evictionLimit);if (toEvict > 0) {logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit);// 随机驱逐的方式将过期实例的驱逐影响分布在不同应用之间,避免某一应用实例被全部驱逐。Random random = new Random(System.currentTimeMillis());for (int i = 0; i < toEvict; i++) {// Pick a random item (Knuth shuffle algorithm)int next = i + random.nextInt(expiredLeases.size() - i);Collections.swap(expiredLeases, i, next);Lease<InstanceInfo> lease = expiredLeases.get(i);String appName = lease.getHolder().getAppName();String id = lease.getHolder().getId();EXPIRED.increment();logger.warn("DS: Registry: expired lease for {}/{}", appName, id);internalCancel(appName, id, false);}}}
  • 除了自我保护模式以外,失效驱逐过程中还以为了分批和随机驱逐的方式来提供系统的可用性,分批驱逐举例:
假设 20 个租约,其中有 10 个租约过期。第一轮执行开始
int registrySize = 20;
int registrySizeThreshold = (int) (20 * 0.85) = 17;
int evictionLimit = 20 - 17 = 3;
int toEvict = Math.min(10, 3) = 3;
第一轮执行结束,剩余 17 个租约,其中有 7 个租约过期。第二轮执行开始
int registrySize = 17;
int registrySizeThreshold = (int) (17 * 0.85) = 14;
int evictionLimit = 17 - 14 = 3;
int toEvict = Math.min(7, 3) = 3;
第二轮执行结束,剩余 14 个租约,其中有 4 个租约过期。...以此类推,或者将 renewalPercentThreshold 设置为0 ,但不建议

集群模式下如何注册 & 集群同步

  • Eureka 属于 AP 设计,注册中心是完全平等和独立,且状态并不完全一致,当 Eureka Client 请求注册、续期、下线到某一个注册中心实例时,该实例会将这些信息同步到集群中其它注册中心,以注册的代码为例:
    # com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#register/*** Registers the information about the {@link InstanceInfo} and replicates* this information to all peer eureka nodes. If this is replication event* from other replica nodes then it is not replicated.** @param info*            the {@link InstanceInfo} to be registered and replicated.* @param isReplication*            true if this is a replication event from other replica nodes,*            false otherwise.*/@Overridepublic void register(final InstanceInfo info, final boolean isReplication) {int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {leaseDuration = info.getLeaseInfo().getDurationInSecs();}super.register(info, leaseDuration, isReplication);// 同步到集群其它服务器replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);}# com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateToPeers/*** Replicates all eureka actions to peer eureka nodes except for replication* traffic to this node.**/private void replicateToPeers(Action action, String appName, String id,InstanceInfo info /* optional */,InstanceStatus newStatus /* optional */, boolean isReplication) {Stopwatch tracer = action.getTimer().start();try {if (isReplication) {numberOfReplicationsLastMin.increment();}// If it is a replication already, do not replicate again as this will create a poison replicationif (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {return;}for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {// If the url represents this host, do not replicate to yourself.if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {continue;}replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);}} finally {tracer.stop();}}

自我保护模式

作用

  • Eureka 通过定期接收注册实例发送的心跳信号(续约请求)来判断服务是否存活。当一个实例未能按时发送心跳信号时,Eureka 会将其标记为“不可用”,并从注册列表中移除。但是,当遇到网络分区、延迟或临时故障时,可能导致一些正常运行的实例无法发送心跳信号,导致 Eureka 错误地将这些实例下线,进而造成服务的大量下线,影响系统的稳定性。
  • 为了防止这种情况,Eureka 的自我保护机制的目的是:
避免大量下线:当心跳数量突然下降时,停止过快地移除实例。
提高系统可用性:在网络抖动或短暂的连接问题下,保证系统中的服务实例尽可能保持在线。
  • 缺点:当服务实例确实不可用时,可能导致 Eureka 注册表无法及时更新,影响服务发现的准确性。

工作原理

  • 计算预期心跳续约率:Eureka 根据注册表中当前服务实例的数量计算出预期的心跳续约总数。
    protected void updateRenewsPerMinThreshold() {this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews* (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())* serverConfig.getRenewalPercentThreshold());}# 以上面的实例为例
int(3 (实例数) *60.0 / 30(续期时间)* 0.85) = 5
  • 实际续约率低于预期阈值:如果实际收到的心跳续约数低于预期数的 85%(默认阈值),Eureka 会自动启动自我保护模式,认为可能发生了网络问题或节点不可达的情况。
  • 暂停实例下线:在自我保护模式下,Eureka 暂停对未续约实例的剔除操作,直到心跳率恢复到正常水平。

参考文档

  • Spring 项目构建
  • Spring Cloud 开发手册

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

相关文章:

Spring Cloud Netflix 系列:Eureka 经典实战案例和底层原理解析

文章目录 前言Eureka 简介架构设计工作流程 项目 demo 构建Eureka Server 的搭建Eureka Client 的配置补充说明 运行效果 深入使用Eureka 注册中心添加认证搭建 Eureka 集群实现高可用双节点集群搭建 运行效果补充说明为什么要配置 不同host 原理解析服务注册、心跳续期详细流程…...

ElasticSearch学习篇17_《检索技术核心20讲》最邻近检索-局部敏感哈希、乘积量化PQ思路

目录 场景在搜索引擎和推荐引擎中&#xff0c;对相似文章去重是一个非常重要的环节&#xff0c;另外是拍照识花、摇一摇搜歌等场景都可以使用它快速检索。 基于敏感性哈希的检索更擅长处理字面上的相似而不是语义上的相似。 向量空间模型ANN检索加速思路 局部敏感哈希编码 随…...

2024亚太杯国际赛C题参考文章50页+完整解题思路+数据处理+最终结果

中国宠物食品行业的发展趋势与汇率情景分析&#xff1a;基于多模型的量化预测与决策分析 一 、 摘要 本文针对宠物产业及相关产业的发展分析问题&#xff0c;采用多种数学建模方法和数据 分析技术&#xff0c;构建了一系列预测和评估模型。从宠物数量预测、全球市场分析、产业 …...

推荐几个 VSCode 流程图工具

Visual Studio Code&#xff08;简称VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。 VSCode 发布于 2015 年&#xff0c;而且很快就成为开发者社区中广受欢迎的开发工具。 VSCode 可用于 Windows、macOS 和 Linux 等操作系统。 VSCode 拥有一个庞大的扩展市…...

渗透测试笔记——shodan(4)

声明&#xff1a; 学习视频来自B站up主 【泷羽sec】有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&am…...

一次封装,解放双手:Requests如何实现0入侵请求与响应的智能加解密

引言 之前写了 Requests 自动重试的文章&#xff0c;突然想到&#xff0c;之前还用到过 Requests 自动加解密请求的逻辑&#xff0c;分享一下。之前在做逆向的时候&#xff0c;发现一般医院的小程序请求会这么玩&#xff0c;请求数据可能加密也可能不加密&#xff0c;但是返回…...

c++中操作数据库的常用函数

在C中操作数据库&#xff0c;尤其是MySQL数据库&#xff0c;主要通过MySQL提供的C API或MySQL Connector/C库来实现。这些库提供了一系列的函数&#xff0c;使得开发者能够在C应用程序中执行数据库的连接、查询、更新、删除等操作。以下是C中操作MySQL数据库的一些常用函数&…...

CoAP 协议介绍:特性、应用与优劣势

CoAP 协议简介 CoAP 协议&#xff08;Constrained Application Protocol&#xff09;是一种专门为受限设备设计的互联网应用协议。它旨在让小型、低功耗的设备能够接入物联网&#xff08;IoT&#xff09;。该协议允许这些设备以最小的资源与更广泛的互联网进行通信。 CoAP 协…...

leetcode hot100【LeetCode 53.最大子数组和】java实现

LeetCode 53.最大子数组和 题目描述 给定一个整数数组 nums&#xff0c;找到一个具有最大和的连续子数组&#xff08;至少一个元素&#xff09;&#xff0c;返回其最大和。 子数组是数组中的一个连续部分。 示例 1: 输入: nums [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续…...

MAC C语言 Helloword

在 macOS 系统上编写并运行一个简单的 “Hello, World!” 程序&#xff0c;你可以使用多种编程语言。下面我将以 C 语言为例&#xff0c;展示如何在 macOS 上编写、编译和运行这个经典的 “Hello, World!” 程序。 步骤 1: 安装 Xcode Command Line Tools macOS 系统上通常没…...

【过程控制系统】第6章 串级控制系统

目录 6. l 串级控制系统的概念 6.1.2 串级控制系统的组成 6.l.3 串级控制系统的工作过程 6.2 串级控制系统的分析 6.2.1 增强系统的抗干扰能力 6.2.2 改善对象的动态特性 6.2.3 对负荷变化有一定的自适应能力 6.3 串级控制系统的设计 6.3.1 副回路的选择 2.串级系…...

springboot:责任链模式实现多级校验

责任链模式是将链中的每一个节点看作是一个对象&#xff0c;每个节点处理的请求不同&#xff0c;且内部自动维护一个下一节点对象。 当一个请求从链式的首段发出时&#xff0c;会沿着链的路径依此传递给每一个节点对象&#xff0c;直至有对象处理这个请求为止。 属于行为型模式…...

如何构建高效的接口自动化测试框架?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选…...

spring-logback引用外部文件

背景 在spring微服务开发和云部署中&#xff0c;都涉及到日志的收集&#xff0c;很多时候为例方便管理和开发&#xff0c;很多公司都会开发一些基础配置代码。其中日志就是很重要的部分&#xff0c; 为了方便部署、收集、查看&#xff0c;所以日志文件需要存储在同一个…...

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…...

go项目中比较好的实践方案

工作两年来&#xff0c;我并未遇到太大的挑战&#xff0c;也没有特别值得夸耀的项目。尽管如此&#xff0c;在日常的杂项工作中&#xff0c;我积累了不少心得&#xff0c;许多实践方法也在思考中逐渐得到优化。因此&#xff0c;我在这里记录下这些心得。 转发与封装 这个需求…...

Windows之使用putty软件以ssh的方式连接Linux中文显示乱码

项目场景&#xff1a; 运行环境&#xff1a;Windows10 使用软件&#xff1a;putty 操作说明&#xff1a;以ssh的方式连接Linux 中文显示乱码 问题描述 Windows之使用putty软件以ssh的方式连接Linux中文显示乱码 原因分析&#xff1a; linux 机器的系统语言字符集与putty软件…...

springboot整合hive

springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…...

vxe-form table 修改表单数据校验的主题样式

在使用 vxe-form 表单校验时&#xff0c;数据校验可以支持2种主题样式 官网&#xff1a;https://vxeui.com 普通样式 通过设置 valid-config.theme‘normal’ 设置为普通样式 高亮样式 通过设置 valid-config.theme‘beautify’ 设置为高亮样式 <template><div&…...

【UE5】使用基元数据对材质传参,从而避免新建材质实例

在项目中&#xff0c;经常会遇到这样的需求&#xff1a;多个模型&#xff08;例如 100 个&#xff09;使用相同的材质&#xff0c;但每个模型需要不同的参数设置&#xff0c;比如不同的颜色或随机种子等。 在这种情况下&#xff0c;创建 100 个实例材质不是最佳选择。正确的做…...

一个计算频率的模块

先上代码 module _sync_reg #(parameter INIT 0,parameter ASYNC_RESET 0 ) (input clk,input rst,input in,output out );(* ASYNC_REG "TRUE" *) reg sync1; (* ASYNC_REG "TRUE" *) reg sync2;assign out sync2;generate if (ASYNC_RE…...

在SpringBoot项目中集成MongoDB

文章目录 1. 准备工作2. 在SpringBoot项目中集成MongoDB2.1 引入依赖2.2 编写配置文件2.3 实体类 3. 测试4. 文档操作4.1 插入操作4.1.1 单次插入4.1.2 批量插入 4.2 查询操作4.2.1 根据id查询4.2.2 根据特定条件查询4.2.3 正则查询4.2.4 查询所有文档4.2.5 排序后返回 4.3 删除…...

OpenJudge - 24:输出保留3位小数的浮点数

【题目来源】http://shnoip.openjudge.cn/level1/24/【题目描述】 读入一个单精度浮点数&#xff0c;保留3位小数输出这个浮点数。【输入格式】 只有一行&#xff0c;一个单精度浮点数。【输出格式】 也只有一行&#xff0c;读入的单精度浮点数。【输入样例】 12.34521【输出样…...

华为流程L1-L6业务流程深度细化到可执行

该文档主要介绍了华为业务流程的深度细化及相关内容,包括流程框架、建模方法、流程模块描述、流程图建模等,旨在帮助企业构建有效的流程体系,实现战略目标。具体内容如下: 华为业务流程的深度细化 流程层级:华为业务流程分为 L1 - L6 六个层级,L1 为流程大类,L2 为流程…...

Python中Tushare(金融数据库)入门详解

文章目录 Python中Tushare&#xff08;金融数据库&#xff09;入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…...

Odoo中,要实现实时数据推送,SSE 与 WebSocket 该如何选择

目录 1. 技术特点对比 2. 使用场景 适合使用 SSE 的场景&#xff1a; 适合使用 WebSocket 的场景&#xff1a; 3. 优缺点总结 SSE 优点&#xff1a; SSE 缺点&#xff1a; WebSocket 优点&#xff1a; WebSocket 缺点&#xff1a; 4. 选择建议 选择 SSE 的条件&#x…...

02. Python基础知识

一、注释 在开发程序过程中&#xff0c;如果一段代码的逻辑比较复杂&#xff0c;不是特别容易理解&#xff0c;可以适当添加注释&#xff0c;以辅助自己或其他开发人员解读代码。注释是给程序员看的&#xff0c;为了让程序员方便阅读代码&#xff0c;解释器会忽略注释。在 Pyto…...

Mac 修改默认jdk版本

当前会话生效 这里演示将 Java 17 版本降低到 Java 8 查看已安装的 Java 版本&#xff1a; 在终端&#xff08;Terminal&#xff09;中运行以下命令&#xff0c;查看已安装的 Java 版本列表 /usr/libexec/java_home -V设置默认 Java 版本&#xff1a; 找到 Java 8 的安装路…...

数字赋能,气象引领 | 气象景观数字化服务平台重塑京城旅游生态

在数字化转型的浪潮中&#xff0c;旅游行业正以前所未有的速度重塑自身&#xff0c;人民群众对于高品质、个性化旅游服务需求的日益增长&#xff0c;迎着新时代的挑战与机遇&#xff0c;为开展北京地区特色气象景观预报&#xff0c;打造“生态气象旅游”新业态&#xff0c;助推…...

C语言项⽬实践-贪吃蛇

目录 1.项目要点 2.窗口设置 2.1mode命令 2.2title命令 2.3system函数 2.Win32 API 2.1 COORD 2.2 GetStdHandle 2.3 CONSOLE_CURSOR_INFO 2.4 GetConsoleCursorInfo 2.5 SetConsoleCursorInfo 2.5 SetConsoleCursorPosition 2.7 GetAsyncKeyState 3.贪吃蛇游戏设…...

springboot整合kafka

springboot整合kafka pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven…...

量子计算机全面解析:技术、应用与未来

标题&#xff1a;量子计算机全面解析&#xff1a;技术、应用与未来 一、什么是量子计算机&#xff1f; 量子计算机是一种利用量子力学原理&#xff08;如叠加、纠缠和干涉&#xff09;进行计算的新型计算设备。与传统计算机基于比特&#xff08;0 和 1&#xff09;的运算方式不…...

提升软件测试报告的质量:Allure2中添加用例失败截图、日志、HTML块和视频的方法

Allure2的用途 Allure2是一个用于生成测试报告的框架&#xff0c;广泛应用于自动化测试和手动测试中。它支持多种测试框架&#xff0c;如JUnit、TestNG、MSTest等&#xff0c;通过生动的图表和详细的日志&#xff0c;使得非技术人员也能轻松地理解测试结果。许多团队选用Allur…...

Mysql启动报错:本地计算机上的mysql服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止

原因 是手动去改了mysql的配置文件my.ini的内容&#xff0c;重新启动服务启动不了。 看了很多文章最终找到了恢复数据的办法。 第一步备份 先备份mysql数据存的文件夹Data&#xff0c;如果找不到则去看配置文件那一行datadir 第二步重新安装mysql 卸载篇可以看我之前发的文…...

国际环境和背景下的云计算领域

前言 在当前国际环境和背景下&#xff0c;云计算领域呈现出复杂多变的局面&#xff0c;其发展深受技术创新、地缘政治、全球经济以及监管政策的影响。以下从技术趋势、市场竞争、地缘政治和监管环境四个方面详细解析云计算领域的现状。 一、技术趋势&#xff1a;多云与边缘计算…...

网络安全-企业环境渗透2-wordpress任意文件读FFmpeg任意文件读

一、 实验名称 企业环境渗透2 二、 实验目的 【实验描述】 操作机的操作系统是kali 进入系统后默认是命令行界面 输入startx命令即可打开图形界面。 所有需要用到的信息和工具都放在了/home/Hack 目录下。 本实验的任务是通过外网的两个主机通过代理渗透到内网的两个主机。…...

C# 超链接控件LinkLabel无法触发Alt快捷键

在C#中&#xff0c;为控件添加快捷键的方式有两种&#xff0c;其中一种就是Windows中较为常见的Alt快捷键&#xff0c;比如运行对话框&#xff0c;记事本菜单等。只需要按下 Alt 框号中带下划线的字母即可触发该控件的点击操作。如图所示 在C#开发中&#xff0c;实现类似的操作…...

一分钟学习数据安全——数据安全风险的系统化应对思路

数据是组织的重要资产&#xff0c;未经授权的数据访问可能导致数据泄露、数据篡改、隐私侵犯和合规风险等问题。企业可以通过数据访问控制来提高信息系统在数据全生命周期管理中的安全性。企业可以引入IAM系统&#xff0c;来控制身份来管理权限。通过对用户访问权限的管理和合适…...

深入了解 Spring Security 的授权核心功能

Spring Security 是一个强大且灵活的安全框架&#xff0c;能够帮助开发者为 Spring 应用程序提供认证和授权服务。在实际应用中&#xff0c;Spring Security 主要涉及用户的认证&#xff08;谁是用户&#xff09;和授权&#xff08;用户能做什么&#xff09;。本文将深入讲解 S…...

【Web前端】创建我的第一个 Web 表单

Web 开发中&#xff0c;表单是不可或缺的组成部分。无论是用户注册、登录还是反馈收集&#xff0c;表单都是与用户交互的重要方式。 什么是 Web 表单&#xff1f; Web 表单是一种用于收集用户输入数据的界面元素。它们允许用户在浏览器中输入信息并提交这些信息到服务器。Web …...

“人工智能+高职”:VR虚拟仿真实训室的发展前景

在当今科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;与虚拟现实&#xff08;VR&#xff09;技术的融合正逐步改变着各行各业&#xff0c;教育领域也不例外。特别是在高等职业教育&#xff08;简称“高职”&#xff09;体系中&#xff0c;VR虚拟仿真实训室…...

状态模式之状态机

状态机的背景 在软件开发过程中&#xff0c;尤其是涉及到复杂的系统行为控制时&#xff0c;我们常常会遇到这样的情况&#xff1a;一个对象或者系统会在多种状态之间进行转换&#xff0c;并且在不同状态下对相同事件的响应是不同的。 以自动售卖机为例&#xff0c;自动售卖机…...

NUXT3学习日记四(路由中间件、导航守卫)

前言 在 Nuxt 3 中&#xff0c;中间件&#xff08;Middleware&#xff09;是用于在页面渲染之前或导航发生之前执行的函数。它们允许你在路由切换时执行逻辑&#xff0c;像是身份验证、重定向、权限控制、数据预加载等任务。中间件可以被全局使用&#xff0c;也可以只在特定页…...

基于重复控制补偿的高精度 PID 控制

1. 背景与原理 重复控制&#xff08;Repetitive Control, RC&#xff09;是一种适用于周期性信号跟踪和周期性扰动抑制的控制方法&#xff0c;通过在控制回路中引入周期补偿器来提高系统的控制精度。将 RC 与 PID 控制相结合&#xff0c;利用 PID 的快速响应特性和 RC 的周期补…...

Linux之日志

日志 在编写网络服务器, 各种软件时, 程序一定要打印一些日志信息. 1. 可以向显示器打印, 也可以向文件中写入. 2. 日志是软件在运行时记录的流水账, 用于排查服务进程挂掉的信息. 其中必须要有的是: 日志等级, 时间, 日志内容.可选的是文件名, 代码行数, 进程pid 等 日志…...

【LeetCode面试150】——202快乐数

博客昵称&#xff1a;沈小农学编程 作者简介&#xff1a;一名在读硕士&#xff0c;定期更新相关算法面试题&#xff0c;欢迎关注小弟&#xff01; PS&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟沈小农&#xff0c;希望我的文章能帮助到你。欢迎大家在…...

云原生之k8s服务管理

文章目录 服务管理Service服务原理ClusterIP服务 对外发布应用服务类型NodePort服务Ingress安装配置Ingress规则 Dashboard概述 认证和授权ServiceAccount用户概述创建ServiceAccount 权限管理角色与授权 服务管理 Service 服务原理 容器化带来的问题 自动调度&#xff1a;…...

【Vue】 npm install amap-js-api-loader指南

前言 项目中的地图模块突然打不开了 正文 版本太低了&#xff0c;而且Vue项目就应该正经走项目流程啊喂&#xff01; npm i amap/amap-jsapi-loader --save 官方说这样执行完&#xff0c;就这结束啦&#xff01;它结束了&#xff0c;我还没有&#xff0c;不然不可能记录这篇文…...

RocketMQ: 部署结构与存储特点

RocketMQ 是什么 它是一个队列模型的消息中间件&#xff0c;具有高性能、高可靠、高实时、分布式特点 Producer、Consumer、队列都可以分布式Producer 向一些队列轮流发送消息 队列集合称为 TopicConsumer 如果做广播消费则一个 consumer 实例消费这个 Topic 对应的所有队列如果…...

Android OpenGL ES详解——绘制圆角矩形

1、绘制矩形 代码如下&#xff1a; renderer类&#xff1a; package com.example.roundrectimport android.content.Context import android.opengl.GLES30 import android.opengl.GLSurfaceView.Renderer import com.opengllib.data.VertexArray import com.opengllib.prog…...