未发现oracle(tm)客户端和网络组件_SpringColud Eureka的服务注册与发现

一、Eureka简介

本文中所有代码都会上传到git上,请放心浏览 项目git地址:https://github.com/839022478/Spring-Cloud

在传统应用中,组件之间的调用,通过有规范的约束的接口来实现,从而实现不同模块间良好的协作。但是被拆分成微服务后,每个微服务实例的网络地址都可能动态变化,数量也会变化,使得原来硬编码的地址失去了作用。需要一个中心化的组件来进行服务的登记和管理,为了解决上面的问题,于是出现了服务治理,就是管理所有的服务信息和状态,也就是我们所说的注册中心

1.1 注册中心

比如我们去做火车或者汽车,需要去买票乘车,只看我们有没有票(有没有服务),有就去买票(获取注册列表),然后乘车(调用),不用关心到底有多少车在运行

流程图:f9483b4f78b06eb9619de986fdc03dec.png使用注册中心,我们不需要关心有多少提供方,只管去调用就可以了,那么注册中心有哪些呢?

注册中心:Eureka,Nacos,Consul,Zookeeper

本文中讲解的是比较火热的Spring Cloud微服务下的Eureka,Eureka是Netflix开发的服务发现框架,是一个RESTful风格的服务,是一个用于服务发现和注册的基础组件,是搭建Spring Cloud微服务的前提之一,它屏蔽了Server和client的交互细节,使得开发者将精力放到业务上。

服务注册与发现主要包括两个部分:服务端(EurekaServer)和客户端(EurekaClient)

  • 服务端(Eureka Server): 一个公共服务,为Client提供服务注册和发现的功能,维护注册到自身的Client的相关信息,同时提供接口给Client获取注册表中其他服务的信息,使得动态变化的Client能够进行服务间的相互调用。

  • 客户端(Eureka Client): Client将自己的服务信息通过一定的方式登记到Server上,并在正常范围内维护自己信息一致性,方便其他服务发现自己,同时可以通过Server获取到自己依赖的其他服务信息,完成服务调用,还内置了负载均衡器,用来进行基本的负载均衡

Eureka GIt官网:https://github.com/Netflix/Eureka

1.3 服务注册与发现

服务注册与发现关系图:ee90502e161f84823a7daf6509eafb59.png

1.2 client功能和server功能

1.2.1 client功能

  1. 注册:每个微服务启动时,将自己的网络地址等信息注册到注册中心,注册中心会存储(内存中)这些信息。

  2. 获取服务注册表:服务消费者从注册中心,查询服务提供者的网络地址,并使用该地址调用服务提供者,为了避免每次都查注册表信息,所以client会定时去server拉取注册表信息到缓存到client本地。

  3. 心跳:各个微服务与注册中心通过某种机制(心跳)通信,若注册中心长时间和服务间没有通信,就会注销该实例。

  4. 调用:实际的服务调用,通过注册表,解析服务名和具体地址的对应关系,找到具体服务的地址,进行实际调用。

1.2.2 server注册中心功能

  1. 服务注册表:记录各个微服务信息,例如服务名称,ip,端口等。注册表提供 查询API(查询可用的微服务实例)和管理API(用于服务的注册和注销)。

  2. 服务注册与发现:注册:将微服务信息注册到注册中心。发现:查询可用微服务列表及其网络地址。

  3. 服务检查:定时检测已注册的服务,如发现某实例长时间无法访问,就从注册表中移除。

二、Eureka单节点搭建

2.1 pom.xml

在有的教程中,会引入 spring-boot-starter-web,这个依赖其实不用,因为 spring-cloud-starter-netflix-eureka-server的依赖已经包含了它,在pom依赖进去,就可以了

<dependency>  <groupId>org.springframework.cloudgroupId>  <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>dependency>

2.2 application.yml

server:  port: 8500eureka:  client:    #是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息    register-with-eureka: false    #是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false    fetch-registry: false    #设置服务注册中心的URL,用于client和server端交流    service-url:      defaultZone: http://localhost:8080/eureka/

2.3 服务端启动类

启动类上添加此注解标识该服务为配置中心@EnableEurekaServer

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

2.4 启动

我们启动 EurekaDemoApplication,然后在浏览器中输入地址 http://localhost:8500/,就可以启动我们的 Eureka 了,我们来看下效果,出现了这个画面,就说明我们已经成功启动~,只是此时我们的服务中是还没有客户端进行注册

e18d3ad82ba459ee0414cb4108ba03ee.png

三、服务注册

注意:在客户端pom里面我们需要加上 spring-boot-starter-web,否则服务是无法正常启动的

3.1 pom.xml

 <dependency>      <groupId>org.springframework.bootgroupId>      <artifactId>spring-boot-starter-webartifactId>  dependency>  <dependency>      <groupId>org.springframework.cloudgroupId>      <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>  dependency>   

3.2 application.yml

#注册中心eureka:  client:    #设置服务注册中心的URL    service-url:      defaultZone: http://localhost:8500/eureka/  #服务名  instance:    appname: mxn

3.3 客户端启动类

在客户端启动类中我们需要加上 @EnableDiscoveryClient

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient@SpringBootApplicationpublic class EurekaClientApplication {    public static void main(String[] args) {        SpringApplication.run(EurekaClientApplication.class, args);    }}

3.4 查看效果

工程启动后,刷新 http://localhost:8500/页面,我们可以发现服务注册成功了5e0bb1ef0fea79476519d8f3aa2577b9.png

并且我们可以在idea日志打印中看到

DiscoveryClient_MXN/DESKTOP-5BQ3UK8-registration status:204

说明就是注册成功了 Eureka Server与Eureka Client之间的联系主要通过心跳的方式实现。心跳(Heartbeat)即Eureka Client定时向Eureka Server汇报本服务实例当前的状态,维护本服务实例在注册表中租约的有效性。

Eureka Client将定时从Eureka Server中拉取注册表中的信息,并将这些信息缓存到本地,用于服务发现

四、Eureka 端点

官网地址:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations

Eureka服务器还提供了一个端点 (eureka/apps/{applicaitonName})可以查看所注册的服务详细信息 。applicaitonName就是微服务的名称,比如这里我们访问 http://localhost:8500/eureka/apps/mxn

3ecb277ec9a4351e00a1288e0b438a40.png

五、Eureka 原理

5.1 本质

存储了每个客户端的注册信息。EurekaClient从EurekaServer同步获取服务注册列表。通过一定的规则选择一个服务进行调用

5.2 Eureka架构图

69dc78ae427cb63c7499161c82dee351.png

  • 服务提供者: 是一个eureka client,向Eureka Server注册和更新自己的信息,同时能从Eureka Server注册表中获取到其他服务的信息。

  • 服务注册中心: 提供服务注册和发现的功能。每个Eureka Cient向Eureka Server注册自己的信息,也可以通过Eureka Server获取到其他服务的信息达到发现和调用其他服务的目的。

  • 服务消费者: 是一个eureka client,通过Eureka Server获取注册到其上其他服务的信息,从而根据信息找到所需的服务发起远程调用。

  • 同步复制: Eureka Server之间注册表信息的同步复制,使Eureka Server集群中不同注册表中服务实例信息保持一致。

  • 远程调用: 服务客户端之间的远程调用。

  • 注册: Client端向Server端注册自身的元数据以供服务发现。

  • 续约: 通过发送心跳到Server以维持和更新注册表中服务实例元数据的有效性。当在一定时长内,Server没有收到Client的心跳信息,将默认服务下线,会把服务实例的信息从注册表中删除。

  • 下线: Client在关闭时主动向Server注销服务实例元数据,这时Client的服务实例数据将从Server的注册表中删除。

  • 获取注册表: Client向Server请求注册表信息,用于服务发现,从而发起服务间远程调用。

5.3 Eureka自我保护

有时候我们会看到这样的提示信息:

EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

这是因为默认情况下,Eureka Server在一定时间内,没有接收到某个微服务心跳,会将某个微服务注销(90S)。但是当网络故障时,微服务与Server之间无法正常通信,上述行为就非常危险,因为微服务正常,不应该注销,它的指导思想就是 宁可保留健康的和不健康的,也不盲目注销任何健康的服务我们也可以通过命令去关闭自我保护的功能:

eureka:  server:     enable-self-preservation: false

那么自我保护是如何触发的呢?

自我保护机制的触发条件是:当每分钟心跳次数( renewsLastMin) 小于 numberOfRenewsPerMinThreshold时,并且开启自动保护模式开关( eureka.server.enable-self-preservation=true) 时触发自我保护机制,不再自动过期租约 上面我们所有的小于 numberOfRenewsPerMinThreshold,到底是怎么计算的呢,我们在eureka源码中可以得知:numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比(默认为0.85)expectedNumberOfRenewsPerMin  = 当前注册的应用实例数 x 2当前注册的应用实例数 x 2 是因为,在默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2

例如:我们有10个服务,期望每分钟续约数:10 * 2=20,期望阈值:20*0.85=17,当少于17时,就会触发自我保护机制

b68a26c40b72df6ff44d5a0884ce50fc.png

5.4 健康检查

由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。db893296b8673c505767dde55454b32a.png

比如心跳一直正常,服务一直UP,但是此服务DB(数据库)连不上了,无法正常提供服务。

此时,我们需要将 微服务的健康状态也同步到server。只需要启动eureka的健康检查就行。这样微服务就会将自己的健康状态同步到eureka。配置如下即可。

在client端配置:将自己的健康状态传播到server。

eureka:  client:    healthcheck:      enabled: true

5.5 Eureka监听事件

import com.netflix.appinfo.InstanceInfo;import org.springframework.cloud.netflix.eureka.server.event.*;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Componentpublic class CustomEvent {    @EventListener    public void listen(EurekaInstanceCanceledEvent event ) {        System.out.println(LocalDateTime.now()+"服务下线事件:"+event.getAppName()+"---"+event.getServerId());//发钉钉    }    @EventListener    public void listen(EurekaInstanceRegisteredEvent event) {        InstanceInfo instanceInfo = event.getInstanceInfo();        System.out.println(LocalDateTime.now()+"服务上线事件:"+instanceInfo.getAppName()+"---"+instanceInfo.getInstanceId());    }    @EventListener    public void listen(EurekaInstanceRenewedEvent event) {        System.out.println(LocalDateTime.now()+"服务续约/心跳上报事件:"+event.getAppName()+"---"+event.getServerId());    }    @EventListener    public void listen(EurekaRegistryAvailableEvent event) {        System.out.println(LocalDateTime.now()+"注册中心可用事件");    }    @EventListener    public void listen(EurekaServerStartedEvent event) {        System.out.println(LocalDateTime.now()+"注册中心启动事件");    }}

5.6 Renew: 服务续约

Eureka Client 会每隔 30 秒发送一次心跳来续约。通过续约来告知 Eureka Server 该 Eureka Client 运行正常,没有出现问题。默认情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除,此时间可配置,一般情况不建议更改。

5.6 服务剔除

如果Eureka Client在注册后,既没有续约,也没有下线(服务崩溃或者网络异常等原因),那么服务的状态就处于不可知的状态,不能保证能够从该服务实例中获取到回馈,所以需要服务剔除此方法定时清理这些不稳定的服务,该方法会批量将注册表中所有过期租约剔除,剔除是定时任务,默认60秒执行一次。延时60秒,间隔60秒

剔除的限制:1.自我保护期间不清除。2.分批次清除。

六、Eureka缺陷

由于集群间的同步复制是通过HTTP的方式进行,基于网络的不可靠性,集群中的Eureka Server间的注册表信息难免存在不同步的时间节点,不满足CAP中的C(数据一致性)

七、总结

中间我们讲解了eureka的节点搭建,以及原理,对于现在很火热的微服务,我们对Eureka是非常有必要进行了解的,如果觉得文章对你有帮助,来个点赞支持吧,如果对文章有疑问或建议,欢迎讨论留言,谢谢大家~

--  End  --

———————

1.原创不易,你的在看是我创作的动力。

2.欢迎关注公众号 牧小农的夏天,「带你一起学Java」

3.疫情期间,勤洗手,戴口罩,做好个人防护。

923fb7b289e5b9d652deac0466765c9a.png

“在看转发”是最大的支持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql global index_Oracle中addsplit partition对globallocal index的影响

生产库中某些大表的分区异常&#xff0c;需要对现有表进行在线操作&#xff0c;以添加丢失分区&#xff0c;因为是生产库&#xff0c;还是谨慎点好&#xff0c;今天有空&#xff0c;针对addspli生产库中某些大表的分区异常&#xff0c;需要对现有表进行在线操作&#xff0c;以添…

sap寄售退货单_多个退货单

sap寄售退货单我曾经听说过&#xff0c;过去人们一直在努力使方法具有单个出口点。 我知道这是一种过时的方法&#xff0c;从未认为它特别值得注意。 但是最近我与一些仍坚持该想法的开发人员联系&#xff08;最后一次是在这里 &#xff09;&#xff0c;这让我开始思考。 因此…

课堂经验值管理小程序_微信小程序怎么管理门店?

微信门店小程序是一种不用注册下载就能使用的购物平台&#xff0c;近年来很是流行&#xff0c;而且它操作简单&#xff0c;能让用户快速找到自己需要的产品&#xff0c;然后进行购买&#xff0c;深得用户喜爱&#xff0c;有用户的地方就会有商家&#xff0c;商家想拥有自己的微…

C语言 | 直接插入排序

解题思路&#xff1a;直接插入排序是一种最简单的排序方法&#xff0c;其基本操作是将一条记录插入到已排好的有序表中&#xff0c;从而得到一个新的、记录数量增1的有序表。C语言源代码演示&#xff1a;#include//头文件 int main()//主函数 {void insort(int post[],int n)…

mysql+after+commit_Spring事务aftercommit原理及实践

来道题CREATE TABLE goods (id bigint(20) NOT NULL AUTO_INCREMENT,good_id varchar(20) DEFAULT NULL,num int(11) DEFAULT NULL,PRIMARY KEY (id),KEY goods_good_id_index (good_id)) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ciClass.forName("c…

序列化和反序列化的概念_序列化的概念

序列化和反序列化的概念讨论了为什么Optional不可序列化以及如何处理&#xff08;即将推出&#xff09;之后&#xff0c;让我们仔细看看序列化。 总览 这篇文章介绍了序列化的一些关键概念。 它尝试精简地执行此操作&#xff0c;而不会涉及太多细节&#xff0c;包括将建议降至…

python自动解析json_Python语言解析JSON详解

本文主要向大家介绍了Python语言解析JSON详解&#xff0c;通过具体的内容向大家展示&#xff0c;希望对大家学习Python语言有所帮助。 JSON 函数使用 JSON 函数需要导入 json 库&#xff1a;import json。函数 描述json.dumps 将 Python 对象编码成 JSON 字符串json.loads 将已…

C语言必学的12个排序算法:基数排序

# 基本思想基数排序(radix sort)&#xff0c;同样时一种非比较的内部排序算法&#xff0c;主要基于多关键字排序的思想进行排序&#xff0c;它将单个关键字按照基数分成“多个关键字”进行排序。例如整数789是一个关键字&#xff0c;可以按照十进制位划分多关键字&#xff08;十…

有没有code能改xml内容_Spring源码解析-applicationContext.xml加载和bean的注册

applicationContext文件加载和bean注册流程​ Spring对于从事Java开发的boy来说&#xff0c;再熟悉不过了&#xff0c;对于我们这个牛逼的框架的介绍就不在这里复述了&#xff0c;Spring这个大杂烩&#xff0c;怎么去使用怎么去配置&#xff0c;各种百度谷歌都能查到很多大牛教…

C语言数据类型转换

首先变量的数据类型是可以转换的。转换的方法有两种&#xff0c;一种是自动转换&#xff0c;另一种是强制转换。自动转换即当不同类型的数据进行混合运算时&#xff0c;编译系统将按照一定的规则自动完成。而强制类型转换是由程序员通过编程强制转换数据的类型。自动转换的规则…

jdk 9和jdk8_JDK 9 –给圣诞老人的信?

jdk 9和jdk8众所周知&#xff0c;冬天&#xff08;尤其是圣诞节前的时间&#xff09;是做梦的合适时机&#xff0c;希望有一个梦想似乎可以触及的时刻。 当孩子们和大人在纸上或在他们对圣诞老人的虚构或真实信件中写下自己的梦想时&#xff0c;希望他们的梦想将成为现实。 这很…

java 类持久化_Java 持久化之 -- IO 全面整理(看了绝不后悔)

目录&#xff1a;一、java io 概述什么是IO&#xff1f;IO包括输入流和输出流&#xff0c;输入流指的是将数据以字符或者字节形式读取到内存 分为字符输入流和字符输入流输入流指的是从内存读取到外界 &#xff0c;分为字符输入流和字节输出流Java IO即Java 输入输出系统。不管…

idea 找不到或无法加载主类_解决IDEA中Groovy项目no Groovy library is defined的问题

实验环境IDEA2019.1.2Groovy-2.5.8错误重现新建了一个Groovy工程&#xff0c;指定了groovy版本&#xff0c;如图新建了一个简单的Groovy Class&#xff0c;运行&#xff0c;出现如下错误错误的尝试(以下是试错过程&#xff0c;并不能解决问题&#xff0c;读者可以不要跟着操作&…

C语言标识符、关键字和注释

这一节主要讲解C语言中的几个基本概念。标识符定义变量时&#xff0c;我们使用了诸如“a”“abc”“mn123”这样的名字&#xff0c;它们都是程序员自己起的&#xff0c;一般能够表达出变量的作用&#xff0c;这叫做标识符&#xff08;Identifier&#xff09;。标识符就是程序员…

java与java ee_Java EE 8怎么了?

java与java eeJava EE 8的工作进展顺利。 是时候赶上了&#xff01; 无需费力就可以潜入… 不要忘记Java EE 7….. 围绕三个重要主题 HTML 5对齐–用于WebSocket的Java API&#xff08;JSR 356&#xff09;&#xff0c;JSON处理&#xff08;JSR 353&#xff09;&#xff0c;JA…

java 类.class_面试官:Java反射是什么?我回答不上来!

一.概念反射就是把Java的各种成分映射成相应的Java类。Class类的构造方法是private&#xff0c;由JVM创建。反射是java语言的一个特性&#xff0c;它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和…

巧解C语言运算符的优先级和结合性

本篇文章我们从一个例子入手讲解&#xff0c;请看下面的代码&#xff1a;#include int main(){ int a 16, b 4, c 2; int d a b * c; int e a / b * c; printf( "d%d, e%d\n", d, e); return 0; }运行结果&#xff1a;d24, e81) 对于表达式a b * c&#xff0…

jms mdb_MDB!= JMS,反之亦然

jms mdb基本 消息驱动Bean&#xff08;又称为MDB&#xff09;只是另一个EJB&#xff0c;例如无状态&#xff0c;有状态或单例。 使用MessageDriven批注指定。 MDB用于异步消息处理 它们与无状态EJB 相似 &#xff0c;因为它们都是由EJB容器池化的 但是&#xff0c;它们与无状…

java interestops_Java Channel.setInterestOps方法代码示例

import org.jboss.netty.channel.Channel; //导入方法依赖的package包/类protected void doConnect() throws Throwable {long start System.currentTimeMillis();ChannelFuture future bootstrap.connect(getConnectAddress());try{boolean ret future.awaitUninterruptibl…

python时间间隔循环_python循环间隔

广告关闭回望2020&#xff0c;你在技术之路上&#xff0c;有什么收获和成长么&#xff1f;对于未来&#xff0c;你有什么期待么&#xff1f;云社区年度征文&#xff0c;各种定制好礼等你&#xff01;序言如图1.1中关于如何用python去计算两个时间(年月日)相隔多少天&#xff0c…