概述
關(guān)于Eureka
微服務(wù)是當(dāng)前互聯(lián)網(wǎng)系統(tǒng)的主流架構(gòu),而服務(wù)注冊與發(fā)現(xiàn)則是微服務(wù)架構(gòu)的基礎(chǔ),Spring Cloud為我們提供的眾多組件,其中Eureka就是Spring Cloud為我們提供服務(wù)注冊與發(fā)現(xiàn)功能的組件
相關(guān)版本
JDK:1.8
SpringBoot:2.2.5.RELEASE
SpringCloud:Hoxton.SR3
相關(guān)文章
如果對微服務(wù)的概念還不是特別了解,建議先戳一下這篇文章:什么是微服務(wù)架構(gòu)? - 老劉的回答 - 知乎
https://www.zhihu.com/question/65502802/answer/802678798
本文結(jié)構(gòu)
- 為什么需要服務(wù)注冊與發(fā)現(xiàn)
- 搭建Eureka服務(wù)注冊中心
- 搭建Eureka客戶端實例
- 實現(xiàn)Eureka的高可用
Eureka入門
為什么需要服務(wù)注冊與發(fā)現(xiàn)
開始coding之前先了解一下微服務(wù)架構(gòu)中為什么需要服務(wù)注冊與發(fā)現(xiàn)。在微服務(wù)架構(gòu)中,存在有多個微小的子服務(wù),各個子服務(wù)之間需要http通訊,那么肯定需要知道彼此的IP地址,那假設(shè)系統(tǒng)中存在ABC三個子服務(wù)存在如下的情況:
- A調(diào)用BC,A存BC的IP
- B調(diào)用AC,B存AC的IP
- C調(diào)用AB,C存AB的IP
ABC都需要在各自的服務(wù)中維護(hù)對方的IP地址,這還只是ABC三個子服務(wù)之間,假設(shè)系統(tǒng)中有100個子服務(wù)呢?而且一旦某個子服務(wù)的IP發(fā)生改變,則意味著所有跟它有關(guān)聯(lián)的子服務(wù)都需要修改對應(yīng)的IP地址。顯然這是非常不合理的,所以我們需要一個服務(wù)注冊與發(fā)現(xiàn)中心的角色。系統(tǒng)中所有的子服務(wù)在啟動時都注冊到服務(wù)注冊中心,于是所有的子服務(wù)相關(guān)信息都會存儲在服務(wù)注冊中心,當(dāng)A需要調(diào)用BC時,不在需要自己維護(hù)一份其他服務(wù)的IP地址,A可以向服務(wù)注冊中心獲取一份其他服務(wù)的IP地址,如下圖:

搭建Eureka服務(wù)注冊中心
創(chuàng)建工程
-
使用IDEA創(chuàng)建項目,通過Spring Initianlizr創(chuàng)建項目Spring Initianlizr
-
輸入工程信息工程信息
-
依賴選擇Spring Cloud Discovery里面的Eureka Server,最后保存你的項目就行了
選擇依賴
增加必要注解和修改配置
- 先利用@EnableEurekaServer讓此服務(wù)成為注冊中心,在啟動類上加@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
訪問localhost:8761看看(我配置的端口是8761)

可以看到Instance currently registered with Eureka列表中實例是空的,也就是還沒有實例注冊到這個服務(wù)注冊中心。運(yùn)行的時候發(fā)現(xiàn)console控制臺一直打印com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server這個異常,這個異常是是Eureka客戶端實例沒有配置對應(yīng)Eureka服務(wù)注冊中心時會拋出的錯誤,這里因為默認(rèn)情況下Eureka服務(wù)注冊中心自己本身也會被作為一個實例注冊到EurekaEureka服務(wù)注冊中心,這時候因為這個Eureka服務(wù)沒有配置需要注冊到哪個Eureka服務(wù)注冊中心,所以會拋出這個錯誤
- 配置文件增加下面的配置(這里用的yml),通過register-with-eureka: false配置當(dāng)前這個服務(wù)不要注冊到Eureka服務(wù)注冊中心,一般情況下作為Eureka服務(wù)注冊中心的服務(wù)都會增加這個配置
eureka:
client:
register-with-eureka: false
增加這個配置以后,重新啟動,程序運(yùn)行的時候就不會再出現(xiàn)com.netflix.discovery.shared.transport.TransportException異常了
搭建Eureka客戶端實例
創(chuàng)建工程
和搭建Eureka服務(wù)注冊中心過程類似,主要在第三步時選擇Spring Cloud Discovery里面的Eureka Discovery Client,并且注意SpringBoot版本和SpringCloud版本需要和服務(wù)注冊中心服務(wù)保持一致

增加必要注解和修改配置
- 先加上web依賴,否則等等項目啟動會失敗
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 利用@EnableEurekaClient讓此服務(wù)成為Eureka客戶端實例,在啟動類上加@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
- 修改配置文件
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: client
- defaultZone配置當(dāng)前服務(wù)實例需要注冊到的服務(wù)注冊中心的地址
- name配置當(dāng)前服務(wù)名稱
啟動項目,然后打開/localhost:8761看一下(服務(wù)注冊中心)

可以看到一個名字CLIENT的服務(wù)實例已經(jīng)注冊到服務(wù)注冊中心了。到這就完成了一個最簡單的服務(wù)注冊與發(fā)現(xiàn)過程了
實現(xiàn)Eureka的高可用
為了保證Eureka的高可用,可以通過部署多臺Eureka服務(wù)注冊中心(集群)的方式來實現(xiàn)

如上圖所示,建立一個擁有3臺服務(wù)注冊中心的服務(wù)注冊中心集群,并且各個服務(wù)注冊中心進(jìn)行相互注冊,然后客戶端實例向每個服務(wù)注冊中心都發(fā)起注冊。
搭建服務(wù)注冊中心集群
這里就以兩個服務(wù)注冊中心為例,注意我這里為了方便是采取一個工程項目配置兩個SpringBoot啟動,先看第一個服務(wù)注冊中心我設(shè)置的啟動端口是8761

然后配置文件里defaultZone把服務(wù)注冊中心1注冊到http://localhost:8762/eureka/,等等第二個服務(wù)注冊中心準(zhǔn)備在8762啟動
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:8762/eureka/
spring:
application:
name: eureka
接著看第二個服務(wù)注冊中心配置的端口,啟動端口是8762

再看第二個服務(wù)注冊中心的配置文件,defaultZone把第二個服務(wù)注冊中心注冊到第一個服務(wù)注冊中心的地址http://localhost:8761/eureka/
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka
服務(wù)端實例注冊到集群
先啟動上文的兩個服務(wù)注冊中心,先看看如果服務(wù)端實例只注冊到兩個服務(wù)注冊中心的其中一個的情況吧,配置文件配置只注冊到8761
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: client
咋們分別進(jìn)localhost:8761和localhost:8762看看,可以發(fā)現(xiàn)雖然實例只注冊到其中一個服務(wù)注冊中心,但是兩個服務(wù)里都發(fā)現(xiàn)這個實例,這說明通過服務(wù)注冊中心相互注冊已經(jīng)實現(xiàn)了集群共享注冊實例

真正的高可用
上文已經(jīng)做到服務(wù)注冊中心同步客戶端實例,但是如果這個時候我們把localhost:8761這臺服務(wù)注冊中心(實例注冊到的服務(wù)注冊中心)掛掉會怎樣?先看客戶端實例的控制臺,因為localhost:8761掛掉,已經(jīng)在打印無法注冊到服務(wù)注冊中心的異常com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server。再看看還保持運(yùn)行的localhost:8762,發(fā)現(xiàn)客戶端實例在localhost:8762中也被清除了。PS:這里要注意一點(diǎn),由于Eureka的心跳監(jiān)測機(jī)制(概述中的相關(guān)文章有介紹心跳監(jiān)測)和緩存的問題,在掛掉localhost:8761以后查看localhost:8762,仍然可以看到客戶端實例在線的狀態(tài),需要一定時間以后客戶端實例才會在localhost:8762中清除

如果localhost:8761掛掉,原本注冊到localhost:8761中的實例在localhost:8762中也會被清除,那整個服務(wù)注冊中心集群就都失去這個實例的注冊信息,還如何高可用?這時候我們把客戶端實例的配置文件改成defaultZone配置兩個注冊地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/, http://localhost:8762/eureka/
spring:
application:
name: client
把兩個注冊中心和實例都啟動,查看一下兩個服務(wù)注冊中心,和上面一樣兩個都注冊上了實例,不同就在于如果現(xiàn)在把localhost:8761掛掉,localhost:8762仍舊可以一直保持著實例在線,這樣實例永遠(yuǎn)不會清除,實例會一直注冊在服務(wù)注冊中心集群中,這是真正的高可用。
一個疑問
- 很多同學(xué)肯定跟我一樣有一個疑問:客戶端實例的defaultZone配置已經(jīng)修改成同時向兩個注冊中心注冊,那兩個注冊中心有沒有相互注冊又有什么關(guān)系?就算它們之間沒有相互注冊,一樣可以做到高可用啊
- 解答:因為客戶端實例defaultZone雖然配置了兩個地址,但是并不是同時向兩個地址發(fā)起注冊。Eureka的注冊規(guī)則是,從第一個注冊中心地址開始嘗試注冊,直到最后一個地址,如果成功了就不再向其他注冊中心地址發(fā)起注冊。也就是從始至終客戶端實例都是只向一個注冊中心發(fā)起注冊,集群中的其他注冊中心都是通過同步共享的方式獲得這個客戶端實例的。所以很顯然,讓服務(wù)注冊中心相互注冊時必要的,如果沒有相互注冊是做不到同步共享客戶端實例的
總結(jié)
本文源碼地址:https://github.com/iemi/Spring-Cloud-Eureka
如果你覺得本文有幫助到你,幫忙點(diǎn)個贊,Github給星星,感謝!


