一、Eureka的基礎架構
Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模塊來實現服務注冊和發現(請對比Zookeeper)。
Eureka 采用了 C-S 的設計架構。Eureka Server 作為服務注冊功能的服務器,它是服務注冊中心。
而系統中的其他微服務,使用 Eureka 的客戶端連接到 Eureka Server并維持心跳連接。這樣系統的維護人員就可以通過 Eureka Server 來監控系統中各個微服務是否正常運行。SpringCloud 的一些其他模塊(比如Zuul)就可以通過 Eureka Server 來發現系統中的其他微服務,并執行相關的邏輯。
請注意和Dubbo的架構對比
Eureka包含兩個組件:Eureka Server和Eureka Client
Eureka Server提供服務注冊服務
各個節點啟動后,會在EurekaServer中進行注冊,這樣EurekaServer中的服務注冊表中將會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀的看到
EurekaClient是一個Java客戶端,用于簡化Eureka Server的交互,客戶端同時也具備一個內置的、使用輪詢(round-robin)負載算法的負載均衡器。在應用啟動后,將會向Eureka Server發送心跳(默認周期為30秒)。如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳,EurekaServer將會從服務注冊表中把這個服務節點移除(默認90秒)
二、Eureka三大角色
- Eureka Server:提供服務注冊和發現
- Service Provider:服務提供方將自身服務注冊到Eureka,從而使服務消費方能夠找到
- Service Consumer:服務消費方從Eureka獲取注冊服務列表,從而能夠消費服務
三、原理圖
- Eureka:就是服務注冊中心(可以是一個集群),對外暴露自己的地址
- 提供者:啟動后向Eureka注冊自己信息(地址,提供什么服務)
- 消費者:向Eureka訂閱服務,Eureka會將對應服務的所有提供者地址列表發送給消費者,并且定期更新
- 心跳(續約):提供者定期通過http方式向Eureka刷新自己的狀態
四、入門案例
-
項目結構
加入依賴
<?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>cloud-demo</artifactId>
<groupId>cn.itcast.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-service</artifactId>
<dependencies>
<!-- eureka 服務端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<!--<artifactId>spring-cloud-starter-eureka-server</artifactId>-->
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
-
application
-
yml
啟動
- 引入pom依賴
- 添加@EnableEurekaServer注解啟用Eureka服務
- 添加端口
- 訪問http://127.0.0.1:10086/
- 啟動報錯問題分析
eureka本身既是一個服務端也是一個客戶端
集群環境下eureka之間會進行相互注冊,單機狀態下無人可注冊所以他報錯了
解決方案
-
自己注冊自己(第一次還是會報錯,因為未啟動好就進行注冊,后面不會報錯)
-
申明自己端就是注冊中心,我的職責就是維護服務實例,并不需要去檢索服務
五、服務提供者修改
-
添加依賴
-
添加注解
-
添加配置
六、服務消費者修改
-
添加依賴
-
添加注解
-
添加配置
-
代碼修改
七、actuator監控信息
-
服務提供方依賴添加
-
信息添加
-
父工程內容構建
八、Eureka自我保護
什么是自我保護模式?
默認情況下,如果EurekaServer在一定時間內沒有接收到某個微服務實例的心跳,EurekaServer將會注銷該實例(默認90秒)。但是當網絡分區故障發生時,微服務與EurekaServer之間無法正常通信,以上行為可能變得非常危險了——因為微服務本身其實是健康的,此時本不應該注銷這個微服務。Eureka通過“自我保護模式”來解決這個問題——當EurekaServer節點在短時間內丟失過多客戶端時(可能發生了網絡分區故障),那么這個節點就會進入自我保護模式。一旦進入該模式,EurekaServer就會保護服務注冊表中的信息,不再刪除服務注冊表中的數據(也就是不會注銷任何微服務)。當網絡故障恢復后,該Eureka Server節點會自動退出自我保護模式。
在自我保護模式中,Eureka Server會保護服務注冊表中的信息,不再注銷任何服務實例。當它收到的心跳數重新恢復到閾值以上時,該Eureka Server節點就會自動退出自我保護模式。它的設計哲學就是寧可保留錯誤的服務注冊信息,也不盲目注銷任何可能健康的服務實例。一句話講解:好死不如賴活著
綜上,自我保護模式是一種應對網絡異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目注銷任何健康的微服務。使用自我保護模式,可以讓Eureka集群更加的健壯、穩定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false 禁用自我保護模式。
九、Eureka詳解
接下來我們詳細講解Eureka的原理及配置。
9.1 基礎架構
Eureka架構中的三個核心角色:
- 服務注冊中心
Eureka的服務端應用,提供服務注冊和發現功能,就是剛剛我們建立的eureka-demo - 服務提供者
提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現,只要對外提供的是Rest風格服務即可。本例中就是我們實現的user-service-demo - 服務消費者
消費應用從注冊中心獲取服務列表,從而得知每個服務方的信息,知道去哪里調用服務方。本例中就是我們實現的consumer-demo
9.2 高可用的Eureka Server
Eureka Server即服務的注冊中心,在剛才的案例中,我們只有一個EurekaServer,事實上EurekaServer也可以是一個集群,形成高可用的Eureka中心。
服務同步
多個Eureka Server之間也會互相注冊為服務,當服務提供者注冊到Eureka Server集群中的某個節點時,該節點會把服務的信息同步給集群中的每個節點,從而實現數據同步。因此,無論客戶端訪問到Eureka Server集群中的任意一個節點,都可以獲取到完整的服務列表信息。
動手搭建高可用的EurekaServer
我們假設要搭建兩條EurekaServer的集群,端口分別為:10086和10087
- 復制EurekaServer
-
第一種
-
第二種
相互注冊
-
提供方跟消費方多地址添加
9.2 服務提供者
服務注冊
服務提供者在啟動時,會檢測配置屬性中的:eureka.client.register-with-erueka=true參數是否正確,事實上默認就是true。如果值確實為true,則會向EurekaServer發起一個Rest請求,并攜帶自己的元數據信息,Eureka Server會把這些信息保存到一個雙層Map結構中。第一層Map的Key就是服務名稱,第二層Map的key是服務的實例id。
服務續約
在注冊服務完成以后,服務提供者會維持一個心跳(定時向EurekaServer發起Rest請求),告訴EurekaServer:“我還活著”。這個我們稱為服務的續約(renew);
有兩個重要參數可以修改服務續約的行為:
也就是說,默認情況下每個30秒服務會向注冊中心發送一次心跳,證明自己還活著。如果超過90秒沒有發送心跳,EurekaServer就會認為該服務宕機,會從服務列表中移除,這兩個值在生產環境不要修改,默認即可。
但是在開發時,這個值有點太長了,經常我們關掉一個服務,會發現Eureka依然認為服務在活著。所以我們在開發階段可以適當調小。
實例id
先來看一下服務狀態信息:
在Eureka監控頁面,查看服務注冊信息:
在status一列中,顯示以下信息:
- UP(1):代表現在是啟動了1個示例,沒有集群
- DESKTOP-2MVEC12:user-service:8081:是示例的名稱(instance-id),
- 默認格式是:
${hostname} + ${spring.application.name} + ${server.port}
- instance-id是區分同一服務的不同實例的唯一標準,因此不能重復。
- 默認格式是:
我們可以通過instance-id屬性來修改它的構成:
eureka:
instance:
instance-id: ${spring.application.name}:${server.port}
重啟服務再試試看:
9.3 服務消費者
獲取服務列表
當服務消費者啟動是,會檢測eureka.client.fetch-registry=true
參數的值,如果為true,則會從Eureka Server服務的列表只讀備份,然后緩存在本地。并且每隔30秒
會重新獲取并更新數據。我們可以通過下面的參數來修改:
eureka:
client:
registry-fetch-interval-seconds: 5
生產環境中,我們不需要修改這個值。
但是為了開發環境下,能夠快速得到服務的最新狀態,我們可以將其設置小一點。
9.4 失效剔除和自我保護
失效剔除
有些時候,我們的服務提供方并不一定會正常下線,可能因為內存溢出、網絡故障等原因導致服務無法正常工作。Eureka Server需要將這樣的服務剔除出服務列表。因此它會開啟一個定時任務,每隔60秒對所有失效的服務(超過90秒未響應)進行剔除。
可以通過eureka.server.eviction-interval-timer-in-ms
參數對其進行修改,單位是毫秒,生成環境不要修改。
這個會對我們開發帶來極大的不變,你對服務重啟,隔了60秒Eureka才反應過來。開發階段可以適當調整,比如10S
自我保護
我們關停一個服務,就會在Eureka面板看到一條警告:
這是觸發了Eureka的自我保護機制。當一個服務未按時進行心跳續約時,Eureka會統計最近15分鐘心跳失敗的服務實例的比例是否超過了85%。在生產環境下,因為網絡延遲等原因,心跳失敗實例的比例很有可能超標,但是此時就把服務剔除列表并不妥當,因為服務可能沒有宕機。Eureka就會把當前實例的注冊信息保護起來,不予剔除。生產環境下這很有效,保證了大多數服務依然可用。
但是這給我們的開發帶來了麻煩, 因此開發階段我們都會關閉自我保護模式:
eureka:
server:
enable-self-preservation: false # 關閉自我保護模式(缺省為打開)
eviction-interval-timer-in-ms: 1000 # 掃描失效服務的間隔時間(缺省為60*1000ms 失效剔除)