本文章基于spring-boot-starter-parent 2.0.6RELEASE,spring-cloud-dependencies Finchley.SR2。
Eureka是什麼
Eureka 是 Netflix的子子產品之一, 用于實作服務注冊與發現,是微服務架構中最為核心和基礎的子產品。Eureka有兩個元件:一個是EurekaServer,用于定位服務以實作中間層伺服器的負載均衡和故障轉移;另個一是EurekaClient(內建在我們的微服務中),用于與Server進行互動,并可以通過服務辨別符去擷取服務。 Spring Cloud 基于 Netflix Eureka做了二次封裝,主要負責完成微服務架構中的服務治理功能。
Eureka基礎架構
三個核心要素:
- 服務注冊中心: Eureka提供的服務端,提供服務注冊于發現功能
- 服務提供者: 提供服務的應用,可以是spring boot應用,也可以是其他技術平台且遵循Eureka通信機制的應用。
- 服務消費者: 消費者應用從服務注冊中心擷取服務清單,進而使消費者可以知道去何處調用其所需要的服務。
下圖是來自Eureka官方的基于叢集配置的架構圖:

- 處于不同節點的Eureka Server通過Replicate進行資料同步;
- Application Service為服務提供者,向Eureka Server注冊、服務同步、服務續約等;
- Application Client為服務消費者,可以向Eureka Server擷取服務執行個體清單、服務調用、服務續約、服務下線等;
- Make Remote Call完成一次服務調用。
服務治理機制:
服務啟動後向Eureka注冊,Eureka Server會将注冊資訊向其他Eureka Server進行同步,當服務消費者要調用服務提供者,則向服務注冊中心擷取服務提供者位址,然後會将服務提供者位址緩存在本地,下次再調用時,則直接從本地緩存中取,完成一次調用。
當服務注冊中心Eureka Server檢測到服務提供者因為當機、網絡原因不可用時,則在服務注冊中心将服務置為DOWN狀态,并把目前服務提供者狀态向訂閱者釋出,訂閱過的服務消費者更新本地緩存。
服務提供者在啟動後,周期性(預設30秒)向Eureka Server發送心跳,以證明目前服務是可用狀态。Eureka Server在一定的時間(預設90秒)未收到用戶端的心跳,則認為服務當機,登出該執行個體。
Eureka使用
下面用一個使用者擷取訂單的例子,來說明Eureka的使用:
Eureka服務注冊中心
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.ym:
server:
port: 8081 #預設值8080
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設定清理間隔(機關:毫秒 預設是60*1000)
instance:
hostname: localhost
client:
register-with-eureka: false #不把自己作為一個用戶端注冊到自己身上
fetch-registry: false #不從服務端擷取注冊資訊(因為在這裡自己就是服務端,而且已經禁用自己注 冊了)
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
在spring boot啟動項目上加上注解:@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class);
}
}
浏覽器通路http://localhsot:8081,看到下圖則說明服務注冊中心啟動成功
服務提供者(Order)
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml:
server:
port: 6000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8081/eureka #Eureka服務端提供的注冊位址
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} #此執行個體注冊到eureka服務端的唯一的執行個體ID
prefer-ip-address: true #是否顯示IP位址
spring:
application:
name: order-microservice #此執行個體注冊到eureka服務端的name
OrderController:
@RestController
public class OrderController {
@RequestMapping("/getOrder.do")
public Map<String,Object> getOrder() {
Map<String, Object> map = new HashMap();
map.put("key","order");
return map;
}
}
啟動類加上@EnableEurekaClient注解:
@SpringBootApplication
@EnableEurekaClient
public class AppOrderApplication {
public static void main(String[] args) {
SpringApplication.run(AppOrderApplication.class);
}
}
服務消費者(User)
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml:
server:
port: 5000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8081/eureka #Eureka服務端提供的注冊位址
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} #此執行個體注冊到eureka服務端的唯一的執行個體ID
prefer-ip-address: true #是否顯示IP位址
spring:
application:
name: user-microservice #此執行個體注冊到eureka服務端的name
AppConfig:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
UserController:
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/getOrder.do")
public Object getOrder() {
return restTemplate.getForObject("http://localhost:6000/getOrder.do",Object.class);
}
}
啟動類上加上@EnableEurekaClient注解:
@SpringBootApplication
@EnableEurekaClient
public class AppUserApplication {
public static void main(String[] args) {
SpringApplication.run(AppUserApplication.class);
}
}
用戶端與服務端啟動後,通路Eurek注冊中心即可看到服務執行個體已注冊:
浏覽器通路http://localhost:5000/getOrder.do ,結果頁面如下,說明服務調用成功。
Eureka叢集
Eureka Server的設計一開始就考慮了高可用問題,在Eureka的服務治理設計中,所有節點即是服務提供方,也是服務消費方,服務注冊中心也是。在上面的單節點服務注冊中心的配置檔案中,我們設定了下面兩個配置:
register-with-eureka: false #不把自己作為一個用戶端注冊到自己身上
fetch-registry: false #不從服務端擷取注冊資訊(因為在這裡自己就是服務端,而且已
Eureka Server的高可用就是将自己作為服務向其他服務注冊中心注冊自己。
下面進行執行個體示範,在單台機器上模拟叢集環境:
1.修改/etc/host檔案,mac上路徑為/etc/hosts,Windows系統路徑
C:\Window\System32\drivers\etc\hosts
。
2.簡單起見,就不複制兩個工程了,直接通過配置三個profile來啟動三個Eureka Server
spring:
application:
name: eureka-server
---
spring:
profiles: peer1
server:
port: 8081
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設定清理間隔(機關:毫秒 預設是60*1000)
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2:8082/eureka,http://peer3:8083/eureka
---
spring:
profiles: peer2
server:
port: 8082
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設定清理間隔(機關:毫秒 預設是60*1000)
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1:8081/eureka,http://peer3:8083/eureka
---
spring:
profiles: peer3
server:
port: 8083
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設定清理間隔(機關:毫秒 預設是60*1000)
instance:
hostname: peer3
client:
serviceUrl:
defaultZone: http://peer1:8081/eureka,http://peer2:8082/eureka
.yml
檔案中
---
辨別檔案分割.
3. 啟動項目
打成jar包啟動方式:
java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer1
java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer2
java -jar eurka-server-0.0.1.jar --spring.profiles.active=peer3
這裡使用IDEA啟動:
三個配置依次填入peer1、peer2、peer3
4.通路Eureka服務注冊中心
http://peer1:8081 http://peer2:8082 http://peer3:8083 即可看到叢集搭建成功。
Eureka的自保護機制
服務注冊到Eureka Server之後,會維護一個心跳連接配接,告訴Eureka Server自己還活着。Eureka Server在運作期間,會統計心跳失敗的比例在15分鐘之内是否低于85%,如果出現低于的情況,Eureka Server會認為用戶端與注冊中心出現了網絡故障,會将目前的執行個體注冊資訊保護起來,讓這些執行個體不會過期,盡可能保護這些注冊資訊,此時會出現以下情況:
- Eureka 不再從注冊清單中移除因為長時間沒有收到心跳而過期的服務。
- Eureka 仍然能夠接收新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證目前節點可用)
- 當網絡穩定後,目前執行個體新的注冊資訊會被同步到其它節點中
另外,在保護期間如果執行個體出現問題,Eureka Server則會出現可用性問題,部分請求會失敗。是以用戶端也要配套容錯機制,比如可以使用請求重試、斷路器等機制。
本地開發的時候,可以使用
eureka.server.enable-self-preservation=false
參數來關閉保護機制,以確定注冊中心可以将不可用的執行個體正确剔除。
Eureka與Zookeeper的差別
不知道CAP定理的同學請先去了解CAP定理知識。
Zookeeper在設計的時候遵循的是CP原則,即保證一緻性和分區容錯性,Zookeeper會出現這樣一種情況,當master節點因為網絡故障與其他節點失去聯系時剩餘節點會重新進行leader選舉,問題在于,選舉leader的時間太長:30~120s,且選舉 間整個Zookeeper叢集是不可用的,這就導緻在選舉期間注冊服務處于癱瘓狀态,在雲部署的環境下,因網絡環境使Zookeeper叢集失去master節點是較大機率發生的事情,雖然服務能夠最終恢複,但是漫長的選舉時間導緻長期的服務注冊不可用是不能容忍的。
Eureka在設計的時候遵循的是AP原則,即可用性和分區容錯性。Eureka各個節點(服務)是平等的, 沒有主從之分,幾個節點 down掉不會影響正常工作,剩餘的節點(服務) 依然可以提供注冊與查詢服務,而Eureka的用戶端在向某個 Eureka注冊或發現連接配接失敗,則會自動切換到其他節點,也就是說,隻要有一台Eureka還在,就能注冊可用(保證可用性), 隻不過查詢到的資訊不是最新的(不保證強一緻)。
------------本文結束感謝您的閱讀------------