關(guān)于Eureka的概念作用以及用法詳解
一、概念
1.1、什么是服務(wù)治理
Spring Cloud 封裝了 Netflix
公司開發(fā)的 Eureka 模塊來實(shí)現(xiàn)服務(wù)治理
服務(wù)治理就是提供了微服務(wù)架構(gòu)中各微服務(wù)實(shí)例的快速上線或下線且保持各服務(wù)能正常通信的能力的方案總稱。
服務(wù)治理的優(yōu)點(diǎn):
- 更高的可用性:服務(wù)治理可以支持動(dòng)態(tài)的服務(wù)實(shí)例集群環(huán)境,任何服務(wù)實(shí)例可以隨時(shí)上線或下線。并且
當(dāng)一個(gè)服務(wù)實(shí)例不可用時(shí),治理服務(wù)器可以將請求轉(zhuǎn)給其他服務(wù)提供者
,當(dāng)一個(gè)新的服務(wù)實(shí)例上線時(shí),也能夠快速地分擔(dān)服務(wù)調(diào)用請求。 - 負(fù)載均衡:服務(wù)治理可以提供動(dòng)態(tài)的負(fù)載均衡功能,可以
將所有請求動(dòng)態(tài)地分布到其所管理的所有服務(wù)實(shí)例中進(jìn)行處理
。 - 提升應(yīng)用的彈性:服務(wù)治理的客戶端會(huì)
定時(shí)從服務(wù)治理服務(wù)器中復(fù)制一份服務(wù)實(shí)例信息緩存到本地中
,這樣即使當(dāng)服務(wù)治理服務(wù)器不可用時(shí),服務(wù)消費(fèi)者也可以使用本地的緩存去訪問相應(yīng)的服務(wù)
,而不至于中斷服務(wù)。通過這種機(jī)制,極大地提高了應(yīng)用的彈性。 - 高可用性集群:可以構(gòu)建服務(wù)治理集群,
通過互相注冊機(jī)制
,將每個(gè)治理服務(wù)器所管轄的服務(wù)信息列表進(jìn)行交換
,使服務(wù)治理服務(wù)擁有更高的可用性。
1.2、 什么是Eureka
Eureak
是Netflix
開源微服務(wù)框架中一系列項(xiàng)目中的一個(gè)。Spring Cloud
對其進(jìn)行了二次封裝,形成了Spring Cloud Netflix
子項(xiàng)目,但未對Netflix
微服務(wù)實(shí)現(xiàn)原理進(jìn)行更改,只是進(jìn)行了Spring Boot
化,使開發(fā)者更容易使用和整合。
在Eureka
中,對于服務(wù)治理有如下3個(gè)概念:
- 服務(wù)治理服務(wù)器(Eureka服務(wù)器) :Eureka采用了CS的設(shè)計(jì)架構(gòu),Eureka Server 作為服務(wù)注冊功能的服務(wù)器,也就是服務(wù)注冊中心(這里的Eureka Server指的是我們自己專門寫一個(gè)Java應(yīng)用來引用Eureka Server的依賴,將這個(gè)應(yīng)用作為注冊中心)。而系統(tǒng)中的其他微服務(wù),使用 Eureka的客戶端連接到 Eureka Server并維持心跳連接。這樣系統(tǒng)的維護(hù)人員就可以通過 Eureka Server 來監(jiān)控系統(tǒng)中各個(gè)微服務(wù)是否正常運(yùn)行。
- 服務(wù)注冊代理(服務(wù)提供者):如果一個(gè)微服務(wù)是一個(gè)服務(wù)提供者,那么可以通過服務(wù)注冊代理將服務(wù)配置信息注冊到治理服務(wù)器上。服務(wù)注冊代理可以理解為一個(gè)Eureka客戶端,負(fù)責(zé)將微服務(wù)所提供的服務(wù)向Eureka服務(wù)器執(zhí)行注冊、續(xù)約和注銷等操作,以使服務(wù)消費(fèi)者可以發(fā)現(xiàn)并進(jìn)行消費(fèi)。在服務(wù)注冊時(shí)需要向服務(wù)治理服務(wù)器提供服務(wù)名稱、宿主服務(wù)器IP地址、服務(wù)端口號、域名等主要數(shù)據(jù)。
- 服務(wù)發(fā)現(xiàn)客戶端(服務(wù)消費(fèi)者):也是一個(gè)Eureka客戶端。它在啟動(dòng)時(shí)會(huì)默認(rèn)從所服務(wù)治理服務(wù)器中獲取所有的服務(wù)注冊表信息,通過所獲取到的服務(wù)注冊列表信息來消費(fèi)相應(yīng)的服務(wù)。
1.3、 Eureka包含兩個(gè)組件
Eureka Server提供注冊服務(wù)功能
各個(gè)微服務(wù)節(jié)點(diǎn)通過配置啟動(dòng)后,會(huì)在EurekaServer中進(jìn)行注冊,這樣EurekaServer中的服務(wù)注冊表中將會(huì)存儲所有可用服務(wù)節(jié)點(diǎn)的信息,服務(wù)節(jié)點(diǎn)的信息可以在界面中直觀看到。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
EurekaClient通過注冊中心進(jìn)行訪問
EurekaClient可以分為提供者和消費(fèi)者,他們都是一個(gè)Java客戶端,客戶端同時(shí)也具備一個(gè)內(nèi)置的、使用輪詢(round-robin)負(fù)載算法的負(fù)載均衡器。在應(yīng)用啟動(dòng)后,將會(huì)向Eureka Server發(fā)送心跳(默認(rèn)周期為30秒)。如果Eureka Server在多個(gè)心跳周期內(nèi)沒有接收到某個(gè)節(jié)點(diǎn)的心跳,EurekaServer將會(huì)從服務(wù)注冊表中把這個(gè)服務(wù)節(jié)點(diǎn)移除(默認(rèn)90秒)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
1.4、 什么場景使用Eureka
準(zhǔn)確來說是什么場景需要使用注冊中心:
大并發(fā)量的應(yīng)用情況下就需要搭建集群(這里的集群指的不是Eureka注冊中心集群,而是指的微服務(wù)各個(gè)模塊的集群),搭建集群我們就需要通過注冊中心來實(shí)時(shí)掌握每個(gè)應(yīng)用的情況,如果根本沒有大并發(fā)場景,項(xiàng)目雖然也拆分了服務(wù),但是用不到集群,那我們大可不必使用注冊中心,使用注冊中心從某種意義上來講,增加了程序的復(fù)雜度,而且還得時(shí)刻維護(hù)注冊中心,有點(diǎn)大材小用了。
1.5、 Eureka停更
關(guān)于停更問題我在這篇博客已經(jīng)講的很清楚了:https://blog.csdn.net/weixin_43888891/article/details/125193088?spm=1001.2014.3001.5501
1.6、代碼要實(shí)現(xiàn)的內(nèi)容
二、單機(jī)Eureka構(gòu)建步驟
使用Eureka那就意味著一定是微服務(wù)架構(gòu),這就涉及到了聚合工程,本篇博客的代碼完全是基于本人上一篇博客 搭建的聚合工程 來進(jìn)行開發(fā)的。
idea聚合工程搭建詳解:https://blog.csdn.net/weixin_43888891/article/details
2.1、搭建Eureka Server
1、建Module:cloud-eureka-server7001
2、改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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>mscloud</artifactId><groupId>com.gzl.cn</groupId><version>1.0-SNAPSHOT</version></parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-eureka-server7001</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- 引入自己定義的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>com.gzl.cn</groupId> <artifactId>cloud-api-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--boot web actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--一般通用配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> </project>
3、寫YML
server: port: 7001 eureka: instance: hostname: localhost #eureka服務(wù)端的實(shí)例名稱 client: #false表示不向注冊中心注冊自己。 register-with-eureka: false #false表示自己端就是注冊中心,我的職責(zé)就是維護(hù)服務(wù)實(shí)例,并不需要去檢索服務(wù) fetch-registry: false service-url: #設(shè)置與Eureka Server交互的地址查詢服務(wù)和注冊服務(wù)都需要依賴這個(gè)地址。 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4、主啟動(dòng)類
@SpringBootApplication @EnableEurekaServer public class EurekaSever7001Application { public static void main(String[] args) { SpringApplication.run(EurekaSever7001Application.class, args); } }
5、啟動(dòng)測試
2.2、搭建Eureka Client端的提供者
這里我們直接接著上一篇文章中的cloud-provider-payment8001服務(wù)進(jìn)行調(diào)整
1、在原有cloud-provider-payment8001服務(wù)的pom當(dāng)中添加以下依賴
<!--eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
2、添加yml
eureka: client: #表示是否將自己注冊進(jìn)EurekaServer默認(rèn)為true。 register-with-eureka: true #是否從EurekaServer抓取已有的注冊信息,默認(rèn)為true。單節(jié)點(diǎn)無所謂,集群必須設(shè)置為true才能配合ribbon使用負(fù)載均衡 fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
3、啟動(dòng)類添加注解
@EnableEurekaClient
4、測試
先要啟動(dòng)EurekaServer確保 //localhost:7001/ 可以訪問 然后再啟動(dòng)cloud-provider-payment8001
微服務(wù)注冊名配置說明:
5、自我保護(hù)機(jī)制
下面一排紅字不用管,他是Eureka的自我保護(hù)機(jī)制,在最文章后面我會(huì)具體講他的作用。
2.3、搭建Eureka Client端的消費(fèi)者
這里我們直接接著上一篇文章中的cloud-provider-payment8001服務(wù)進(jìn)行調(diào)整
1、在原有cloud-consumer-order80服務(wù)的pom當(dāng)中添加以下依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
2、添加yml
eureka: client: #表示是否將自己注冊進(jìn)EurekaServer默認(rèn)為true。 register-with-eureka: true #是否從EurekaServer抓取已有的注冊信息,默認(rèn)為true。單節(jié)點(diǎn)無所謂,集群必須設(shè)置為true才能配合ribbon使用負(fù)載均衡 fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
3、啟動(dòng)類添加注解
@EnableEurekaClient
4、測試
先要啟動(dòng)EurekaServer, 7001服務(wù) 再啟動(dòng)服務(wù)提供者provider, 8001服務(wù) 最后啟動(dòng)服務(wù)消費(fèi)者consumer,80服務(wù) 訪問://localhost/consumer/payment/get/1
三、Eureka集群
通過上面的練習(xí),我們會(huì)發(fā)現(xiàn)根本沒體會(huì)到Eureka作用是什么,沒有Eureka服務(wù)照樣可以運(yùn)行使用,這也就是上面提到的,假如微服務(wù)不使用集群的話,完全沒必要使用注冊中心。下面我們進(jìn)行分別搭建Eureka集群,和微服務(wù)集群。
3.1、Eureka集群原理說明
微服務(wù)RPC遠(yuǎn)程服務(wù)調(diào)用最核心的是什么
高可用,試想你的注冊中心只有一個(gè)only one, 它出故障了那就呵呵( ̄▽ ̄)"了,會(huì)導(dǎo)致整個(gè)為服務(wù)環(huán)境不可用,所以需要搭建Eureka集群
3.2、EurekaServer集群環(huán)境構(gòu)建步驟
1、參考cloud-eureka-server7001 新建 cloud-eureka-server7002(直接復(fù)制就行)
2、改pom
3、父工程的pom當(dāng)中添加model
正常通過ide創(chuàng)建,他是會(huì)自動(dòng)在父工程添加model的,而我們是復(fù)制的所以需要手動(dòng)添加
4、修改啟動(dòng)名字:EurekaSever7002Application
5、修改映射配置
添加:
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com
6、修改yml(7001和7002都需要修改),由于7002是直接復(fù)制的,所以7002的yml端口號需要改成7002
7002主要是修改端口和hostname,,7001的yml當(dāng)中的hostname修改為eureka7001.com
server: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服務(wù)端的實(shí)例名稱
7、將 支付服務(wù)8001微服務(wù) 和 訂單服務(wù)80微服務(wù) 發(fā)布到上面2臺Eureka集群配置中(兩個(gè)服務(wù)都需要修改yml)
http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
8、測試
先要啟動(dòng)EurekaServer, 7001/7002服務(wù) //eureka7001.com:7001/ 再要啟動(dòng)服務(wù)提供者provider, 8001 再要啟動(dòng)消費(fèi)者,80 訪問://localhost/consumer/payment/get/1
3.3、支付服務(wù)提供者8001集群環(huán)境構(gòu)建
1、參考cloud-provider-payment8001 新建 cloud-provider-payment8002(直接復(fù)制就行) 2、改pom
3、父工程的pom當(dāng)中添加model
4、修改啟動(dòng)名字:PaymentMain8002 5、修改yml(主要就是修改端口號為8002) 6、修改8001/8002的Controller
主要是方便區(qū)分我們調(diào)用的是哪個(gè)服務(wù)
3.4、調(diào)整80消費(fèi)服務(wù)
1、訂單服務(wù)訪問地址不能寫死
// 通過在eureka上注冊過的微服務(wù)名稱調(diào)用 public static final String PaymentSrv_URL = "http://CLOUD-PAYMENT-SERVICE";
2、使用@LoadBalanced注解賦予RestTemplate負(fù)載均衡的能力
spring-cloud-starter-netflix-eureka-client
依賴當(dāng)中就依賴了ribbon
依賴,所以我們不用添加ribbon
依賴就能使用他的注解。
一旦地址改為以服務(wù)名稱訪問的形式"//CLOUD-PAYMENT-SERVICE
",就必須添加這個(gè)負(fù)載均衡的注解,不然訪問80服務(wù)的接口就會(huì)報(bào)錯(cuò)。
3、測試
先要啟動(dòng)EurekaServer, 7001/7002服務(wù)再要啟動(dòng)服務(wù)提供者provider, 8001/8002服務(wù)然后最后啟動(dòng)80服務(wù)訪問://localhost/consumer/payment/get/31 多次訪問這個(gè)接口,返回的日志當(dāng)中的端口號會(huì)交替出現(xiàn),這就是負(fù)載均衡。當(dāng)服務(wù)提供者8001和8002任意一個(gè)掛掉之后,并不會(huì)影響服務(wù)調(diào)用。Ribbon和Eureka整合后Consumer可以直接調(diào)用服務(wù)而不用再關(guān)心地址和端口號,且該服務(wù)還有負(fù)載功能了。
3.5、Eureka集群嚴(yán)重問題
在測試過程發(fā)現(xiàn)的問題,所以記錄一下!
這時(shí)候會(huì)發(fā)現(xiàn)所有服務(wù)全注冊到了7001,而7002實(shí)際上并沒有服務(wù),當(dāng)我們把7001服務(wù)關(guān)閉后,會(huì)發(fā)現(xiàn)過一段時(shí)間服務(wù)自動(dòng)就注冊到了7002,可能需要個(gè)幾秒,這幾秒的過程當(dāng)中如果調(diào)用服務(wù)是會(huì)報(bào)錯(cuò)的!
為什么會(huì)都優(yōu)先注冊到7001而不是7002呢?跟配置文件寫的順序有關(guān)!
假設(shè)7001注冊中心掛掉的同時(shí)8001服務(wù)也掛掉了,然后先恢復(fù)7001服務(wù),然后再恢復(fù)8001服務(wù)。這時(shí)候會(huì)出現(xiàn)以下情況。8001注冊到了7001注冊中心,而其他沒有掛掉的服務(wù),由于7001掛掉了之后注冊在7001的服務(wù)全部轉(zhuǎn)移到了7002注冊中心。
這個(gè)時(shí)候會(huì)引發(fā)一個(gè)非常嚴(yán)重的問題,就是服務(wù)提供者的集群失效!
多次訪問80服務(wù)的接口,會(huì)發(fā)現(xiàn)一直是調(diào)用的8002服務(wù),他不會(huì)去調(diào)用8001,因?yàn)?0服務(wù)注冊在了7002注冊中心,而8001注冊在了7001注冊中心,服務(wù)都不在一個(gè)注冊中心,所以他根本調(diào)用不了。
解決辦法: 假如注冊中心和一個(gè)服務(wù)掛掉之后,一定要先想辦法先恢復(fù)服務(wù),而不是先恢復(fù)掛掉的注冊中心!先恢復(fù)8001服務(wù)的話,他會(huì)直接注冊到7002注冊中心,就完全避免了這樣的問題。當(dāng)然這里啟動(dòng)8001服務(wù)的時(shí)候會(huì)報(bào)錯(cuò)但是不影響的,因?yàn)樗麊?dòng)的時(shí)候會(huì)先去注冊到7001,然后發(fā)現(xiàn)7001掛掉了這時(shí)候會(huì)報(bào)錯(cuò),然后自動(dòng)注冊到7002。
從這個(gè)問題也間接的會(huì)發(fā)現(xiàn),微服務(wù)框架當(dāng)中,有時(shí)候程序啟動(dòng)的先后順序至關(guān)重要!
3.6、主機(jī)名稱修改 和 ip提示
1、主機(jī)名稱修改
這里一個(gè)是應(yīng)用名稱,一個(gè)是主機(jī)名稱
2、ip提示
當(dāng)我們服務(wù)多了,有時(shí)候以應(yīng)用名稱根本無法快速鎖定他在哪臺服務(wù)器部署,所以可以添加以下配置。
3.7、服務(wù)發(fā)現(xiàn)Discovery
對于注冊進(jìn)eureka里面的微服務(wù),可以通過服務(wù)發(fā)現(xiàn)來獲得該服務(wù)的信息
在8001的PaymentController添加一個(gè)接口:
DiscoveryClient 導(dǎo)包的時(shí)候?qū)旅娴陌?/p>
import org.springframework.cloud.client.discovery.DiscoveryClient;
@Resource private DiscoveryClient discoveryClient; @GetMapping(value = "/payment/discovery") public Object discovery() { // 獲取注冊的服務(wù) List<String> services = discoveryClient.getServices(); for (String element : services) { System.out.println(element); } // 根據(jù)服務(wù)名稱獲取服務(wù)詳細(xì)信息 List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance element : instances) { System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t" + element.getUri()); } return this.discoveryClient; }
測試://localhost:8001/payment/discovery 訪問后看控制臺輸出內(nèi)容!
四、Eureka心跳機(jī)制
4.1、什么是心跳機(jī)制
在了解保護(hù)機(jī)制之前,我們有必要先了解一下Eureka的心跳機(jī)制。
使用注冊中心,那我們的服務(wù)信息就需要注冊到注冊中心,注冊中心起到的作用是服務(wù)治理,那他就需要時(shí)刻掌握服務(wù)是否宕機(jī),心跳機(jī)制就是Eureka client一旦注冊到注冊中心后,就需要每隔一段時(shí)間告訴Eureka server一下,我還是活的。
4.2、Eureka Client心跳頻率配置
在每一個(gè)Eureka Client啟動(dòng)的時(shí)候,都會(huì)有一個(gè)HeartbeatThread的心跳線程,這個(gè)線程的作用就是保證默認(rèn)30秒
的時(shí)候向Eureka Server發(fā)送一個(gè)信息的請求,告訴Eureka Server當(dāng)前的Eureka Client還存活著。
下面這個(gè)參數(shù)可以來配置心跳間隔時(shí)間(這個(gè)是在Eureka的client端配置的):
eureka: instance: lease-renewal-interval-in-seconds: 30
4.3、Eureka Server端接收到心跳做了什么操作
Eureka Server在接收到請求之后,肯定是先去自己的注冊表中去,找到請求的對應(yīng)的服務(wù)信息,在這個(gè)服務(wù)信息里面有個(gè)Lease的對象,這個(gè)里面就是可以進(jìn)行心跳續(xù)約操作的,更新Lease對象里面的LastUpdateTimestamp時(shí)間戳,每一次接收到都會(huì)更新這個(gè)時(shí)間戳的。
4.4、Eureka Server查看心跳是否收到
Eureka Server在啟動(dòng)的時(shí)候啟動(dòng)的時(shí)候會(huì)每60秒遍歷一次注冊表中的信息,然后查看注冊表中的信息是否有過期的,如果過期會(huì)加入到一個(gè)列表里面單獨(dú)處理。
清理間隔時(shí)間配置(單位毫秒,默認(rèn)是60*1000,在Eureka的server端配置的):
eureka: server: eviction-interval-timer-in-ms: 60
4.5、Eureka Client心跳最大等待時(shí)間
Eureka服務(wù)端在收到最后一次心跳后等待時(shí)間上限,單位為秒(默認(rèn)是90秒),超時(shí)將剔除服務(wù)
。 通過下面可以配置等待時(shí)間(這個(gè)是在Eureka的client端配置的):
eureka: instance: lease-expiration-duration-in-seconds: 90
4.6、總結(jié)
通過以上了解,我們一共接觸了三個(gè)時(shí)間配置,一個(gè)是注冊中心的掃描過期時(shí)間
,掃描過期時(shí)間就好比,租車公司要定期查看哪些車租聘日到期了,需要進(jìn)行收回。還有一個(gè)客戶端設(shè)置的 租期更新時(shí)間間隔
,這個(gè)時(shí)間就是租戶需要隔一段時(shí)間告訴租聘公司,我還要繼續(xù)租這個(gè)車,還有一個(gè)是租期到期時(shí)間
,這個(gè)時(shí)間就是假如客戶端超過這個(gè)時(shí)間沒有給租聘公司發(fā)送心跳,那么就認(rèn)為不租了。
server端: eureka.server.eviction-interval-timer-in-ms//清理間隔(單位毫秒,默認(rèn)是60*1000) client端: eureka.instance.lease-renewal-interval-in-seconds =10//租期更新時(shí)間間隔(默認(rèn)30秒) eureka.instance.lease-expiration-duration-in-seconds =30//租期到期時(shí)間(默認(rèn)90秒)
五、Eureka自我保護(hù)機(jī)制
首先明確觀點(diǎn):Eureka自我保護(hù)機(jī)制有很多bug,而且中文資料很缺乏,網(wǎng)上普遍是一篇博客抄來抄去的,本人通過案例也確實(shí)發(fā)現(xiàn)很多bug的地方,如果鉆牛角尖的話,可能幾天都學(xué)不完!
5.1、什么是自我保護(hù)機(jī)制
保護(hù)模式主要用于一組客戶端和Eureka Server之間存在網(wǎng)絡(luò)分區(qū)場景下的保護(hù)
。為了防止EurekaClient可以正常運(yùn)行,但是 與 EurekaServer網(wǎng)絡(luò)不暢通情況下(網(wǎng)絡(luò)延遲等原因),在保護(hù)模式開啟的情況下,EurekaServer不會(huì)立刻將EurekaClient服務(wù)剔除。
如果在Eureka Server的首頁看到以下這段提示,則說明Eureka進(jìn)入了保護(hù)模式:
這個(gè)需要在注冊中心配置的!
server: #關(guān)閉自我保護(hù)機(jī)制,保證不可用服務(wù)被及時(shí)踢除,默認(rèn)為true開啟的 enable-self-preservation: false
5.2、為什么會(huì)出現(xiàn)自我保護(hù)機(jī)制
一句話:某時(shí)刻某一個(gè)微服務(wù)因?yàn)榫W(wǎng)絡(luò)原因不可用了,Eureka不會(huì)立刻清理,依舊會(huì)對該微服務(wù)的信息進(jìn)行保存,屬于CAP里面的AP分支。
因?yàn)榫W(wǎng)絡(luò)通信是可能恢復(fù)的,但是Eureka客戶端只會(huì)在啟動(dòng)時(shí)才去服務(wù)端注冊。如果因?yàn)榫W(wǎng)絡(luò)的原因而剔除了客戶端,將造成客戶端無法再注冊到服務(wù)端。為了避免此問題,Eureka提供了自我保護(hù)機(jī)制。
CAP即:
- Consistency(一致性)
- Availability(可用性)
- Partition tolerance(分區(qū)容忍性)
清理?xiàng)l件:
- Eureka服務(wù)端會(huì)檢查最近15分鐘內(nèi)所有Eureka 實(shí)例正常心跳占比(這個(gè)15分鐘是在源碼當(dāng)中有個(gè)每15分鐘執(zhí)行一次的定時(shí)任務(wù)),如果低于85%就會(huì)觸發(fā)自我保護(hù)機(jī)制。
- 觸發(fā)了保護(hù)機(jī)制,Eureka將暫時(shí)把這些失效的服務(wù)保護(hù)起來,不讓其過期,但這些服務(wù)也并不是永遠(yuǎn)不會(huì)過期(該現(xiàn)象可能出現(xiàn)在如果網(wǎng)絡(luò)不通但是EurekaClient未出現(xiàn)巖機(jī))。
- Eureka在啟動(dòng)完成后,每隔60秒會(huì)檢查一次服務(wù)健康狀態(tài)(這個(gè)60秒就是上面提到的Eureka Server查看心跳是否收到默認(rèn)的配置)
- 如果這些被保護(hù)起來失效的服務(wù)過一段時(shí)間后(默認(rèn)90秒,這個(gè)90秒就是上面提到的心跳最大等待時(shí)間)還是沒有恢復(fù),就會(huì)把這些服務(wù)剔除。如果在此期間服務(wù)恢復(fù)了并且實(shí)例心跳占比高于85%時(shí),就會(huì)自動(dòng)關(guān)閉自我保護(hù)機(jī)制。
- 此時(shí)如果換做別的注冊中心如果一定時(shí)間內(nèi)沒有收到心跳會(huì)將剔除該服務(wù),這樣就出現(xiàn)了嚴(yán)重失誤,因?yàn)榭蛻舳诉€能正常發(fā)送心跳,只是網(wǎng)絡(luò)延遲問題,而保護(hù)機(jī)制是為了解決此問題而產(chǎn)生的。它的設(shè)計(jì)哲學(xué)就是寧可保留錯(cuò)誤的服務(wù)注冊信息,也不盲目注銷任何可能健康的服務(wù)實(shí)例。一句話講解:好死不如賴活著
綜上,自我保護(hù)模式是一種
應(yīng)對網(wǎng)絡(luò)異常的安全保護(hù)措施
。它的架構(gòu)哲學(xué)是寧可同時(shí)保留所有微服務(wù)(健康的微服務(wù)和不健康的微服務(wù)都會(huì)保留)也不盲目注銷任何健康的微服務(wù)。使用自我保護(hù)模式,可以讓Eureka集群更加的健壯、穩(wěn)定。
5.3、如何選擇關(guān)閉還是開啟自我保護(hù)機(jī)制
Eureka服務(wù)端默認(rèn)情況下是會(huì)開啟自我保護(hù)機(jī)制的。但我們在不同環(huán)境應(yīng)該選擇是否開啟保護(hù)機(jī)制。
自我保護(hù)機(jī)制的配置是(默認(rèn)是開啟的):eureka.server.enable-self-preservation=true
一般情況下,我們會(huì)選擇在 開發(fā)環(huán)境下關(guān)閉自我保護(hù)機(jī)制,而在生產(chǎn)環(huán)境下啟動(dòng)自我保護(hù)機(jī)制。
開發(fā)環(huán)境下,我們我們啟動(dòng)的服務(wù)數(shù)量較少而且會(huì)經(jīng)常修改重啟。如果開啟自我保護(hù)機(jī)制,很容易觸發(fā)Eureka客戶端心跳占比低于85%的情況。使得Eureka不會(huì)剔除我們的服務(wù),從而在我們訪問的時(shí)候,會(huì)訪問到可能已經(jīng)失效的服務(wù),導(dǎo)致請求失敗,影響我們的開發(fā)。
在生產(chǎn)環(huán)境下,我們啟動(dòng)的服務(wù)多且不會(huì)反復(fù)啟動(dòng)修改。環(huán)境也相對穩(wěn)定,影響服務(wù)正常運(yùn)行的人為情況較少。適合開啟自我保護(hù)機(jī)制,讓Eureka進(jìn)行管理。
5.4、Eureka控制臺參數(shù)
如下我啟動(dòng)了3個(gè)服務(wù):
Lease expiration enabled:Eureka自動(dòng)保護(hù)機(jī)制啟動(dòng)后該值為false。
Renews threshold:Eureka Server 期望每分鐘收到客戶端實(shí)例續(xù)約的閱值。
Renews threshold = 服務(wù)實(shí)例總數(shù) *(60/續(xù)約間隔)*自我保護(hù)續(xù)約百分比閾值因子(閾值因子默認(rèn)85%,續(xù)約間隔默認(rèn)是30)。
Renews (last min): Eureka Server 最后1分鐘收到客戶端實(shí)例續(xù)約的總數(shù)。
Renews(last min) = 服務(wù)實(shí)例總數(shù) * (60/續(xù)約間隔)
如果自我保護(hù)模式開啟了,且當(dāng)續(xù)約閾值>0,上一分鐘的續(xù)約數(shù)>閾值,那么可以清理。言外之意就是,當(dāng)上一分鐘續(xù)約數(shù)<閾值,那么就不清理(保護(hù)了)
(Renews (last min) < Renews threshold)
5.5、測試開啟了自我保護(hù)機(jī)制
什么都沒配置,只是啟動(dòng)了三個(gè)服務(wù),然后等了一會(huì)就進(jìn)入保護(hù)模式了。對于這一點(diǎn)我也不是很理解。進(jìn)入保護(hù)模式后,我隨便關(guān)掉了一個(gè)服務(wù),Eureka控制臺上也就幾秒鐘立馬就消失了,并沒有向上面所說的,進(jìn)入保護(hù)模式后,不會(huì)輕易移除服務(wù)!
我開啟了自我保護(hù)機(jī)制,并且給每個(gè)要注冊的服務(wù)設(shè)置如下配置:
eureka: instance: #Eureka服務(wù)端在收到最后一次心跳后等待時(shí)間上限,單位為秒(默認(rèn)是90秒),超時(shí)將剔除服務(wù) lease-expiration-duration-in-seconds: 2 #Eureka客戶端向服務(wù)端發(fā)送心跳的時(shí)間間隔,單位為秒(默認(rèn)是30秒) lease-renewal-interval-in-seconds: 1
注意要觀察Renews (last min)和Renews threshold值的時(shí)候,啟動(dòng)項(xiàng)目后一定要等個(gè)1分鐘才可以,等一分鐘過后如下:
Renews threshold完全跟上面提到的算法是不一致的,而且差距還很大,而Renews (last min)卻差距不是很大。針對于此問題,我也搜了很多相關(guān)資料,由于Eureka已經(jīng)停更,很多人已經(jīng)棄用,并沒有太多的人關(guān)注這個(gè)問題了。
當(dāng)我關(guān)閉8001服務(wù)的時(shí)候,Eureka上的8001服務(wù)并沒有立馬消失,而是停留了幾秒鐘,狀態(tài)顯示的是DOWN。
5.6、關(guān)閉自我保護(hù)機(jī)制
eureka: server: enable-self-preservation: false
關(guān)閉后,啟動(dòng)注冊中心就會(huì)看到以下字樣!
六、Eureka健康檢查
由于server和client通過心跳保持服務(wù)狀態(tài),而只有狀態(tài)為UP的服務(wù)才能被訪問 看eureka界面中的status
比如心跳一直正常,服務(wù)一直UP,但是此服務(wù)DB連不上了,無法正常提供服務(wù)
我們需要將微服務(wù)的健康狀態(tài)也同步到server只需要啟動(dòng)eureka的健康檢查這樣微服務(wù)就會(huì)將自己的健康狀態(tài)同步到eureka
這個(gè)需要在Eureka client端設(shè)置,而且默認(rèn)就是開啟的。
eureka: client: healthcheck: enabled: true
剛開始我以為是只要這個(gè)設(shè)置true,然后當(dāng)服務(wù)的mysql掛掉后,會(huì)自動(dòng)更新注冊中心的狀態(tài),然后可以避免其他服務(wù)調(diào)用異常的服務(wù),然而并不是,他還需要配置很多東西,并沒有我想象的那么神奇!
到此這篇關(guān)于關(guān)于Eureka的概念作用以及用法詳解的文章就介紹到這了,更多相關(guān)Eureka概念作用以及用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
maven項(xiàng)目打jar包并包含所有依賴詳細(xì)教程
maven打包生成的普通jar包,只包含該工程下源碼編譯結(jié)果,不包含依賴內(nèi)容,下面這篇文章主要給大家介紹了關(guān)于maven項(xiàng)目打jar包并包含所有依賴的相關(guān)資料,需要的朋友可以參考下2023-05-05簡單捋捋@RequestParam 和 @RequestBody的使用
這篇文章主要介紹了簡單捋捋@RequestParam 和 @RequestBody的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12MyBatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充功能詳解
在開發(fā)中經(jīng)常遇到多個(gè)實(shí)體類有共同的屬性字段,這些字段屬于公共字段,也就是很多表中都有這些字段,能不能對于這些公共字段在某個(gè)地方統(tǒng)一處理,來簡化開發(fā)呢?MyBatis-Plus就提供了這一功能,本文就來為大家詳細(xì)講講2022-08-08詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue
這篇文章主要為大家詳細(xì)介紹了Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue的相關(guān)資料,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-12-12java中for循環(huán)執(zhí)行的順序圖文詳析
關(guān)于java的for循環(huán)想必大家非常熟悉,它是java常用的語句之一,這篇文章主要給大家介紹了關(guān)于java中for循環(huán)執(zhí)行順序的相關(guān)資料,需要的朋友可以參考下2021-06-06