Spring Cloud Eureka 服务注册与发现

[复制链接]
发表于 2024-11-14 11:07:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×


一、Eureka基础知识概述

1.Eureka两个焦点组件



  • Eureka Server :服务注册中心,重要用于提供服务注册功能。
    当微服务启动时,会将自己的服务注册 到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务的信息,这些可用服务可以在 Eureka Server 的管理界面中直观看到
  • Eureka Client :客户端,通常指的是微服务体系中各个微服务,重要用于和 Eureka Server 进行交互。
    在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)
   Eureka的心跳机制重要用于确保客户端(服务提供者)与服务器(服务注册中心)之间的毗连活性。客户端启动后,会定期向服务器发送心跳数据,以告知服务器自己仍然处于活动状态
  
2.Eureka 服务注册与发现




  • 服务注册中心(Register Service): 它是一个 Eureka Server,用于提供服务注册和发现功能。
  • 服务提供者(Provider Service): 它是一个 Eureka Client,用于提供服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现。
  • 服务消费者(Consumer Service): 它是一个 Eureka Client,用于消费服务。它可以从服务注册中心获取服务列表,调用所需的服务。
Eureka 实现服务注册与发现的流程

  • 搭建一个Eureka Server作为服务注册中心
  • 服务提供者Eureka Client启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心
  • 服务消费者Eureka Client启动时,也会向服务注册中心注册
  • 服务消费者还会获取一份可用路由服务列表,该列表中包含了所有注册到服务注册中心的服务信息(包罗服务提供者和自身的信息)
  • 在获得了可用服务列表后,服务消费者通过 HTTP 或消息中心件远程调用服务提供者提供的服务。
  • 服务注册中心(Eureka Server)所饰演的角色十分重要,它是服务提供者和服务消费者之间的桥梁。服务提供者只有将自己的服务注册到服务注册中心才大概被服务消费者调用,而服务消费者也只有通过服务注册中心获取可用服务列表后,才华调用所需的服务。

二、Eureka单机搭建

1.构建父模块和三个子模块 分别为注册中心 eureka-service 仓储模块stock-service 订单模块 order-service


2.父模块pom.xml文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>org.example</groupId>
  7.     <artifactId>cloud-02-Eureka-parent</artifactId>
  8.     <packaging>pom</packaging>
  9.     <version>1.0-SNAPSHOT</version>
  10.     <modules>
  11.         <module>cloud-eureka-service</module>
  12.         <module>cloud-stock-service</module>
  13.         <module>cloud-order-service</module>
  14.     </modules>
  15.     <!-- 统一管理jar包版本 -->
  16.     <properties>
  17.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18.         <maven.compiler.source>1.8</maven.compiler.source>
  19.         <maven.compiler.target>1.8</maven.compiler.target>
  20.         <junit.version>4.12</junit.version>
  21.         <log4j.version>1.2.17</log4j.version>
  22.         <lombok.version>1.18.22</lombok.version>
  23.         <mysql.version>8.0.24</mysql.version>
  24.         <druid.version>1.2.8</druid.version>
  25.         <mybatis-plus.version>3.0.7.1</mybatis-plus.version>
  26.     </properties>
  27.     <dependencies>
  28.         <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
  29.         <dependency>
  30.             <groupId>org.springframework.boot</groupId>
  31.             <artifactId>spring-boot-starter-web</artifactId>
  32.         </dependency>
  33.         <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  34.         <dependency>
  35.             <groupId>com.alibaba</groupId>
  36.             <artifactId>druid-spring-boot-starter</artifactId>
  37.             <version>1.2.8</version>
  38.         </dependency>
  39.         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  40.         <dependency>
  41.             <groupId>mysql</groupId>
  42.             <artifactId>mysql-connector-java</artifactId>
  43.         </dependency>
  44.         <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
  45.         <dependency>
  46.             <groupId>org.springframework.boot</groupId>
  47.             <artifactId>spring-boot-starter-jdbc</artifactId>
  48.         </dependency>
  49.         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  50.         <dependency>
  51.             <groupId>org.projectlombok</groupId>
  52.             <artifactId>lombok</artifactId>
  53.         </dependency>
  54.         <dependency>
  55.             <groupId>com.baomidou</groupId>
  56.             <artifactId>mybatis-plus-boot-starter</artifactId>
  57.             <version>${mybatis-plus.version}</version>
  58.             <optional>true</optional>
  59.             <exclusions>
  60.                 <exclusion>
  61.                     <groupId>com.baomidou</groupId>
  62.                     <artifactId>mybatis-plus-generator</artifactId>
  63.                 </exclusion>
  64.             </exclusions>
  65.         </dependency>
  66.     </dependencies>
  67.     <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
  68.     <dependencyManagement>
  69.         <dependencies>
  70.             <!--spring boot 2.2.2-->
  71.             <dependency>
  72.                 <groupId>org.springframework.boot</groupId>
  73.                 <artifactId>spring-boot-dependencies</artifactId>
  74.                 <version>2.2.2.RELEASE</version>
  75.                 <type>pom</type>
  76.                 <scope>import</scope>
  77.             </dependency>
  78.             <!--spring cloud Hoxton.SR1-->
  79.             <dependency>
  80.                 <groupId>org.springframework.cloud</groupId>
  81.                 <artifactId>spring-cloud-dependencies</artifactId>
  82.                 <version>Hoxton.SR1</version>
  83.                 <type>pom</type>
  84.                 <scope>import</scope>
  85.             </dependency>
  86.         </dependencies>
  87.     </dependencyManagement>
  88.     <build>
  89.         <plugins>
  90.             <plugin>
  91.                 <groupId>org.springframework.boot</groupId>
  92.                 <artifactId>spring-boot-maven-plugin</artifactId>
  93.                 <configuration>
  94.                     <addResources>true</addResources>
  95.                 </configuration>
  96.             </plugin>
  97.         </plugins>
  98.     </build>
  99. </project>
复制代码
3.对cloud-eureka-service注册中心操作
3.1 pom.xml文件
  1.         <dependencies>
  2.         <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
  3.         <dependency>
  4.             <groupId>org.springframework.cloud</groupId>
  5.             <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  6.         </dependency>
  7.     </dependencies>
复制代码
3.2 主启动类
  1. // 添加数据库和 druid 却未配置
  2. // 则添加 exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class}
  3. // 则启动报错
  4. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
  5. @EnableEurekaServer//告诉服务器我是一个注册中心
  6. public class EurekaServiceApplication {
  7.     public static void main(String[] args) {
  8.         SpringApplication.run(EurekaServiceApplication.class,args);
  9.     }
  10. }
复制代码
3.3 application.yml
  1. server:
  2.   port: 8001
  3. eureka:
  4.   instance:
  5.     hostname: 127.0.0.1  #eureka服务端的实例名字127.0.0.1 或 localhost
  6.   client:
  7.     #表识不向注册中心注册自己
  8.     register-with-eureka: false
  9.     #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
  10.     fetch-registry: false
  11.     service-url:
  12.       #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
  13.       #服务注册位置 http://127.0.0.1:8001/eureka/
  14.       defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
复制代码

4.对仓储模块cloud-stock-service操作
4.1 pom.xml
  1.         <dependencies>
  2.         <dependency>
  3.             <groupId>org.springframework.cloud</groupId>
  4.             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5.         </dependency>
  6.     </dependencies>
复制代码
4.2 主启动类
  1. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
  2. @EnableEurekaClient//需要使用Eureka注册中心添加此注解
  3. public class StockServiceApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(StockServiceApplication.class,args);
  6.     }
  7. }
复制代码
4.3 application.yml
  1. server:
  2.   port: 9001
  3. spring:
  4.   application:
  5.     name: cloud-stock-service
  6. eureka:
  7.   client:
  8.     # 向服务端注册
  9.     register-with-eureka: true
  10.     # 需要检索
  11.     fetchRegistry: true
  12.     service-url:
  13.       defaultZone: http://localhost:8001/eureka
复制代码
4.4 StockController
  1. @RestController
  2. @RequestMapping("/stock")
  3. public class StockController {
  4.     @GetMapping("/subStock")
  5.     public String subStock(){
  6.         System.out.println("库存减1");
  7.         return "库存减1";
  8.     }
  9. }
复制代码

5.对订单模块cloud-order-service操作
5.1 pom.xml文件
  1.     <dependencies>
  2.         <dependency>
  3.             <groupId>org.springframework.cloud</groupId>
  4.             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5.         </dependency>
  6.     </dependencies>
复制代码
5.2 主启动类
  1. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
  2. @EnableEurekaClient
  3. public class OrderServiceApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(OrderServiceApplication.class,args);
  6.     }
  7. }
复制代码
5.3 application.yml
  1. server:
  2.   port: 7001
  3. spring:
  4.   application:
  5.     name: cloud-order-servce
  6. eureka:
  7.   client:
  8.     # 向服务端注册
  9.     register-with-eureka: true
  10.     # 需要检索
  11.     fetchRegistry: true
  12.     service-url:
  13.       defaultZone: http://localhost:8001/eureka/
复制代码
5.4 OrderController
  1. @RestController
  2. @RequestMapping("/order")
  3. public class OrderController {
  4.         //这里特别提醒 `http://` 千万别忘加 本人因为这个错误找了很长时间 。。。。
  5.         //CLOUD-STOCK-SERVICE 这里是eureka注册中心的名称
  6.     private static final String HOST = "http://CLOUD-STOCK-SERVICE";
  7.     @Autowired
  8.     private RestTemplate restTemplate;
  9.     @GetMapping("/addOrder")
  10.     public String addOrder(){
  11.         System.out.println("订单已完成");
  12.         return restTemplate.getForObject(HOST + "/stock/subStock",String.class);
  13.     }
  14. }
复制代码
5.5 RestTemplate配置类
  1. @Configuration
  2. public class ApplicationConfig {
  3.     @Bean
  4.     @LoadBalanced//负载均衡器
  5.     public RestTemplate restTemplate(){
  6.         return new RestTemplate();
  7.     }
  8. }
复制代码

6.启动设置
我用的是idea 2021 ,多应用启动设置在如下位置

7.启动
7.1 先启动服务注册中心cloud-eureka-service 访问localhost:8001

7.2 在以端标语为9001和 9002 分别启动 cloud-stock-service
在yml文件 server.port更改 启动完成9001 更改端标语为9002 在启动一次 再次访问localhost:8001

7.3 在以端标语为7001和 7002 分别启动 cloud-order-service ,和 7.2更改方式一样 访问 localhost:8001

8. **测试 **
8.1 访问 localhost:7001/order/addOrder

8.2 观察控制台,当我们多少刷新访问 localhost:7001/order/addOrder 则会出现9001和9002交替处理哀求(轮循),缓解服务器压力,选择服务规则和 @LoadBalanced 负载均衡器有关

试着访问localhost:7002,结果类似

三、Eureka集群搭建

   在微服务架构中,一个体系每每由十几甚至几十个服务构成,若将这些服务全部注册到同一个 Eureka Server 中,就极有大概导致 Eureka Server 因不堪重负而瓦解,最终导致整个体系瘫痪。解决这个问题最直接的办法就是摆设 Eureka Server 集群。
  1.新建cloud-eureka-server-2和cloud-eureka-server-3

2.修改映射配置
打开 C:\Windows\System32\drivers\etc 目录下的hosts文件 修改映射配置添加进hosts文件

3.更改yml文件
3.1 cloud-eureka-service-2的yml文件
  1. server:
  2.   port: 8002
  3. eureka:
  4.   instance:
  5.     hostname: eureka8002.com  #eureka服务端的实例名字
  6.   client:
  7.     #表识不向注册中心注册自己
  8.     register-with-eureka: false
  9.     #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
  10.     fetch-registry: false
  11.     service-url:
  12.       #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
  13.       defaultZone: http://eureka8003.com:8003/eureka/
复制代码

3.2 cloud-eureka-service-2的yml文件
  1. server:
  2.   port: 8003
  3. eureka:
  4.   instance:
  5.     hostname: eureka8003.com  #eureka服务端的实例名字
  6.   client:
  7.     #表识不向注册中心注册自己
  8.     register-with-eureka: false
  9.     #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
  10.     fetch-registry: false
  11.     service-url:
  12.       #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
  13.       defaultZone: http://eureka8002.com:8002/eureka/
复制代码
3.3 cloud-order-service的yml文件
  1. server:
  2.   port: 7001
  3. spring:
  4.   application:
  5.     name: cloud-order-servce
  6. eureka:
  7.   client:
  8.     # 向服务端注册
  9.     register-with-eureka: true
  10.     # 需要检索
  11.     fetchRegistry: true
  12.     service-url:
  13.       defaultZone: http://localhost:8002/eureka,http://localhost:8003/eureka
复制代码

3.3 cloud-stock-service的yml文件
  1. server:
  2.   port: 9001
  3. spring:
  4.   application:
  5.     name: cloud-stock-service
  6. eureka:
  7.   client:
  8.     # 向服务端注册
  9.     register-with-eureka: true
  10.     # 需要检索
  11.     fetchRegistry: true
  12.     service-url:
  13.       defaultZone: http://localhost:8002/eureka,http://localhost:8003/eureka
复制代码

4.分别为cloud-eureka-service-2和cloud-eureka-service-3添加启动类
  1. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
  2. @EnableEurekaServer//告诉服务器我是一个注册中心
  3. public class EurekaServiceApplication2 {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(EurekaServiceApplication2.class,args);
  6.     }
  7. }
  8. -----------------------------------------------------------------------------------------------------------------
  9. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
  10. @EnableEurekaServer//告诉服务器我是一个注册中心
  11. public class EurekaServiceApplication3 {
  12.     public static void main(String[] args) {
  13.         SpringApplication.run(EurekaServiceApplication3.class,args);
  14.     }
  15. }
复制代码

5.启动
5.1 启动cloud-eureka-service-2和cloud-eureka-service-3
5.1.1 访问localhost:8002

5.1.2 访问localhost:8003


5.2 启动cloud-order-service和 端标语为9001和9002的cloud-stock-service集群服
5.2.1 访问localhost:8002

5.2.2 访问localhost:8003


6.测试 多次访问localhost:7001 观察控制台


以上方式可以形成一组相互注册的 Eureka Server 集群,当服务提供者发送注册哀求到 Eureka Server 时,Eureka Server 会将哀求转发给集群中所有与之相连的 Eureka Server 上,以实现 Eureka Server 之间的服务同步。

通过服务同步,服务消费者可以在集群中的任意一台 Eureka Server 上获取服务提供者提供的服务。这样,即使集群中的某个服务注册中心发生故障,服务消费者仍然可以从集群中的其他 Eureka Server 中获取服务信息并调用,而不会导致体系的整体瘫痪,这就是 Eureka Server 集群的高可用性。

四、心跳续约

   “心跳”指的是一段定时发送的自界说信息,让对方知道自己“存活”,以确保毗连的有效性。大部分 CS 架构的应用程序都接纳了心跳机制,服务端和客户端都可以发心跳。通常情况下是客户端向服务器端发送心跳包,服务端用于判定客户端是否在线
    心跳续约是指服务实例(Eureka客户端)定期向Eureka服务器发送心跳包,以证明其仍然在线并愿意继续提供服务。Eureka服务器会根据这些心跳包来更新服务实例的活泼状态,并维护一个可用的服务实例列表。
  

功能先容
Spring Cloud A 和 Spring Cloud B可以看作两个服务的提供者
Spring Cloud C 相当于 服务的消费者 定时(默认30秒)获取服务列表
registry服务注册列表 里面存储的是 各个注册服务的 名称 ip 端标语
readWriteCacheMap 会实时同步registry注册列表中的数据
readOnlyCacheMap 默认每30秒去同步一次readWriterCacheMap对象中的数据

详细流程


  • A和B 服务 向Eureka Service 服务注册列表中注册服务 将自己的服务名称 ip + 端标语注册到 registry服务注册列表。
  • A和B每隔30秒 (默认30秒) 发送 一次心跳任务告诉Eureka 我还活着, registry服务注册列表 同步数据到readWriteCacheMap
  • C 服务 通过readOnlyCacheMap 每30秒拉去一次注册表数据,这个数据不是同步的而是30秒(默认30秒)更新一次,这也是有时我们会在UI界面上看到服务注册乐成,调用时却出现错误的缘故原由。同理,服务下线也存在同样的问题,服务已经下线了,但是照旧有客户端在调用已经下线的服务,这时就会出现毗连拒绝的错误。
  • 我们在Eureka UI页面上看到的注册信息,现实上并没有走readOnlyCacheMap,而是直接通过registry服务注册列表获取,以是我们能够在Eureka UI页面实时的看到注册的新服务。
  • 服务续约默认是30秒 ,定时请理60秒清理一次超过90秒未续约的服务,也就是说在连续3次丢失心跳后会被Eureka Server的evict线程清理,最非常的情况,服务下线后,大概需要耽误180s之后,Eureka Server中的registry对象才会被更新。
综上分析,在非手动清除的情况下,缓存需要180秒才华感知下线的服务,这种情况在生产情况中非常严峻。

上述问题中,我们可以更改默认值,来解决感知下线服务时间过长问题
Eureka注册中心
  1. eureka:
  2.   server:
  3.     #清理无效服务间隔 (默认60秒)
  4.     eviction-interval-timer-in-ms: 1000
  5.     #同步readWrite到readOnly间隔(默认30秒)
  6.     response-cache-update-interval-ms: 10000
  7.     #Client直接从readWriteCacheMap更新服
  8.     #use-read-only-response-cache: false
复制代码
服务提供者
  1. eureka:
  2.   instance:
  3.     # Eureka注册中心(服务端)在收到客户端心跳之后,
  4.     #等待下一次心跳的超时时间,如果在这个时间内没有收到下次心跳,则移除该客户端。(默认90秒)
  5.     lease-expiration-duration-in-seconds: 5
  6.     # 客户端向注册中心发送心跳的时间间隔(默认30秒)
  7.     lease-renewal-interval-in-seconds: 2
复制代码
五、Eureka自我保护机制

   Eureka的自我保护机制是一种应对网络异常的安全保护措施,宁可同时保留所有微服务(康健的服务和不康健的服务都会保留)也不盲目移除任何康健的服务。
  当我们在当地调试基于 Eureka 的程序时,Eureka 服务注册中心很有大概会出现红色警告。



  • 现实上,这个警告是触发了 Eureka 的自我保护机制而出现的。默认情况下,如果 Eureka Server 在一段时间内没有接收到某个服务提供者的心跳,就会将这个服务提供者提供的服务从服务注册表中移除。 这样服务消费者就再也无法从服务注册中心中获取到这个服务了,更无法调用该服务。
  • 但在现实的分布式微服务体系中,康健的服务也有大概会由于网络故障(例如网络耽误、卡顿等缘故原由)而无法与 Eureka Server正常通讯。若此时 Eureka Server因为没有接收心跳而误将康健的服务从服务列表中移除,这显然是不公道的。而 Eureka 的自我保护机制就是来解决此问题的。
  • 所谓 “Eureka 的自我保护机制”,其中心思想就是“好死不如赖活着”。如果 Eureka Server 在一段时间内没有接收到 Eureka Client 的心跳,那么 Eureka Server 就会开启自我保护模式,将所有的 Eureka Client 的注册信息保护起来,而不是直接从服务注册表中移除。一旦网络规复,这些 Eureka Client 提供的服务还可以继续被服务消费者消费。

默认情况下,Eureka 的自我保护机制是开启的,如果想要关闭,则需要在配置文件中添加以下配置
  1. eureka:
  2.   server:
  3.           # false 关闭 Eureka 的自我保护机制,默认是开启
  4.     enable-self-preservation: false
复制代码

需要注意的是:
Eureka 的自我保护机制也存在弊端。如果在 Eureka 自我保护机制触发期间,服务提供者提供的服务出现问题,那么服务消费者就很轻易获取到已经不存在的服务进而出现调用失败的情况。此时,我们可以通过客户端的容错机制来解决此问题
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表