本文摘錄於筆者出版的書籍 《Spring Cloud 微服務架構進階》一書html
在傳統的單體應用中,組件之間的調用經過有規範約束的接口進行,實現不一樣模塊間良好協做。在微服務架構中,本來的'巨石'應用按照業務被分割成相對獨立的、提供特定功能的服務,每個微服務均可以經過集羣或者其餘方式進行動態的擴展,每個微服務實例的網絡地址均可能動態變化,這使得本來經過硬編碼地址的調用方式失去了適用性。微服務架構中,服務跨度之大,數量之多,迫切須要架構創建一個去中心化的組件對各個微服務實例的信息進行登記和管理,同時提供能力讓各個服微務實例之間可以互相發現,從而達到互相調用的結果。web
一般來講服務註冊與發現包括兩部分,一個是Server端,另外一個是Client。Server是一個公用組件,爲Client提供服務註冊和發現的功能,維護着註冊到自身的Client的相關信息,同時提供接口給Client獲取到註冊表中其餘服務的信息,使得動態變化的Client在服務地址穩定的時間節點可以進行服務間調用。Client將本身的服務信息經過必定的方式登記到Server上,並在正常範圍內維護本身信息的一致性,方便其餘服務發現本身,同時能夠經過Server獲取到本身依賴的其餘服務信息,完成服務調用。spring
Eureka這個詞來源於古希臘語,意爲「我找到了!我發現了!」,據傳,阿基米德在洗澡時發現浮力原理,高興得來不及穿上褲子,跑到街上大喊:「Eureka(我找到了)!」。緩存
在Netflix中,Eureka是一個REST風格的服務註冊與發現的基礎服務組件,主要是應用在AWS中定位中間層服務的負載均衡和故障轉移。Eureka由兩部分組成,一個是Eureka Server,提供服務註冊和發現的功能,就是咱們上面所說的Server端;另外一個是Java客戶端,稱爲Eureka Client,是爲了使得與服務端交互更加簡單,Eureka Client會定時將本身的信息註冊到Eureka Server中,並從Server中發現其餘服務。客戶端中有一個內置的負載均衡器,用來進行基本的循環負載均衡。bash
Spring Cloud的版本基於Finchley.M9,spring-cloud-netflix的版本基於2.0.0.M8,Eureka的版本基於v1.8.7。微信
能夠經過IDEA快速搭建包含Eurake Server依賴的SpringBoot項目網絡
主要依賴架構
<dependency> // eureka-client相關依賴
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency> // actuator相關依賴
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency> // Spring Web MVC相關依賴
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
複製代碼
在啓動類中的註解@EnableEurekaServer
app
@SpringBootApplication
// `@EnableEurekaServer`註解會爲項目自動配置必須的配置類,標識該服務爲註冊中心
@EnableEurekaServer
public class Chapter4EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(Chapter2EurekaServerApplication.class, args);
}
}
複製代碼
在application.yml
配置文件中添加如下配置,配置註冊中心的端口和標識本身爲Eureka Server。負載均衡
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false // 代表該服務不會向Eureka Server註冊本身的信息
fetch-registry: false // 代表該服務不會向Eureka Server獲取註冊信息
service-url: // Eureka Server註冊中心的地址,用於client與server進行交流
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
複製代碼
Eureka Server既能夠獨立部署,也能夠集羣部署,在集羣部署的條件下,Eureka Server間會進行註冊表信息同步的操做,這時被同步註冊表信息的Eureka Server將會被同步註冊表信息的Eureka Server稱爲peer
。
請注意上述配置中service-url其實指向的註冊中心爲實例自己,一般來說,每個Eureka Server也是一個Eureka Client,它會嘗試註冊本身,因此須要最少一個註冊中心的URL來定位對等點peer
。若是不提供這樣一個註冊端點,註冊中心也能工做,可是會在日誌中打出沒法向peer
註冊本身。在獨立(Standalone)Eureka Server的模式下,Eureka Server通常會關閉做爲client端註冊本身的行爲,註冊中心將無註冊到它的peer
中。
Eureka Server與Eureka Client之間的維繫主要經過心跳的方式實現,心跳(Heartbeat)即Eureka Client定時向Eureka Server彙報當前的本服務實例的狀態。
Eureka Server須要隨時維持最新的服務實例信息,因此在註冊表中的每一個服務實例都須要按期發送心跳到Server中以使本身的註冊保持最新的狀態(數據通常直接保存在內存中)。這意味着Eureka Client不須要爲每次服務間請求都向註冊中心請求依賴服務實例信息,Eureka Client將定時從Eureka Server中拉取Eureka Server中的註冊表中的全部信息,並將註冊表信息緩存到本地,用於服務發現。
啓動Eureka Server後,應用會有一個主頁面用來展現當前註冊表中的服務實例信息和暴露一些基於HTTP協議的的endpoint在/eureka
路徑下被Eureka Client用於註冊自身、獲取註冊表信息以及發送心跳等。
能夠經過IDEA快速搭建包含Eurake Client依賴的SpringBoot項目。
主要依賴有:
<dependency>// eureka-server相關依賴
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
複製代碼
啓動類
@SpringBootApplication
public class Chapter4EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(Chapter2EurekaClientApplication.class, args);
}
}
複製代碼
在Finchley
版本中的Spring Cloud中,只要引入spring-cloud-starter-netflix-eureka-client
的依賴,應用就會自動註冊到Eureka Server,可是須要在配置文件中添加Eureka Server的地址。
在application.yml
添加如下配置:
eureka:
instance:
prefer-ip-address: true
client:
service-url: // Eureka Server註冊中心的地址,用於client與server進行交流
defaultZone: http://localhost:8761/eureka/
server:
port: 8765
spring:
application:
name: eureka-client
複製代碼
搭建好上述的兩個的Eureka應用後,依次啓動Server和Client。
Eureka Server主頁
訪問地址Eureka Server的主頁http://localhost:8761
,能夠看到如下界面:
與服務註冊中心交換信息
DiscoveryClient
來源於spring-cloud-client-discovery,是SpringCloud中定義的用來服務發現的頂級接口,在SpringCloud的各種服務發現組件中(如Netflix Eureka或者Consul)都有相應的實現。它提供從服務註冊中心中根據serviceId的獲取到對應的服務實例信息的能力。
當一個服務實例擁有DiscoveryClient
的具體實現時,就能夠從Eureka Server中發現其餘的服務實例。
在Eureka Client中注入DiscoveryClient
,並從Eureka Server獲取服務實例的信息。
在chapter2-eureka-client
添加一個ServiceInstanceRestController
的controller
@RestController
public class ServiceInstanceRestController {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/service-instances/{applicationName}")
public List<ServiceInstance> serviceInstancesByApplicationName(
@PathVariable String applicationName) {
return this.discoveryClient.getInstances(applicationName);
}
}
複製代碼
啓動應用後,訪問地址http://localhost:8765/service-instances/eureka-client
,獲取應用名爲eureka-client
的(服務自己)服務實例的元數據,結果以下:
[
{
"host":"192.168.1.168",
"port":8765,
"metadata":{
"management.port":"8765",
"jmx.port":"59110"
},
"uri":"http://192.168.1.168:8765",
"secure":false,
"serviceId":"EUREKA-CLIENT",
"instanceInfo":{
"instanceId":"192.168.1.168:eureka-client:8765",
"app":"EUREKA-CLIENT",
"appGroupName":null,
"ipAddr":"192.168.1.168",
"sid":"na",
"homePageUrl":"http://192.168.1.168:8765/",
"statusPageUrl":"http://192.168.1.168:8765/info",
"healthCheckUrl":"http://192.168.1.168:8765/health",
"secureHealthCheckUrl":null,
"vipAddress":"eureka-client",
"secureVipAddress":"eureka-client",
"countryId":1,
"dataCenterInfo":{
"@class":"com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name":"MyOwn"
},
"hostName":"192.168.1.168",
"status":"UP",
"leaseInfo":{
"renewalIntervalInSecs":30,
"durationInSecs":90,
"registrationTimestamp":1515585341831,
"lastRenewalTimestamp":1515585341831,
"evictionTimestamp":0,
"serviceUpTimestamp":1515585341260
},
"isCoordinatingDiscoveryServer":false,
"metadata":{
"management.port":"8765",
"jmx.port":"59110"
},
"lastUpdatedTimestamp":1515585341831,
"lastDirtyTimestamp":1515581890364,
"actionType":"ADDED",
"asgName":null,
"overriddenStatus":"UNKNOWN"
}
}
]
複製代碼
Eureka中的標準元數據有主機名、IP地址、端口號、狀態頁url和健康檢查url等,這些元數據都會保存在Eureka Server的註冊信息表中,Eureka Client經過根據服務名讀取這些元數據來發現和調用其餘的服務實例。元數據能夠自定義以適應特定的業務場景,這些將在下面章節進行講解。
詳細瞭解本書:地址