Yang's blog Yang's blog
首页
后端开发
密码学
机器学习
命令手册
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

xiaoyang

尽人事,听天命
首页
后端开发
密码学
机器学习
命令手册
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • SpringCloud

    • 微服务架构介绍
    • SpringCloud介绍
    • Spring Cloud:生产者与消费者
    • Spring Cloud Eureka:构建可靠的服务注册与发现
      • 1. Eureka 两大组件
      • 2. Eureka的服务注册与发现
      • 3. 代码示例
        • 3.1 搭建服务注册中心
        • 3.2 注册服务
        • 3.3 修改调用调用服务方式
        • 3.3.1 配置 RestTemplate
        • 3.3.2 修改消费者的服务调用方式
        • 3.4 构建Eureka集群:实现负载均衡与故障容错
      • 4. 总结
    • Spring Cloud Ribbon:负载均衡
    • Spring Cloud Fegin:服务调用
    • Spring Cloud Hystrix:熔断器
    • Spring Cloud Zuul:统一网关路由
    • Spring Cloud Config:配置中心
  • Java后端框架

    • LangChain4j

      • 介绍
      • 快速开始
      • Chat and Language Models
      • Chat Memory
      • Model Parameters
      • Response Streaming
      • AI Services
      • Agent
      • Tools (Function Calling)
      • RAG
      • Structured Outputs
      • Classification
      • Embedding (Vector) Stores
      • Image Models
      • Quarkus Integration
      • Spring Boot Integration
      • Kotlin Support
      • Logging
      • Observability
      • Testing and Evaluation
      • Model Context Protocol
    • SpringBoot

      • SpringBoot-核心介绍
  • 八股文

    • 操作系统
    • JVM介绍
    • Java多线程
    • Java集合框架
    • Java反射
    • JavaIO
    • Mybatis介绍
    • Spring介绍
    • SpringBoot介绍
    • Mysql
    • Redis
    • 数据结构
    • 云计算
    • 设计模式
    • 计算机网络
    • 锁核心类AQS
    • Nginx
    • 面试场景题
  • 前端技术

    • 初识Vue3
    • Vue3数据双向绑定
    • Vue3生命周期
    • Vue-Router 组件
    • Pinia 集中式状态存储
  • 中间件

    • RocketMQ
  • 源码分析

    • 线程池源码解析
    • Redisson源码分析
  • 开发知识

    • 请求参数注解
    • 时间复杂度和空间复杂度
    • JSON序列化与反序列化
    • Timestamp vs Datetime
    • Java开发中必备能力单元测试
    • 正向代理和反向代理
    • 什么是VPN
    • 后端服务端主动推送消息的常见方式
    • 正则表达式
    • SseEmitter vs Flux 的本质区别与底层原理解析
    • Function Calling与MCP区别
    • 分布式事务
  • 后端开发
  • SpringCloud
xiaoyang
2024-05-17
目录

Spring Cloud Eureka:构建可靠的服务注册与发现

# 3.Spring Cloud Eureka:构建可靠的服务注册与发现

Eureka一词源自古希腊词汇,表示"发现了"。在软件领域,Eureka是由Netflix开发的一款开源的服务注册与发现组件。Spring Cloud将Eureka与Netflix中的其他开源服务组件整合进Spring Cloud Netflix模块中,形成了Spring Cloud Netflix Eureka,用于实现Spring Cloud的服务注册与发现功能。

# 1. Eureka 两大组件

Eureka采用了Client/Server(客户端/服务器)架构,包括两个主要组件:Eureka Server和Eureka Client。

  • Eureka Server:作为服务注册中心,用于提供服务注册功能。当微服务启动时,会将自己的服务注册到Eureka Server。Eureka Server维护了一个可用服务列表,包含了所有已注册到Eureka Server的可用服务的信息。
  • Eureka Client:表示微服务系统中的各个微服务,用于与Eureka Server进行交互。微服务启动后,Eureka Client会定期向Eureka Server发送心跳,以表明自己的存活状态。如果Eureka Server在多个心跳周期内没有收到某个Eureka Client的心跳,将把该服务从可用服务列表中移除。

# 2. Eureka的服务注册与发现

Eureka实现了服务注册与发现的功能,具体流程如下图所示:

图1:Eureka服务注册与发现原理图

  • 服务注册中心(Register Service):作为Eureka Server,用于提供服务注册和发现功能。
  • 服务提供者(Provider Service):作为Eureka Client,用于提供服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现。
  • 服务消费者(Consumer Service):也是Eureka Client,用于消费服务。它可以从服务注册中心获取服务列表,并调用所需的服务。
  1. Eureka的作用
    Eureka在微服务架构中扮演着重要角色,具有以下功能:

    • 服务注册:服务提供者将自己的服务注册到Eureka Server,从而使服务消费者能够发现和调用该服务。
    • 服务发现:服务消费者从Eureka Server获取可用服务列表,以便选择合适的服务进行调用。
    • 服务健康检查:Eureka Client定期向Eureka Server发送心跳,用于确认自身的健康状态。如果Eureka Server连续多个心跳周期未收到某个服务的心跳,将剔除该服务实例。
    • 高可用性:通过互相注册,多个Eureka Server实例可以实现高可用性。当某个Eureka Server不可用时,其他可用的服务器可以接管其职责。

# 3. 代码示例

下面,我们通过一个案例来展示下为什么使用 Eureka ?以及Eureka是如何实现服务注册与发现的。

# 3.1 搭建服务注册中心

在主工程下创建一个名为 cloud-eureka-7001 的 Spring Boot Module 作为服务注册中心,可以直接选择eureka-server依赖快速构建,或者并在其 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.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-eureka-7001</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-eureka-7001</name>
    <description>cloud-eureka-7001</description>
    <parent>
        <groupId>cn.ywenrou</groupId>
        <artifactId>spring-cloud-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

然后在resource目录下创建application.yml,配置如下:

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
      #设置与eureka  server交互的地址和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/  #单机就是指向自己
1
2
3
4
5
6
7
8
9
10
11

最后在启动类上加上@EnableEurekaServer注解并启动:

package cn.ywenrou.cloudeureka7001;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class CloudEureka7001Application {

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

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

访问http://localhost:7001/ (opens new window),请注意此时注册服务为空:

# 3.2 注册服务

在上一章中我们引出了存在的问题,当消费者需要调用生产者的API时,硬编码主机名和端口号是一种不灵活的做法。为了解决这个问题,Spring Cloud提供了Eureka作为服务注册中心,以便消费者能够动态地发现和调用生产者的服务。所以我们现在需要将上一张的单体服务中修改下配置。

首先模块cloud-service1和cloud-service2在pom.xml文件中引入下面依赖:

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

然后在application.yml新增eureka配置:

server:
  port: xxx
#spring 配置
spring:
  application:
    name: cloud-servicex
#eureka配置
eureka:
  client:
    #表示是否将自己注册进eureka  默认为true
    register-with-eureka: true
    #是否从EurekaServer中抓取已有的注册信息,默认为true,单点无所谓,集群必须设置true才能和ribbon使用负载均衡
    fetch-registry: true
    service-url:
      #单机配置
      defaultZone: http://localhost:7001/eureka
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

最后在启动类上加入@EnableEurekaClient注解并启动项目,访问http://localhost:7001/ (opens new window),可以看到2个服务实例注册进来:

# 3.3 修改调用调用服务方式

我们首先展示如何在不使用负载均衡的情况下,通过服务名进行服务调用。为此,我们需要在 config 包下创建一个配置类,以便将 RestTemplate 注入为 Spring 容器中的一个 bean。

# 3.3.1 配置 RestTemplate

package cn.ywenrou.cloudservice2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
    
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.3.2 修改消费者的服务调用方式

在消费者服务中,通过 DiscoveryClient 获取服务实例列表,并选择第一个实例进行调用。在这里你会发现,虽然我们不再使用传统的硬编码主机名和端口号的方式,而是采用动态方式进行调用,但这个过程依然比较复杂。我们选择第一个实例进行调用是为了演示方便,但在实际项目中,一个服务通常会部署多个实例以提高系统的可靠性和可用性。仅使用第一个实例进行调用是简化后的示例,在真实场景中应使用更高级的负载均衡策略来分配请求。

package cn.ywenrou.cloudservice2.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
class ConsumerController {

    @Autowired
    private DiscoveryClient discoveryClient;
    
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value="/service2/hello")
    public String helloController() {
        // 获取服务实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances("cloud-service1");
        if (instances == null || instances.isEmpty()) {
            throw new RuntimeException("No instances found for service: cloud-service1");
        }

        // 选择第一个实例进行调用
        ServiceInstance instance = instances.get(0);
        System.out.println("服务地址:" + instance.getUri());

        String url = instance.getUri().toString() + "/service1/hello";

        // 使用RestTemplate进行调用
        return restTemplate.getForObject(url, String.class);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 3.4 构建Eureka集群:实现负载均衡与故障容错

在微服务架构中,高可用性是至关重要的。如果我们只搭建了Eureka的单机版,一旦该节点宕机,整个服务将无法使用。为了解决这个问题,我们需要搭建Eureka的集群版,通过实现负载均衡与故障容错来确保微服务的可靠性和稳定性。其实在微服务中每个单体都是可以作为消费者和生成者,实际上就是启动多个 Eureka 实例,多个 Eureka 实例之间,互相注册,互相同步数据,共同组成一个 Eureka 集群。

例如我们要搭建三个Eureka组成集群,我们只需要再创建cloud-eureka-7002 和cloud-eureka-7003步骤和之前一样,选择依赖可以快速构建:

首先修改电脑的host文件的主机映射:

修改这三个Eureka单体的application.yml,这里以cloud-eureka-7002为例:

server:
  port: 7002
spring:
  application:
    name: eureka-server # eureka服务集群的name要相同
eureka:
  client:
    register-with-eureka: true # 将eureka服务器注册为服务
    fetch-registry: true # 获取注册信息
    service-url:
      defaultZone: 'http://eureka7001.com:7001/eureka,http://eureka7003.com:7003/eureka' # 将注册服务器地址写成另外两个集群的地址,此处用eureka7001.com和eureka7003.com代理localhost或127.0.0.1
  instance:
    hostname: eureka7002.com # 注意hostname不能为空
1
2
3
4
5
6
7
8
9
10
11
12
13

然后全部启动服务,这里以打开端口为7002的eureka服务为例http://localhost:7002/,可以看到集群已经搭建成功。

# 4. 总结

Spring Cloud Eureka是Netflix开源的服务注册与发现组件,通过Eureka Server和Eureka Client的配合,可以实现微服务架构中的服务注册与发现功能。Eureka的存在简化了服务管理和调用过程,提供了可靠的服务注册与发现机制。在前面我们提到,一个服务通常会部署多个实例以提高系统的可靠性和可用性。传统方式调用一个服务需要先获取服务实例列表,再选择一个实例进行调用,这个过程既繁琐又复杂,尤其是在选择合适的实例时。为了简化这一过程,引出Ribbon。

编辑 (opens new window)
上次更新: 2025/10/28, 02:15:03

← Spring Cloud:生产者与消费者 Spring Cloud Ribbon:负载均衡→

最近更新
01
SpringBoot-核心介绍
11-13
02
Redisson源码分析
11-13
03
线程池源码解析
10-31
更多文章>
Theme by Vdoing | Copyright © 2023-2025 xiaoyang | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式