【SpringCloud】服务注册/服务发现

devtools/2025/3/20 9:04:07/

在这里插入图片描述

文章目录

  • 前言
  • 什么是注册中心
  • CAP理论
  • Eureka

前言

在生活中,我们不可避免地与各种医院、学校、政府等机构打交道,那么要想与这些机构取得联系,就需要知道这些机构的电话号码,但是这些机构的电话号码也可能是会变化的,那么当这些机构更换了电话号码之后,不可能让机构一个一个的通知用户说电话号码更换了,那么让个人自己去问更换之后的电话号码又是比较麻烦的,这样机构每换一次电话号码,我们就需要重新知道更换后的电话号码。

那么是否有方法可以解决这个问题呢?当然是有的,我们都知道有114这个查号平台,当机构注册或者更换手机号的时候,都需要把自己的电话号上报给114平台,那么当用户需要知道某个机构的电话号码的时候,就可以直接去114平台询问,那么这样就极大的方便了个人和机构。

在这里插入图片描述
那么类似的,在我们的微服务中,当服务方更换机器或者其他原因导致的IP地址更换的时候,我们的使用方要想使用这个服务,就不得不更换调用接口的IP,那么这样的话,每次服务方的IP更换之后就需要更改业务代码,这样就很麻烦,所以在微服务开发中,也可以采用类似的方案。

服务启动/变更时,向注册中心报道,注册中心记录应用和IP的关系。
调用方调用时,先去注册中心获取服务方的IP,再去服务方进行调用。

什么是注册中心

在最初的架构体系中,集群的概念还不那么流行,且机器数量也比较少,此时直接使用DNS+Nginx就可以满足几乎所有服务的发现。相关的注册信息直接配置在Nginx。但是随着微服务的流行与流量的激增,机器规模逐渐变大,并且机器会有频繁的上下线行为,这种时候需要运维手动地去维护这个配置信息是一个很麻烦的操作。所以开发者们开始希望有这么一个东西,它能维护一个服务列表,哪个机器上线了,哪个机器宕机了,这些信息都会自动更新到服务列表上,客户端拿到这个列表,直接进行服务调用即可。这个就是注册中心。

注册中心主要有三个角色:

  • 服务提供者(Server):一次业务中,被其他微服务调用的服务,也就是提供接口给其他微服务
  • 服务消费者(Client):一次业务中,调用其他微服务的服务,也就是调用其他微服务提供的接口
  • 服务注册中心(Registry):用于保存Server的注册信息,当Server节点发生变更的时候,Registry会同步变更,服务与注册中心使用一定机制通信,如果注册中心与某个服务长时间无法通信,就会注销该实例

服务注册:服务提供者在启动时,向Registry注册自身服务,并向Registry定期发送心跳汇报存活状态
服务发现:服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口,服务发现的一个重要作用就是提供给服务消费者一个可用的服务列表。

CAP理论

谈到注册中心就不可避免的提到CAP理论,CAP理论是分布式系统中最基础,也是最关键的理论。

CAP理论(也称为 布鲁尔定理)是分布式系统领域的一个重要理论,用于描述在分布式环境中对系统特性的一种权衡。它指出:

在分布式系统中,无法同时完全满足以下三种特性,只能在其中选择两个进行优化:

CAP的三种特性

  1. 一致性(Consistency, C)
    所有节点对同一份数据的访问结果是相同的,即所有用户无论在哪个节点查询,看到的数据都是最新的。
  • 类似于关系型数据库中的“强一致性”。
  • 示例:写入一条数据后,所有节点都立刻能读到这条数据。
  1. 可用性(Availability, A)
    系统在任何时候都能响应用户的请求(无论请求成功与否)。
  • 即使部分节点故障,系统仍然能够提供服务。
  • 示例:分布式系统某个节点宕机,但其他节点仍然可以处理请求。
  1. 分区容忍性(Partition Tolerance, P)
    系统能够容忍网络分区,即使节点之间的通信中断,系统仍然可以继续运行。
  • 在分布式系统中,网络分区是一种不可避免的现象(如网络故障、延迟等)。
  • 示例:即使数据中心之间的连接断开,两个数据中心的服务仍然可用。

CAP理论的核心在于:分布式系统中不可能同时完全满足 C、A 和 P,只能在其中选择两种特性进行优化。

由于 P(分区容忍性) 是分布式系统的基本要求,因此在实际系统设计中,往往需要在 一致性(C) 和 可用性(A) 之间做权衡。

在这里插入图片描述
所以根据CAP理论的取舍就出现了三种架构:

  1. CP系统(一致性 + 分区容忍性)
  • 强调一致性,即便牺牲部分可用性(例如,某些请求可能会被拒绝)。
  • 特点:当网络分区发生时,系统优先保证数据一致性,可能暂停服务。
  1. AP系统(可用性 + 分区容忍性)
  • 强调系统的可用性,即便牺牲部分一致性(例如,可能存在短时间的数据不一致)。
  • 特点:当网络分区发生时,系统优先保证服务可用,但可能返回旧数据或不同节点数据不一致。
  1. CA系统(一致性 + 可用性)
  • 强调一致性和可用性,但无法容忍网络分区。
  • 特点:仅适用于不涉及分布式的系统(例如单点部署)。

因为 P 特性是无法避免的,所以对于分布式微服务来说,就只有两种架构AP和CP架构。

那么常见的注册中心有哪些,以及这些注册中心是AP还是CP系统呢?

1. Eureka

  • 开发者:Netflix 开源,Spring Cloud 提供支持。
  • 特点
    • 轻量级:专注于服务注册和发现。
    • 高可用性:基于 AP(可用性和分区容忍性)的设计,追求高可用性,允许短暂的不一致性。
    • 自我保护机制:当注册中心检测到服务实例较少时,不会立即将其标记为不可用(防止网络抖动影响)。
    • 维护状态:目前处于维护模式,推荐用 Spring Cloud Alibaba 的 Nacos 替代。
  • 应用场景
    • 使用 Spring Cloud Netflix 生态的系统。

2. Consul

  • 开发者:HashiCorp。
  • 特点
    • 多功能:同时支持服务注册、配置管理和健康检查。
    • 强一致性:基于 Raft 共识算法,确保数据一致性(CP)。
    • 跨数据中心支持:适合复杂分布式环境。
    • Key-Value 存储:支持简单的配置管理。
    • 提供 UI 界面方便查看服务状态。
  • 应用场景
    • 需要配置管理和服务注册一体化的场景。
    • 对一致性要求较高的分布式系统。

3. Zookeeper

  • 开发者:Apache。
  • 特点
    • 强一致性:基于 ZAB 协议(类似 Paxos),提供 CP 保证。
    • 分布式协调服务:除了服务注册,还支持分布式锁、配置管理等功能。
    • 高性能:适合读多写少的场景。
    • 复杂性:安装配置较为复杂,需要手动管理健康检查等功能。
  • 应用场景
    • 需要强一致性的系统,例如分布式数据库或分布式锁。
    • 早期 Hadoop、Kafka 等生态系统的配套工具。

4. Nacos

  • 开发者:阿里巴巴。
  • 特点
    • 多功能整合:同时支持服务注册、服务发现和配置管理。
    • 支持多协议:支持 RESTful、DNS 等多种服务发现协议。
    • 灵活性:支持 AP 和 CP 模式切换。
    • 动态配置:原生支持配置管理(类似于 Spring Cloud Config)。
    • 生态适配性强:兼容 Spring Cloud Alibaba 和 Dubbo。
  • 应用场景
    • 微服务架构下的多场景需求。
    • 需要动态配置管理的系统。

5. Kubernetes Service Discovery

  • 开发者:Kubernetes 社区。
  • 特点
    • 内置服务发现:通过 DNS 或环境变量实现服务注册和发现。
    • 自动化:服务启动时,自动注册到 Kubernetes 的 etcd 中。
    • 整合网络:通过 Kubernetes 的 Service 和 Ingress 提供统一的流量管理。
    • 依赖平台:适合云原生应用,不适合非 Kubernetes 环境。
  • 应用场景
    • 云原生微服务架构。
    • 使用 Kubernetes 作为容器编排工具的系统。

6. Etcd

  • 开发者:CoreOS。
  • 特点
    • 强一致性:基于 Raft 算法,保证数据一致性。
    • 简单高效:以 Key-Value 存储为核心,专注于分布式系统协调。
    • 性能强:低延迟、高吞吐。
    • 生态支持:Kubernetes 内置使用 etcd 作为元数据存储。
  • 应用场景
    • 需要高性能和强一致性的分布式系统。
    • Kubernetes 等系统的元数据存储。

7. Redis(非专业注册中心)

  • 开发者:Redis 社区。
  • 特点
    • 轻量级:利用 Redis 的 Key-Value 存储实现简单的服务注册和发现。
    • 非正式:缺乏专门的服务健康检查机制。
    • 高性能:适合轻量级分布式服务。
  • 应用场景
    • 不需要复杂健康检查的轻量级场景。
注册中心一致性可用性配置管理健康检查应用场景
Eureka弱一致性高可用客户端实现Spring Cloud 生态轻量场景
Consul强一致性高可用内置多功能需求,跨数据中心
Zookeeper强一致性中等手动实现高一致性要求,如分布式锁、任务调度
Nacos可切换高可用内置微服务和动态配置场景
K8s Service Discovery强一致性高可用自动化云原生环境
Etcd强一致性高可用高性能分布式协调服务

在很多情况,给用户提供一个错误的数据也胜过无法提供实例信息造成请求失败更好,所以我们主要学习 AP 架构,其中 Eureka 就是典型的 AP 系统,然后 Nacos 可以实现 AP 和 CP 之间的切换。

Eureka

Eureka 是 Netflix 开源的一款服务注册与发现组件,也是 Spring Cloud Netflix 生态的重要组成部分。它实现了分布式系统中的服务注册与发现功能,适用于微服务架构,具有轻量、灵活的特点。虽然 Eureka 2.0 已经停止维护,新的微服务架构设计中,也不再建议使用,但是目前依然有大量的公司的微服务系统使用 Eureka 作为注册中心。

Eureka 官方文档 https://github.com/Netflix/eureka/wiki

Eureka 采用了典型的客户端-服务端架构:

  • Eureka Server:作为注册中心Server端,向微服务应用程序提供服务注册,发现和健康检查等能力
  • Eureka Client:服务提供者,服务启动时,会想 Eureka Server 注册自己的信息,Eureka Server 会存储这些信息

那么接下来我们学习一下 Eureka 的使用:

搭建Eureka Server

我们在 eureka server 项目中添加 eureka server 依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

然后在启动类上加上 @EnableEurekaServer 注解,开启 eureka 注册中心服务:

java">import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class,args);}
}

然后在配置文件中进行 eureka server 的配置:

server:port: 10010 # 为eureka server配置端口号
spring:application:name: eureka-server # 为该项目设置名称
eureka:instance:hostname: localhostclient:fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为falseregister-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.service-url:# 设置Eureka Server的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

然后我们启动项目,通过 http://127.0.0.1:10010/ 来看看 eureka server 是否启动成功:

在这里插入图片描述

服务注册

我们下订单的时候,订单服务会调用商品服务,所以将商品服务进行服务注册,在 product-service 项目中添加 eureka client依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

完善配置文件:

server:port: 9090
spring:application:name: product-servicedatasource:url: jdbc:mysql://127.0.0.1:3306/cloud_product?characterEncoding=utf8&useSSL=falseusername: rootpassword: ********driver-class-name: com.mysql.cj.jdbc.Driver
# 设置 Mybatis 的 xml 保存路径
mybatis:configuration: # 配置打印 MyBatis 执行的 SQL#    log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true  #自动驼峰转换
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/ #eureka server中配置的 defaultZone
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

启动服务,然后刷新注册中心:

在这里插入图片描述
可以看到product-service已经注册到eureka上了。

服务发现

当服务注册到服务中心之后,我们就可以实现服务发现了:

服务注册和服务发现都封装在eureka-client依赖中,在 order-service 中添加 eureka-client 依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

完善配置文件:

server:port: 8080
spring:application:name: order-servicedatasource:url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=falseusername: rootpassword: lmh041105666driver-class-name: com.mysql.cj.jdbc.Driver
# 设置 Mybatis 的 xml 保存路径
mybatis:configuration: # 配置打印 MyBatis 执行的 SQL#    log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true  #自动驼峰转换
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/ # 这里同样是注册中心中配置的defaultZone
logging:pattern:console: '%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

远程调用;

java">import org.example.mapper.OrderMapper;
import org.example.model.OrderInfo;
import org.example.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import java.util.List;@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;public OrderInfo selectOrderById(Integer id) {OrderInfo orderInfo = orderMapper.selectOrderById(id);//String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();//根据应用名称获取服务列表List<ServiceInstance> instances = discoveryClient.getInstances("product-service");//服务可能有多个,获取第一个EurekaServiceInstance instance = (EurekaServiceInstance) instances.get(0);//拼接urlString url = instance.getUri() + "/product/" + orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
}

启动order-service服务,然后刷新注册中心:

在这里插入图片描述

这个中间的警告我们先不管,可以看到通过上面的操作,我们的服务注册和服务发现都可以正常实现。

然后我们待用订单服务,看看订单服务是否能够正常调用商品服务:

在这里插入图片描述


http://www.ppmy.cn/devtools/168582.html

相关文章

掌握些许 IPv6 要点,windows 远程桌面安全便利两相宜!

掌握这些要点&#xff0c;Windows 远程桌面安全便利两相宜&#xff01; 在日常办公中&#xff0c;许多人会用到 Windows 系统的远程桌面功能。但在实际使用时&#xff0c;会遇到内网计算机难以通过运营商的动态 ip 与多层 NAT 向互联网暴露端口的技术问题&#xff0c;和计算机…

Oracle ASM Failgroup故障组

Oracle ASM Failgroup故障组 1. 故障组的核心作用2. 故障组的配置规则3. 故障组的设计最佳实践4. 故障组的实际示例场景1&#xff1a;普通冗余&#xff08;2个故障组&#xff09;场景2&#xff1a;高冗余&#xff08;3个故障组&#xff0c;跨数据中心&#xff09; 关键注意事项…

pfsense部署三(snort各版块使用)

在上篇文章上我们已经进行了snort的基础配置了&#xff0c;接下来需要进行snort的具体配置&#xff0c;其中包括各板块的设置&#xff0c;例&#xff1a;白名单&#xff0c;警报&#xff0c;规则设置等 规则库配置 点击 service > snort > Global Settings ,在code值…

python函数的多种参数使用形式

目录 1. 位置参数&#xff08;Positional Arguments&#xff09; 2. 关键字参数&#xff08;Keyword Arguments&#xff09; 3. 默认参数&#xff08;Default Arguments&#xff09; 4. 可变参数&#xff08;Variable Positional Arguments&#xff09; 5. 关键字可变参数&…

openpnp - 如果安装面的钣金接触面不平,可以尝试加垫片

文章目录 openpnp - 如果安装面的钣金接触面不平&#xff0c;可以尝试加垫片概述吐槽备注END openpnp - 如果安装面的钣金接触面不平&#xff0c;可以尝试加垫片 概述 在X轴导轨上&#xff0c;架上百分表&#xff0c;打设备的工作平面的平面度&#xff0c;发现工作平面不平(和…

蓝桥杯刷题——第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

一、0握手问题 - 蓝桥云课 算法代码&#xff1a; #include <iostream> using namespace std; int main() {int sum0;for(int i49;i>7;i--)sumi;cout<<sum<<endl;return 0; } 直接暴力&#xff0c;题意很清晰&#xff0c;累加即可。 二、0小球反弹 - 蓝…

Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(五)

翻转队列日志 DDI 添加了以下与翻转队列日志相关的回调和相关结构&#xff1a; DXGKDDI_SETFLIPQUEUELOGBUFFERDXGKARG_SETFLIPQUEUELOGBUFFERDXGK_FLIPQUEUE_LOG_ENTRYDXGKDDI_UPDATEFLIPQUEUELOGDXGKARG_UPDATEFLIPQUEUELOG KMD 提供了一个指向其在 DRIVER_INITIALIZATION…

分布式事务解决方案:Seata原理详解与实战教程

一、为什么需要Seata&#xff1f; 在微服务架构中&#xff0c;跨服务的事务管理成为核心痛点&#xff1a; 传统事务失效&#xff1a;服务拆分导致无法使用本地事务数据不一致风险&#xff1a;网络抖动、服务宕机等情况导致数据错乱复杂场景处理难&#xff1a;涉及多个数据库、…