图片的链接出了一点小bug,导致图片不能正常访问,小伙伴们可以移步这里:https://mp.weixin.qq.com/s/kAqOTKUt_qPlxzI4aGS5Pw

本文是Spring Cloud系列的第四篇,前面三篇文章(使用Spring Cloud搭建服务注册中心使用Spring Cloud搭建高可用服务注册中心Spring Cloud中服务的发现与消费)我们带大家搭建了服务注册中心,向服务注册中心注册了服务,同时也发现和消费了服务。前面的文章我们是以实际代码操作为主,这篇文章我想对前面三篇文章中涉及到的一些知识点再进行详细的梳理,对于一些前面未涉及到的配置再做进一步的说明。

首先,通过前面三篇文章的学习,小伙伴们已经发现了Eureka服务治理体系中涉及到三个核心概念:服务注册中心、服务提供者以及服务消费者,本文将从这三个方面来对Eureka服务治理体系进行一个详细的说明。

服务提供者

Eureka服务治理体系支持跨平台,虽然我们前文使用了Spring Boot来作为服务提供者,但是对于其他技术平台只要支持Eureka通信机制,一样也是可以作为服务提供者,换句话说,服务提供者既可以是Java写的,也可以是python写的,也可以是js写的。这些服务提供者将自己注册到Eureka上,供其它应用发现然后调用,这就是我们的服务提供者,服务提供者主要有如下一些功能:

服务注册

服务提供者在启动的时候会通过发送REST请求将自己注册到Eureka Server上,同时还携带了自身服务的一些元数据信息。Eureka Server在接收到这个REST请求之后,将元数据信息存储在一个双层结构的Map集合中,第一层的key是服务名,第二层的key是具体服务的实例名,我们在上篇文章最后展示出来的截图中,大家也可以看出一些端倪,如下:

同时,我们在服务注册时,需要确认一下eureka.client.register-with-eureka=true配置是否正确,该值默认就为true,表示启动注册操作,如果设置为false则不会启动注册操作。

服务同步

再说服务同步之前,我先描述一个场景:首先我有两个服务注册中心,地址分别是http://localhost:1111http://localhost:1112,然后我还有两个服务提供者,地址分别是http://localhost:8080http://localhost:8081,然后我将8080这个服务提供者注册到1111这个注册中心上去,将8081这个服务提供者注册到1112这个注册中心上去,此时我在服务消费者中如果只向1111这个注册中心去查找服务提供者,那么是不是只能获取到8080这个服务而获取不到8081这个服务?大家看下面一张图:

答案是服务消费者可以获取到两个服务提供者提供的服务。虽然两个服务提供者的信息分别被两个服务注册中心所维护,但是由于服务注册中心之间也互相注册为服务,当服务提供者发送请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步,通过服务同步,两个服务提供者的服务信息我们就可以通过任意一台注册中心来获取到。OK,下面我们来通过一个简单的案例来验证一下我们上面的理论:

eureka-server工程我们前面已经分别创建了application-peer1.properties和application-peer2.properties配置文件,如下:
application-peer1.properties:

spring.application.name=eureka-server
server.port=1111
eureka.instance.hostname=peer1
eureka.client.register-with-eureka=true
eureka.client.service-url.defaultZone=http://peer2:1112/eureka/

application-peer2.properties:

spring.application.name=eureka-server
server.port=1112
eureka.instance.hostname=peer2
eureka.client.register-with-eureka=true
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/

然后我们通过下面两行命令来启动两个服务注册中心实例,如下:

java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

然后我们给provider工程也创建两个配置文件,分别为application-p1.properties和application-p2.properties,内容如下:

application-p1.properties:

spring.application.name=hello-service
server.port=8080
eureka.client.service-url.defaultZone=http://peer1:1111/eureka

application-p2.properties:

spring.application.name=hello-service
server.port=8081
eureka.client.service-url.defaultZone=http://peer2:1112/eureka

然后通过如下命令启动两个服务提供者的实例,如下:

java -jar provider-0.0.1-SNAPSHOT.jar --spring.profiles.active=p1
java -jar provider-0.0.1-SNAPSHOT.jar --spring.profiles.active=p2

OK,我们将8080这个服务注册到1111这个服务注册中心上去了,将8081这个服务注册到1112这个服务注册中心上去了。当两个服务提供者都启动成功之后,我们来看看两个服务注册中心的控制面板,如下: 、

最后我们再来看看ribbon-consumer的配置文件,如下:

spring.application.name=ribbon-consumer
server.port=9000
eureka.client.service-url.defaultZone=http://peer1:1111/eureka

大家看到,我们运行消费端时只向1111那个服务注册中心去获取服务列表,但是在实际运行过程中8080和8081两个服务提供者都有响应我们的请求,如下图:

上面的日志是8081打印的,下面的日志是8080打印的,没毛病。

服务续约

在注册完服务之后,服务提供者会维护一个心跳来不停的告诉Eureka Server:“我还在运行”,以防止Eureka Server将该服务实例从服务列表中剔除,这个动作称之为服务续约,和服务续约相关的属性有两个,如下:

eureka.instance.lease-expiration-duration-in-seconds=90
eureka.instance.lease-renewal-interval-in-seconds=30

第一个配置用来定义服务失效时间,默认为90秒,第二个用来定义服务续约的间隔时间,默认为30秒。

服务消费者

消费者主要是从服务注册中心获取服务列表,拿到服务提供者的列表之后,服务消费者就知道去哪里调用它所需要的服务了,我们从下面几点来进一步了解下服务消费者。

获取服务

当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心来获取服务注册中心上面的服务提供者列表,而Eureka Server上则会维护一份只读的服务清单来返回给客户端,这个服务清单并不是实时数据,而是一份缓存数据,默认30秒更新一次,如果想要修改清单更新的时间间隔,可以通过eureka.client.registry-fetch-interval-seconds=30来修改,单位为秒(注意这个修改是在eureka-server上来修改)。另一方面,我们的服务消费端要确保具有获取服务提供者的能力,此时要确保eureka.client.fetch-registry=true这个配置为true。

服务调用

服务消费者从服务注册中心拿到服务提供者列表之后,通过服务名就可以获取具体提供服务的实例名和该实例的元数据信息,客户端将根据这些信息来决定调用哪个实例,我们之前采用了Ribbon,Ribbon中默认采用轮询的方式去调用服务提供者,进而实现了客户端的负载均衡。

服务下线

服务提供者在运行的过程中可能会发生关闭或者重启,当服务进行正常关闭时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心我要下线了,服务注册中心收到请求之后,将该服务状态置为DOWN,表示服务已下线,并将该事件传播出去,这样就可以避免服务消费者调用了一个已经下线的服务提供者了。

服务注册中心

服务注册中心就是Eureka提供的服务端,它提供了服务注册与发现功能。

失效剔除

上面我们说到了服务下线问题,正常的服务下线发生流程有一个前提那就是服务正常关闭,但是在实际运行中服务有可能没有正常关闭,比如系统故障、网络故障等原因导致服务提供者非正常下线,那么这个时候对于已经下线的服务Eureka采用了定时清除:Eureka Server在启动的时候会创建一个定时任务,每隔60秒就去将当前服务提供者列表中超过90秒还没续约的服务剔除出去,通过这种方式来避免服务消费者调用了一个无效的服务。

自我保护

我们在前三篇文章中给大家看的截图上,都有这样一个警告,如下图:

这个警告实际上就是触发了Eureka Server的自我保护机制。Eureka Server在运行期间会去统计心跳失败比例在15分钟之内是否低于85%,如果低于85%,Eureka Server会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果服务刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败,对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。我们在单机测试的时候很容易满足心跳失败比例在15分钟之内低于85%,这个时候就会触发Eureka的保护机制,一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除。

OK,以上就是我们对Eureka中服务注册中心、服务提供者、服务消费者三个核心概念的一些理解,有问题欢迎留言讨论。

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

以上。。

Eureka中的核心概念的更多相关文章

  1. Mycat中的核心概念

      Mycat中的核心概念     Mycat中的核心概念 1.数据库中间件    Mycat 是一个开源的分布式数据库系统,但是由于真正的数据库需要存储引擎,而 Mycat 并没有 存储引擎,所以并 ...

  2. SpringCloud升级之路2020.0.x版-16.Eureka架构和核心概念

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Eureka 目前 ...

  3. react中的核心概念

    DOM:浏览器中提供的概念: 虚拟DOM:框架中的概念:需要开发框架的程序员手动用JS对象来模拟DOM元素和嵌套关系: 本质:用JS对象,模拟DOM树: 目的:实现页面的按需更新: 要求:点击列头,实 ...

  4. JIRA中的核心概念

    转载自:http://blog.csdn.net/zhengxy2011/article/details/6940380 1.1.1   问题 JIRA跟踪问题(Issue),这些问题可以是bug,功 ...

  5. Mycat入门核心概念

      Mycat中的核心概念     Mycat中的核心概念 1.数据库中间件    Mycat 是一个开源的分布式数据库系统,但是由于真正的数据库需要存储引擎,而 Mycat 并没有 存储引擎,所以并 ...

  6. Ext JS 6学习文档–第2章–核心概念

    核心概念 在下一章我们会构建一个示例项目,而在这之前,你需要学习一些在 Ext JS 中的核心概念,这有助于你更容易理解示例项目.这一章我们将学习以下知识点: 类系统,创建和扩展类 事件 Ext JS ...

  7. 在k8s中的基本概念

    在k8s中的基本概念 一.Pod1. podk8s下最重要也最基本的概念,由一个根容器Pause和许多用户业务容器组成,是容器的载体. 2. pod的yaml定义格式及字段 apiVersion: v ...

  8. ElasticSearch 全文检索— ElasticSearch 核心概念

    ElasticSearch核心概念-Cluster 1)代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的.es的一个概念就是去中心化,字 ...

  9. 图解Disruptor框架(二):核心概念

    图解Disruptor框架(二):核心概念 概述 上一个章节简单的介绍了了下Disruptor,这节就是要好好的理清楚Disruptor中的核心的概念.并且会给出个HelloWorld的小例子. 在正 ...

随机推荐

  1. hdu6489 2018 黑龙江省大学生程序设计竞赛j题

    Problem Description Kayaking is playing a puzzle game containing n different blocks. He marks the bl ...

  2. python 获取mac地址zz

    通过python获取当前mac地址的方法如下:(1)通用方法,借助uuid模块def get_mac_address(): import uuid      node = uuid.getnode() ...

  3. nginx.conf 中php-ftp配置

    location ~ .php$ { root /home/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_par ...

  4. 20181115 python-第一章学习小结part2

    Python基本知识 变量,用来存储中间计算结果,在后面可进行调用被使用的东西,叫做变量. 变量的命名规则: 字母,数字,下划线组合 不能用数字开头 常见的关键字不能用啊 常量,不会变的量,称作常量. ...

  5. VB控件间的拖放

    新建工程,放置控件Picture1,Text1,Text2,复制下面的代码运行 Text1和Text2可以互相拖放,也可以将Picture1拖放给Text1,Text2. Private Sub Fo ...

  6. Egret获取和显示时间,年,月,日,时分秒

    let now = new Date(); this.nowYear = now.getFullYear(); this.nowMonth = now.getMonth() + 1; let noww ...

  7. TCP(控制传输协议)详解

    1.传输层概述 在OSI参考模型中,网络层是面向通信的最高层但同时也是面向用户程序的最底层. 传输层的主要作用: 复用:在发送端,多个应用程序公用一个传输层: 分用:在接收端,传输层把从网络层接收到的 ...

  8. TP框架下载功能

    namespace Home\Controller; use Think\Controller; use Org\Net\Http; class IndexController extends Con ...

  9. Markdown基础语法笔记

    # 一级标题## 二级标题### 三级标题###### #号之后记得加一个空格 仅支持1-6级标题  ### 列表 - 文本1 - 文本2 - 文本3+ 列表2* 列表2 ### 有序列表1. 有序文 ...

  10. Java for Andriod 第二周学习总结

    第四章 学习时遇到的问题或新知识点: 1. 构造方法.每个类至少有一个构造方法,且构造方法必须的名称必须与类名相同. 2. Varargs.允许方法拥有一个可变长度的参数列表. 3. 对象的内存分配. ...