1、Eureka是什么?

Eureka由Netflix开源,并被Pivatal集成到SpringCloud体系中,它是基于 RestfulAPI 风格开发的服务注册与发现组件,它是一个服务注册中心。

服务注册中心本质上是为了解耦服务提供者和服务消费者。

在服务注册中心之前,服务消费者调用服务提供者,会把服务提供者的url地址硬编码到代码中(代码如下),这样做的坏处是不方便后期维护,以及不知道服务提供者的状态信息。


@RestController
@RequestMapping("/page")
public class PageController {
@Resource
private RestTemplate restTemplate;

@GetMapping("/query/{id}")
public Products getProductById(@PathVariable int id){
Products products = restTemplate.getForObject("http://localhost:9999/product/query/" + id, Products.class);
return products;
}
}
 

详细代码

2、服务注册中心如何解耦?

分布式微服务架构中服务注册中心用于存储服务提供者地址信息、服务发布相关的属性信息,消费者通过主动查询和被动通知的方式获取服务提供者的地址信息,而不再需要通过硬编码方式得到提供者的

地址信息。消费者只需要知道当前系统发布了那些服务,而不需要知道服务具体存在于什么位置, 这就是透明化路由。如下图:

上图说明:

  • 服务提供者、服务消费者启动
  • 服务提供者将相关服务信息主动注册到注册中心
  • 服务消费者获取服务注册信息:服务消费者直接调用服务提供者
    • pull模式:服务消费者可以主动拉取可用的服务提供者清单
    • push模式:服务消费者订阅服务(当服务提供者有变化时,注册中心也会主动推送更新后的服务清单给消费者
  • 服务消费者直接调用服务提供者

注册中心也需要完成服务提供者的健康监控,当发现服务提供者失效时需要及时剔除;

3、那么讲完服务注册中心,我们来看看Eureka的基础架构

Eureka交互流程

Eureka 包含两个组件:Eureka Server 和 Eureka Client,Eureka Client是一个Java客户端,用于简化与Eureka Server的交互;Eureka Server提供服务发现的能力,各个微服务启动时,会通过EurekaClient向Eureka Server 进行注册自己的信息(例如网络信息),Eureka Server会存储该服务的信息;

  • Application Service作为服务提供者向Eureka Server中注册服务,Eureka Server接受到注册事件会在集群和分区中进行数据同步,ApplicationClient作为消费端(服务消费者)可以从Eureka Server中获取到服务注册信息,进行服务调用。
  • 微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒,默认Eureka Server 90S会将还没有续约的给剔除)以续约自己的信息
  • Eureka Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服务节点(默认90秒)
  • 每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务 注册列表的同步
  • Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者

总之,Eureka通过心跳检测、健康检查和客户端缓存等机制,提高系统的灵活性、可伸缩性和高可用性。

4、Eureka服务端详解

4.1、服务下线

  当服务正常关闭操作时,会发送服务下线的REST请求给EurekaServer

  服务中心接收到请求后,将该服务置为下线状态

4.2、失效剔除

  Eureka Server会定时(间隔值是eureka.server.eviction-interval-timer-in-ms,默认60s)进行检查,如果发现实例在一定时间(此值由客户端设置的eureka.instance.lease-expiration-duration-in-seconds定义,默认值为90s)内没有收到心跳,则会注销此实例

4.3、自我保护机制

  自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。自我保护机制的工作机制是:如果在15分钟内超过85%的客户端节点都没有正常心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现一下几种情况:

  • Eureka Server不再从注册列表中移除,因为长时间没收到心跳而应该过期的服务
  • Eureka Server仍然能够接收新服务的注册和查询请求,但是不会被同步到其他节点上,保证当前节点依然可用
  • 当网络稳定时,当前Eureka Server新的注册信息会被同步到其他节点中
  因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会想ZK那样,如果有一半不可用的情况,会导致整个集群不可用而变成瘫痪
4.4、为什么会有自我保护机制
  默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳, Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通 信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
  如果心跳失败比例在 15 分钟之内低于 85%,服务中心页面会显示如下提示信息

  我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,这个时候就会触发 Eureka 的保护机制,一旦开启了保护机制(默认开启),则服务注册中心维护的服务实例就不是那么准确了, 此时我们通过修改Eureka Server的配置文件来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐)。
5、Eureka客户端详解
5.1、服务注册详解(服务提供者)
  • 当我们导入eureka-client依赖坐标,配置Eureka服务注册中心地址
  • 服务在启动时会向注册中心发起注册请求,并携带服务元数据信息
  • Eureka注册中心会把服务的信息保存在Map中(ConcurrentHashMap)

5.2、服务续约详解(服务提供者)

  服务每隔30s回向注册中心续约一次,如果没有续约,租约在90s后到期,然后服务会被失效。每隔30s的续约操作我们称之为心跳检测。

  • Eureka Client:30s续约一次,在Eureka Server更新自己的状态(Client端进行配置)
  • Eureka Server:90s还没有进行续约,将该微服务实例从服务注册表(Map)剔除(Client端进行配置)
  • Eureka Client: 30s拉取服务最新的注册表并缓存到本地(Client端进行配置)

通过以下配置

#向Eureka服务中心集群注册服务
eureka:
instance:
# 租约续约间隔时间,默认30秒
lease-renewal-interval-in-seconds: 30
# 租约到期,服务时效时间,默认值90秒,服务超过90秒没有发生心跳,EurekaServer会将服务从列 表移除
lease-expiration-duration-in-seconds: 90

5.3、获取服务列表详解

每个30s服务会从注册中心拉取一份服务列表,这个时间可以通过配置修改。但往往不需要我们调整

  • 服务消费者启动时,从Eureka Server服务列表获取只读备份,缓存到本地
  • 每隔30s会重新获取并更新数据
  • 每隔30s可以通过配置eureka.client.registry-fetch-interval-seconds修改
#向Eureka服务中心集群注册服务
eureka:
client:
# 每隔多久拉取一次服务列表
registry-fetch-interval-seconds: 30

6、Eureka的元数据

Eureka元数据有两种:标准元数据和自定义元数据

6.1、标准元数据

它包含主机名、IP地址、端口号等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用

 6.2、自定义元数据

它可以使用eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。这些元数据可以在远程客户端中访问

通过以下代码调试获取

@RestController
@RequestMapping("/metadata")
public class MetaDataController { @Resource
private DiscoveryClient discoveryClient; @GetMapping("/show")
public Map<String,String> getMetaData(){
List<ServiceInstance> instances = discoveryClient.getInstances("hy-service-product");
ServiceInstance serviceInstance = instances.get(0);
Map<String, String> metadata = serviceInstance.getMetadata();
return metadata;
}
}

 7、Eureka的应用

项目结构

第一步、在父目录的pom文件中引入下面内容

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Greenwich.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
      </dependency>
  </dependencies>
</dependencyManagement>

<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.6.RELEASE</version>
</parent>

其中dependency里面的version内容要和parent里面的version要对应,否则会报错

第二步:在两个Eureka服务的pom文件引入

<!--引入Eureka Server-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

第三步:配置Eureka服务下面的yml文件(记得服务端口号要修改)

server:
port: 11111
spring:
application:
name: hy-cloud-eureka-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
eureka:
instance:
hostname: HyCloudEurekaServiceA
client:
service-url: # 客户端与EurekaServer交互的地址,如果是集群,也需要写其它Server的地址
defaultZone: http://HyCloudEurekaServiceB:22222/eureka/
register-with-eureka: true # 自己就是服务不需要注册自己
fetch-registry: true #自己就是服务不需要从Eureka Server获取服务信息,默认为true,置为false

第四步:启动类

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

第五步:配置两个微服务下的yml文件

page:

server:
port: 8888 # 后期该微服务多实例,端口从9100递增(10个以内)
Spring:
application:
name: hy-service-page
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/hy?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: "root"
password: "123456"
eureka:
client:
serviceUrl: # eureka server的路径
defaultZone: http://HyCloudEurekaServiceA:11111/eureka/,http://HyCloudEurekaServiceB:22222/eureka/
instance:
#使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true
#自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@

product:

server:
port: 9999 # 后期该微服务多实例,端口从9100递增(10个以内)
Spring:
application:
name: hy-service-product
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/hy?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: "root"
password: "123456"
eureka:
client:
serviceUrl: # eureka server的路径
defaultZone: http://HyCloudEurekaServiceA:11111/eureka/,http://HyCloudEurekaServiceB:22222/eureka/
instance:
#使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true
#自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@

第六步:编写Product的Controller

@RestController
@RequestMapping("/product")
public class ProductController { @Resource
private ProductService productService; @RequestMapping("/query/{id}")
public Products query(@PathVariable Integer id){
return productService.findById(id);
}
}

此处省略service代码

第七步:编写Page微服务的Controller

@RestController
@RequestMapping("/page")
public class PageController {
@Resource
private RestTemplate restTemplate; @Resource
private DiscoveryClient discoveryClient; @GetMapping("/query/{id}")
public Products getProductById(@PathVariable int id){
List<ServiceInstance> instances = discoveryClient.getInstances("hy-service-product");
System.out.println(instances);
ServiceInstance serviceInstance = instances.get(0);
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
System.out.println(host + " " + port);
String url = "http://"+host +":" + port +"/product/query/" + id;
Products products = restTemplate.getForObject(url, Products.class);
return products;
}
}

第八步:启动四个服务:随便登录一个Eureka的服务如下图所示,表明启动成功

第九步:测试

代码详细地址

微服务笔记之Eureka(1)的更多相关文章

  1. 微服务之服务中心—Eureka

    Eureka 简介Eureka 是 Spring Cloud Netflix 的一个子模块,也是核心模块之一,用于云端服务发现,是一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故 ...

  2. 将微服务注册到Eureka Server

    一.微服务程序编写 1.在已写好的微服务程序中添加pom依赖: <dependency> <groupId>org.springframework.cloud</grou ...

  3. SpringCloud系列三:将微服务注册到Eureka Server上

    1. 回顾 通过上篇博客的讲解,我们知道硬编码提供者地址的方式有不少问题.要想解决这些问题,服务消费者需要一个强大的服务发现机制,服务消费者使用这种机制获取服务提供者的网络信息.不仅如此,即使服务提供 ...

  4. spring cloud之docker微服务客户端注册eureka问题

    正常我们起一个微服务注册到eureka他的实例id是默认这样的主机名称:服务名称:服务端口号, 如果配置eureka.instance.prefer-ip-address=true则实例id为主机Ip ...

  5. 【一起学源码-微服务】Nexflix Eureka 源码十:服务下线及实例摘除,一个client下线到底多久才会被其他实例感知?

    前言 前情回顾 上一讲我们讲了 client端向server端发送心跳检查,也是默认每30钟发送一次,server端接收后会更新注册表的一个时间戳属性,然后一次心跳(续约)也就完成了. 本讲目录 这一 ...

  6. 【一起学源码-微服务】Nexflix Eureka 源码十三:Eureka源码解读完结撒花篇~!

    前言 想说的话 [一起学源码-微服务-Netflix Eureka]专栏到这里就已经全部结束了. 实话实说,从最开始Eureka Server和Eureka Client初始化的流程还是一脸闷逼,到现 ...

  7. 2021升级版微服务教程3—Eureka完全使用指南

    2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 默认文件1610014380163 教程全目录「含视 ...

  8. Spring Cloud之微服务注册到Eureka Server集群

    在Spring Cloud之服务注册中心搭建Eureka Server服务注册中⼼ - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中已经搭建好了Eureka Server集群,本文就利用 ...

  9. Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门

    服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...

  10. 微服务架构:Eureka集群搭建

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 服务注册.发现是微服务架构的关键原理之一,由于微服务架构是由一系列职责单一的细粒度服务构成的网状结构,服务之间通过轻量机制进行通信,这就必 ...

随机推荐

  1. 【Azure Cache for Redis】Python Djange-Redis连接Azure Redis服务遇上(104, 'Connection reset by peer')

    问题描述 使用Python连接Azure Redis服务,因为在代码中使用的是Djange-redis组件,所以通过如下的配置连接到Azure Redis服务: CACHES = { "de ...

  2. JS 格式化时间字符串

    // 格式时间字符串 formatDateTimeStr(date, type) { if (date === '' || !date) { return '' } var dateObject = ...

  3. 2021级《JAVA语言程序设计》上机考试试题

    勉强写完了 Card package Bean; public class Card { private String CardId; private String CardData; private ...

  4. 记一次完整的PHP代码审计——yccms v3.4审计

    一.环境搭建与使用工具 (一)环境搭建 打开源码查看安装要求 PHP 5.4+,Mysql 5.0.*,直接使用phpstudy配置即可 查看源码目录结构,发现是mvc模式的,那么我们重点关注的就是c ...

  5. 题解 [SCOI2005]王室联邦

    之前树分块也只是听说,今天亲手学了一下(?)( 首先你会发现这个 \(B\) 和 \(3B\) 的约束就很迷(我也不知道为什么搞这种奇怪的约束(悲)),学了才知道... 所以这题的分块方法好像叫&qu ...

  6. 利用反射和代理简单模拟mybatis实现简单的CRUD

    利用反射接口做java数据库操作 今天突发奇想,好像一些基本的CRUD操作路数都是一样的,又想到mybatis中的操作,便想着简单的模拟一下.随便写写,就当练习反射了. Dao接口类: 这里使用泛型, ...

  7. GeoServer发布Oracle空间数据

    1. 概述 Oracle是常用的数据库,Oracle数据库包含空间数据库,可以在Oracle中进行空间数据的存储,更详细的信息可参考: 空间数据库 | Oracle 中国 GeoServer是常用的开 ...

  8. 基于C++的OpenGL 02 之着色器

    1. 概述 本文基于C++语言,描述OpenGL的着色器 环境搭建以及绘制流程可参考: 基于C++的OpenGL 01 之Hello Triangle - 当时明月在曾照彩云归 - 博客园 (cnbl ...

  9. PostgreSQL处理膨胀与事务回卷

    一.表膨胀查询与处理 1.创建扩展 create extension pgstattuple; 2.表膨胀查询 pgstattuple提供了pgstatetuple()和pgstatindex()两个 ...

  10. Python Socket 基础多用户编程

    简介   写下这篇小记的原因是想记录一下自己学习Python Socket编程的心路历程.之前在中专的时间学过一些基础的Socket编程,知道了一些比较基础的内容比如基础的socket.bind()类 ...