一馏艾、Eureka簡(jiǎn)介
本文中所有代碼都會(huì)上傳到git上个绍,請(qǐng)放心瀏覽
項(xiàng)目git地址:https://github.com/839022478/Spring-Cloud
在傳統(tǒng)應(yīng)用中震缭,組件之間的調(diào)用仇矾,通過有規(guī)范的約束的接口來實(shí)現(xiàn)盘榨,從而實(shí)現(xiàn)不同模塊間良好的協(xié)作掏呼。但是被拆分成微服務(wù)后,每個(gè)微服務(wù)實(shí)例的網(wǎng)絡(luò)地址都可能動(dòng)態(tài)變化笼裳,數(shù)量也會(huì)變化唯卖,使得原來硬編碼的地址失去了作用。需要一個(gè)中心化的組件來進(jìn)行服務(wù)的登記和管理躬柬,為了解決上面的問題拜轨,于是出現(xiàn)了服務(wù)治理,就是管理所有的服務(wù)信息和狀態(tài)楔脯,也就是我們所說的注冊(cè)中心
1.1 注冊(cè)中心
比如我們?nèi)プ龌疖嚮蛘咂嚵煤洌枰ベI票乘車,只看我們有沒有票(有沒有服務(wù))昧廷,有就去買票(獲取注冊(cè)列表)堪嫂,然后乘車(調(diào)用),不用關(guān)心到底有多少車在運(yùn)行
流程圖:
使用注冊(cè)中心木柬,我們不需要關(guān)心有多少提供方皆串,只管去調(diào)用就可以了,那么注冊(cè)中心有哪些呢眉枕?
注冊(cè)中心:Eureka恶复,Nacos,Consul速挑,Zookeeper
本文中講解的是比較火熱的Spring Cloud微服務(wù)下的Eureka谤牡,Eureka是Netflix開發(fā)的服務(wù)發(fā)現(xiàn)框架,是一個(gè)RESTful風(fēng)格的服務(wù)姥宝,是一個(gè)用于服務(wù)發(fā)現(xiàn)和注冊(cè)的基礎(chǔ)組件翅萤,是搭建Spring Cloud微服務(wù)的前提之一,它屏蔽了Server和client的交互細(xì)節(jié)腊满,使得開發(fā)者將精力放到業(yè)務(wù)上套么。
服務(wù)注冊(cè)與發(fā)現(xiàn)主要包括兩個(gè)部分:服務(wù)端(Eureka Server)和客戶端(Eureka Client)
服務(wù)端(Eureka Server): 一個(gè)公共服務(wù),為Client提供服務(wù)注冊(cè)和發(fā)現(xiàn)的功能碳蛋,維護(hù)注冊(cè)到自身的Client的相關(guān)信息胚泌,同時(shí)提供接口給Client獲取注冊(cè)表中其他服務(wù)的信息,使得動(dòng)態(tài)變化的Client能夠進(jìn)行服務(wù)間的相互調(diào)用肃弟。
客戶端(Eureka Client): Client將自己的服務(wù)信息通過一定的方式登記到Server上玷室,并在正常范圍內(nèi)維護(hù)自己信息一致性零蓉,方便其他服務(wù)發(fā)現(xiàn)自己,同時(shí)可以通過Server獲取到自己依賴的其他服務(wù)信息阵苇,完成服務(wù)調(diào)用壁公,還內(nèi)置了負(fù)載均衡器感论,用來進(jìn)行基本的負(fù)載均衡
Eureka GIt官網(wǎng):https://github.com/Netflix/Eureka
1.3 服務(wù)注冊(cè)與發(fā)現(xiàn)
服務(wù)注冊(cè)與發(fā)現(xiàn)關(guān)系圖:
1.2 client功能和server功能
1.2.1 client功能
- 注冊(cè):每個(gè)微服務(wù)啟動(dòng)時(shí)绅项,將自己的網(wǎng)絡(luò)地址等信息注冊(cè)到注冊(cè)中心,注冊(cè)中心會(huì)存儲(chǔ)(內(nèi)存中)這些信息比肄。
- 獲取服務(wù)注冊(cè)表:服務(wù)消費(fèi)者從注冊(cè)中心快耿,查詢服務(wù)提供者的網(wǎng)絡(luò)地址,并使用該地址調(diào)用服務(wù)提供者芳绩,為了避免每次都查注冊(cè)表信息掀亥,所以client會(huì)定時(shí)去server拉取注冊(cè)表信息到緩存到client本地。
- 心跳:各個(gè)微服務(wù)與注冊(cè)中心通過某種機(jī)制(心跳)通信妥色,若注冊(cè)中心長(zhǎng)時(shí)間和服務(wù)間沒有通信搪花,就會(huì)注銷該實(shí)例。
- 調(diào)用:實(shí)際的服務(wù)調(diào)用嘹害,通過注冊(cè)表撮竿,解析服務(wù)名和具體地址的對(duì)應(yīng)關(guān)系,找到具體服務(wù)的地址笔呀,進(jìn)行實(shí)際調(diào)用幢踏。
1.2.2 server注冊(cè)中心功能
- 服務(wù)注冊(cè)表:記錄各個(gè)微服務(wù)信息,例如服務(wù)名稱许师,ip房蝉,端口等。
注冊(cè)表提供 查詢API(查詢可用的微服務(wù)實(shí)例)和管理API(用于服務(wù)的注冊(cè)和注銷)微渠。 - 服務(wù)注冊(cè)與發(fā)現(xiàn):注冊(cè):將微服務(wù)信息注冊(cè)到注冊(cè)中心搭幻。發(fā)現(xiàn):查詢可用微服務(wù)列表及其網(wǎng)絡(luò)地址。
- 服務(wù)檢查:定時(shí)檢測(cè)已注冊(cè)的服務(wù)逞盆,如發(fā)現(xiàn)某實(shí)例長(zhǎng)時(shí)間無法訪問檀蹋,就從注冊(cè)表中移除。
二纳击、Eureka單節(jié)點(diǎn)搭建
2.1 pom.xml
在有的教程中续扔,會(huì)引入spring-boot-starter-web
,這個(gè)依賴其實(shí)不用焕数,因?yàn)?code>spring-cloud-starter-netflix-eureka-server的依賴已經(jīng)包含了它纱昧,在pom依賴進(jìn)去,就可以了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2.2 application.yml
server:
port: 8500
eureka:
client:
#是否將自己注冊(cè)到Eureka Server,默認(rèn)為true堡赔,由于當(dāng)前就是server识脆,故而設(shè)置成false,表明該服務(wù)不會(huì)向eureka注冊(cè)自己的信息
register-with-eureka: false
#是否從eureka server獲取注冊(cè)信息,由于單節(jié)點(diǎn)灼捂,不需要同步其他節(jié)點(diǎn)數(shù)據(jù)离例,用false
fetch-registry: false
#設(shè)置服務(wù)注冊(cè)中心的URL,用于client和server端交流
service-url:
defaultZone: http://localhost:8080/eureka/
2.3 服務(wù)端啟動(dòng)類
啟動(dòng)類上添加此注解標(biāo)識(shí)該服務(wù)為配置中心
@EnableEurekaServer
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
2.4 啟動(dòng)
我們啟動(dòng)EurekaDemoApplication
悉稠,然后在瀏覽器中輸入地址 http://localhost:8500/
宫蛆,就可以啟動(dòng)我們的 Eureka 了,我們來看下效果的猛,出現(xiàn)了這個(gè)畫面耀盗,就說明我們已經(jīng)成功啟動(dòng)~,只是此時(shí)我們的服務(wù)中是還沒有客戶端進(jìn)行注冊(cè)
三卦尊、服務(wù)注冊(cè)
注意:在客戶端pom里面我們需要加上spring-boot-starter-web
叛拷,否則服務(wù)是無法正常啟動(dòng)的
3.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2 application.yml
#注冊(cè)中心
eureka:
client:
#設(shè)置服務(wù)注冊(cè)中心的URL
service-url:
defaultZone: http://localhost:8500/eureka/
#服務(wù)名
instance:
appname: mxn
3.3 客戶端啟動(dòng)類
在客戶端啟動(dòng)類中我們需要加上 @EnableDiscoveryClient
注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
3.4 查看效果
工程啟動(dòng)后,刷新http://localhost:8500/
頁面岂却,我們可以發(fā)現(xiàn)服務(wù)注冊(cè)成功了
并且我們可以在idea日志打印中看到DiscoveryClient_MXN/DESKTOP-5BQ3UK8 - registration status: 204
,說明就是注冊(cè)成功了
Eureka Server與Eureka Client之間的聯(lián)系主要通過心跳的方式實(shí)現(xiàn)忿薇。心跳(Heartbeat)即Eureka Client定時(shí)向Eureka Server匯報(bào)本服務(wù)實(shí)例當(dāng)前的狀態(tài),維護(hù)本服務(wù)實(shí)例在注冊(cè)表中租約的有效性躏哩。
Eureka Client將定時(shí)從Eureka Server中拉取注冊(cè)表中的信息署浩,并將這些信息緩存到本地,用于服務(wù)發(fā)現(xiàn)
四震庭、Eureka 端點(diǎn)
官網(wǎng)地址:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
Eureka服務(wù)器還提供了一個(gè)端點(diǎn)(eureka/apps/{applicaitonName})
可以查看所注冊(cè)的服務(wù)詳細(xì)信息 瑰抵。applicaitonName就是微服務(wù)的名稱,比如這里我們?cè)L問 http://localhost:8500/eureka/apps/mxn
五器联、Eureka 原理
5.1 本質(zhì)
存儲(chǔ)了每個(gè)客戶端的注冊(cè)信息二汛。EurekaClient從EurekaServer同步獲取服務(wù)注冊(cè)列表。通過一定的規(guī)則選擇一個(gè)服務(wù)進(jìn)行調(diào)用
5.2 Eureka架構(gòu)圖
- 服務(wù)提供者: 是一個(gè)eureka client拨拓,向Eureka Server注冊(cè)和更新自己的信息肴颊,同時(shí)能從Eureka Server注冊(cè)表中獲取到其他服務(wù)的信息。
- 服務(wù)注冊(cè)中心: 提供服務(wù)注冊(cè)和發(fā)現(xiàn)的功能渣磷。每個(gè)Eureka Cient向Eureka Server注冊(cè)自己的信息婿着,也可以通過Eureka Server獲取到其他服務(wù)的信息達(dá)到發(fā)現(xiàn)和調(diào)用其他服務(wù)的目的。
- 服務(wù)消費(fèi)者: 是一個(gè)eureka client醋界,通過Eureka Server獲取注冊(cè)到其上其他服務(wù)的信息竟宋,從而根據(jù)信息找到所需的服務(wù)發(fā)起遠(yuǎn)程調(diào)用。
- 同步復(fù)制: Eureka Server之間注冊(cè)表信息的同步復(fù)制形纺,使Eureka Server集群中不同注冊(cè)表中服務(wù)實(shí)例信息保持一致丘侠。
- 遠(yuǎn)程調(diào)用: 服務(wù)客戶端之間的遠(yuǎn)程調(diào)用。
- 注冊(cè): Client端向Server端注冊(cè)自身的元數(shù)據(jù)以供服務(wù)發(fā)現(xiàn)逐样。
- 續(xù)約: 通過發(fā)送心跳到Server以維持和更新注冊(cè)表中服務(wù)實(shí)例元數(shù)據(jù)的有效性蜗字。當(dāng)在一定時(shí)長(zhǎng)內(nèi)打肝,Server沒有收到Client的心跳信息,將默認(rèn)服務(wù)下線挪捕,會(huì)把服務(wù)實(shí)例的信息從注冊(cè)表中刪除粗梭。
- 下線: Client在關(guān)閉時(shí)主動(dòng)向Server注銷服務(wù)實(shí)例元數(shù)據(jù),這時(shí)Client的服務(wù)實(shí)例數(shù)據(jù)將從Server的注冊(cè)表中刪除级零。
- 獲取注冊(cè)表: Client向Server請(qǐng)求注冊(cè)表信息断医,用于服務(wù)發(fā)現(xiàn),從而發(fā)起服務(wù)間遠(yuǎn)程調(diào)用妄讯。
5.3 Eureka自我保護(hù)
有時(shí)候我們會(huì)看到這樣的提示信息: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.
孩锡,這是因?yàn)槟J(rèn)情況下,Eureka Server在一定時(shí)間內(nèi)亥贸,沒有接收到某個(gè)微服務(wù)心跳,會(huì)將某個(gè)微服務(wù)注銷(90S)浇垦。但是當(dāng)網(wǎng)絡(luò)故障時(shí)炕置,微服務(wù)與Server之間無法正常通信,上述行為就非常危險(xiǎn)男韧,因?yàn)槲⒎?wù)正常朴摊,不應(yīng)該注銷,它的指導(dǎo)思想就是 寧可保留健康的和不健康的此虑,也不盲目注銷任何健康的服務(wù)
我們也可以通過命令去關(guān)閉自我保護(hù)的功能:
eureka:
server:
enable-self-preservation: false
那么自我保護(hù)是如何觸發(fā)的呢甚纲?
自我保護(hù)機(jī)制的觸發(fā)條件是,當(dāng)每分鐘心跳次數(shù)( renewsLastMin
) 小于 numberOfRenewsPerMinThreshold
時(shí)朦前,并且開啟自動(dòng)保護(hù)模式開關(guān)( eureka.server.enable-self-preservation = true
) 時(shí)介杆,觸發(fā)自我保護(hù)機(jī)制,不再自動(dòng)過期租約
上面我們所有的小于 numberOfRenewsPerMinThreshold
韭寸,到底是怎么計(jì)算的呢春哨,我們?cè)趀ureka源碼中可以得知
numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 續(xù)租百分比(默認(rèn)為0.85)
expectedNumberOfRenewsPerMin = 當(dāng)前注冊(cè)的應(yīng)用實(shí)例數(shù) x 2
當(dāng)前注冊(cè)的應(yīng)用實(shí)例數(shù) x 2 是因?yàn)椋谀J(rèn)情況下恩伺,注冊(cè)的應(yīng)用實(shí)例每半分鐘續(xù)租一次赴背,那么一分鐘心跳兩次,因此 x 2
例如:我們有10個(gè)服務(wù)晶渠,期望每分鐘續(xù)約數(shù):10 * 2=20凰荚,期望閾值:20*0.85=17,當(dāng)少于17時(shí)褒脯,就會(huì)觸發(fā)自我保護(hù)機(jī)制
5.4 健康檢查
由于server和client通過心跳保持 服務(wù)狀態(tài)便瑟,而只有狀態(tài)為UP的服務(wù)才能被訪問『┑撸看eureka界面中的status胳徽。
比如心跳一直正常积锅,服務(wù)一直UP,但是此服務(wù)DB(數(shù)據(jù)庫)連不上了养盗,無法正常提供服務(wù)缚陷。
此時(shí),我們需要將 微服務(wù)的健康狀態(tài)也同步到server往核。只需要啟動(dòng)eureka的健康檢查就行箫爷。這樣微服務(wù)就會(huì)將自己的健康狀態(tài)同步到eureka。配置如下即可聂儒。
在client端配置:將自己的健康狀態(tài)傳播到server虎锚。
eureka:
client:
healthcheck:
enabled: true
5.5 Eureka監(jiān)聽事件
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;
@Component
public class CustomEvent {
@EventListener
public void listen(EurekaInstanceCanceledEvent event ) {
System.out.println(LocalDateTime.now()+"服務(wù)下線事件:"+event.getAppName()+"---"+event.getServerId());
//發(fā)釘釘
}
@EventListener
public void listen(EurekaInstanceRegisteredEvent event) {
InstanceInfo instanceInfo = event.getInstanceInfo();
System.out.println(LocalDateTime.now()+"服務(wù)上線事件:"+instanceInfo.getAppName()+"---"+instanceInfo.getInstanceId());
}
@EventListener
public void listen(EurekaInstanceRenewedEvent event) {
System.out.println(LocalDateTime.now()+"服務(wù)續(xù)約/心跳上報(bào)事件:"+event.getAppName()+"---"+event.getServerId());
}
@EventListener
public void listen(EurekaRegistryAvailableEvent event) {
System.out.println(LocalDateTime.now()+"注冊(cè)中心可用事件");
}
@EventListener
public void listen(EurekaServerStartedEvent event) {
System.out.println(LocalDateTime.now()+"注冊(cè)中心啟動(dòng)事件");
}
}
5.6 Renew: 服務(wù)續(xù)約
Eureka Client 會(huì)每隔 30 秒發(fā)送一次心跳來續(xù)約。 通過續(xù)約來告知 Eureka Server 該 Eureka Client 運(yùn)行正常衩婚,沒有出現(xiàn)問題窜护。 默認(rèn)情況下,如果 Eureka Server 在 90 秒內(nèi)沒有收到 Eureka Client 的續(xù)約非春,Server 端會(huì)將實(shí)例從其注冊(cè)表中刪除柱徙,此時(shí)間可配置,一般情況不建議更改奇昙。
5.6 服務(wù)剔除
如果Eureka Client在注冊(cè)后护侮,既沒有續(xù)約,也沒有下線(服務(wù)崩潰或者網(wǎng)絡(luò)異常等原因)储耐,那么服務(wù)的狀態(tài)就處于不可知的狀態(tài)羊初,不能保證能夠從該服務(wù)實(shí)例中獲取到回饋,所以需要服務(wù)剔除此方法定時(shí)清理這些不穩(wěn)定的服務(wù)什湘,該方法會(huì)批量將注冊(cè)表中所有過期租約剔除长赞,剔除是定時(shí)任務(wù),默認(rèn)60秒執(zhí)行一次禽炬。延時(shí)60秒涧卵,間隔60秒
剔除的限制:
1.自我保護(hù)期間不清除。
2.分批次清除腹尖。
六柳恐、Eureka缺陷
由于集群間的同步復(fù)制是通過HTTP的方式進(jìn)行,基于網(wǎng)絡(luò)的不可靠性热幔,集群中的Eureka Server間的注冊(cè)表信息難免存在不同步的時(shí)間節(jié)點(diǎn)乐设,不滿足CAP中的C(數(shù)據(jù)一致性)
七、總結(jié)
中間我們講解了eureka的節(jié)點(diǎn)搭建绎巨,以及原理近尚,對(duì)于現(xiàn)在很火熱的微服務(wù),我們對(duì)Eureka是非常有必要進(jìn)行了解的场勤,如果覺得文章對(duì)你有幫助戈锻,來個(gè)點(diǎn)贊支持吧歼跟,如果對(duì)文章有疑問或建議,歡迎討論留言格遭,謝謝大家~