相關閱讀:
SpringBoot2.X快速構建和配置
微服務入門 spring cloud環境搭建
1.eureka是什麼?
eureka是Netflix的子模塊之一,也是一個核心的模塊,eureka裏有2個組件,一個是EurekaServer(一個獨立的項目) 這個是用於定位服務以實現中間層服務器的負載平衡和故障轉移,另一個便是EurekaClient(我們的微服務) 它是用於與Server交互的,可以使得交互變得非常簡單:只需要通過服務標識符即可拿到服務。
2. 與spring-cloud的關係:
Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模塊來實現服務註冊和發現(可以對比Zookeeper)。
Eureka 採用了 C-S 的設計架構。Eureka Server 作爲服務註冊功能的服務器,它是服務註冊中心。
而系統中的其他微服務,使用 Eureka 的客戶端連接到 Eureka Server並維持心跳連接。這樣系統的維護人員就可以通過 Eureka Server 來監控系統中各個微服務是否正常運行。SpringCloud 的一些其他模塊(比如Zuul)就可以通過 Eureka Server 來發現系統中的其他微服務,並執行相關的邏輯。
3. 角色關係圖
4 如何使用
4.1 添加依賴
客戶端:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
服務端:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
添加相關依賴
當然不管是服務端還是客戶端都需要添加springCloud的支持
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.2 服務端配置
服務端配置信息:yml或者properties文件都可以
server:
port: 3000
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設置清理間隔(單位:毫秒 默認是60*1000)
instance:
hostname: localhost
client:
registerWithEureka: false #不把自己作爲一個客戶端註冊到自己身上
fetchRegistry: false #不需要從服務端獲取註冊信息(因爲在這裏自己就是服務端,而且已經禁用自己註冊了)
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
自我保護機制 這裏展開一下,
定義:
當Eureka Server節點在短時間內丟失過多客戶端時(可能發生了網絡分區故障),那麼這個節點就會進入自我保護模式。一旦進入該模式,Eureka Server就會保護服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。當網絡故障恢復後,該Eureka Server節點會自動退出自我保護模式。
簡單理解:當一個服務和Eureka失聯後,Eureka認爲這個服務的問題,當大部分服務都失聯(網絡中斷)這個時候Eureka不再認爲是服務的問題,就懷疑人生,感覺是自己出現了問題,不再清除,跟新任何服務註冊列表中的數據
意義:
自我保護模式是一種應對網絡異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目註銷任何健康的微服務。使用自我保護模式,可以讓Eureka集羣更加的健壯、穩定
出現這個頁面就證明搭建成功, 這個警告是因爲自我保護機制關閉的原因,先不關了
4.3 客戶端配置
server:
port: 8082
eureka:
client:
serviceUrl:
defaultZone: http://localhost:3000/eureka #eureka服務端提供的註冊地址 參考服務端配置的這個路徑
instance:
instance-id: user-1 #此實例註冊到eureka服務端的唯一的實例ID
prefer-ip-address: true #是否顯示IP地址
leaseRenewalIntervalInSeconds: 10 #eureka客戶需要多長時間發送心跳給eureka服務器,表明它仍然活着,默認爲30 秒 (與下面配置的單位都是秒)
leaseExpirationDurationInSeconds: 30 #Eureka服務器在接收到實例的最後一次發出的心跳後,需要等待多久纔可以將此實例刪除,默認爲90秒
spring:
application:
name: client-user #此實例註冊到eureka服務端的name
然後在客戶端的spring-boot啓動項目上 加入註解:@EnableEurekaClient 就可以啓動項目了 這裏就不截圖了我們直接來看效果圖:
這裏我們能看見 名字叫server-power的(圖中將其大寫了) id爲 power-0的服務 註冊到我們的Eureka上面來了 至此,一個簡單的eureka已經搭建好了。
eviction-interval-timer-in-ms: 4000 #設置清理間隔(單位:毫秒 默認是60*1000)
leaseRenewalIntervalInSeconds: 10 #eureka客戶需要多長時間發送心跳給eureka服務器,表明它仍然活着,默認爲30 秒 (與下面配置的單位都是秒)
leaseExpirationDurationInSeconds: 30 #Eureka服務器在接收到實例的最後一次發出的心跳後,需要等待多久纔可以將此實例刪除,默認爲90秒
每10秒給我發一個心跳,如果沒發就等待30秒,不然定期(4000ms)進行清理,這就好比一個美女有很多追求者,需要管理這些追求者,美女怎麼知道這些追求者是否移心別戀了,需要定期給美女放電,如果超過約定的時間,最多等待多久,這裏主要考慮,網絡抖動,而不是服務器自己真的掛了,如果說是因爲其他的事情導致的放電失敗,我可以最多寬容你多久,把那些超過等待時間的定期進行清理
5.eureka集羣
爲什麼我們需要配置eureka集羣?
所以的服務都註冊到eurekaserver,萬一eureka自己宕機了怎麼辦,不是整個系統都癱瘓了,這種不符合高可用的原來所以需要eureka進行集羣.
5.1eureka集羣原理
服務啓動後向Eureka註冊,Eureka Server會將註冊信息向其他Eureka Server進行同步,當服務消費者要調用服務提供者,則向服務註冊中心獲取服務提供者地址,然後會將服務提供者地址緩存在本地,下次再調用時,則直接從本地緩存中取,完成一次調用。
這裏eureka和zookeeper的集羣還有些不太一樣,zookeeper是分lender和flower的eureka不區分這些,也就是說都是全部平等的,
5.2 eureka集羣配置
Eureka Server會將註冊信息向其他Eureka Server進行同步 那麼我們得聲明有哪些server呢?
這裏 假設我們有3個Eureka Server 如圖:
5.2.1 3000配置
server:
port: 3000
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設置清理間隔(單位:毫秒 默認是60*1000)
instance:
hostname: localhost
ip-address: 127.0.0.1
client:
registerWithEureka: false #不把自己作爲一個客戶端註冊到自己身上
fetchRegistry: false #不需要從服務端獲取註冊信息(因爲在這裏自己就是服務端,而且已經禁用自己註冊了)
serviceUrl:
defaultZone: http://127.0.0.1:3001/eureka,http://127.0.0.1:3002/eureka
原來我是沒有配置ip-address
5.2.2 3001配置
server:
port: 3001
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設置清理間隔(單位:毫秒 默認是60*1000)
instance:
hostname: localhost
ip-address: 127.0.0.1
client:
registerWithEureka: false #不把自己作爲一個客戶端註冊到自己身上
fetchRegistry: false #不需要從服務端獲取註冊信息(因爲在這裏自己就是服務端,而且已經禁用自己註冊了)
serviceUrl:
defaultZone: http://127.0.0.1:3000/eureka,http://127.0.0.1:3002/eureka
5.2.3 3002配置
server:
port: 3002
eureka:
server:
enable-self-preservation: false #關閉自我保護機制
eviction-interval-timer-in-ms: 4000 #設置清理間隔(單位:毫秒 默認是60*1000)
instance:
hostname: localhost
ip-address: 127.0.0.1
client:
registerWithEureka: false #不把自己作爲一個客戶端註冊到自己身上
fetchRegistry: false #不需要從服務端獲取註冊信息(因爲在這裏自己就是服務端,而且已經禁用自己註冊了)
serviceUrl:
defaultZone: http://127.0.0.1:3001/eureka,http://127.0.0.1:3000/eureka
沒有配置ip-address時eureka不進行信息同步,原因解釋如下:
由於我們的產品需要提供給不同的客戶,不同客戶對應主機有不同的要求,有的不會讓我們擁有更改hostname的權限。所以我們選用的第二種方法,使用ipAddress來註冊。不過需要在網易的博客上面多加一條,指定該Eureka Server的ip-address
也可以使用
這裏 方便理解集羣 我們做了一個域名的映射(條件不是特別支持我使用三臺筆記本來測試。。。) 至於域名怎麼映射的話 這裏簡單提一下吧 修改你的hosts文件(win10的目錄在C:\Windows\System32\drivers\etc 其他系統的話自行百度一下把)附上我的hosts文件:
127.0.0.1 eureka3000.com
127.0.0.1 eureka3001.com
127.0.0.1 eureka3002.com
不過這個地方遇到這麼一個坑,也讓我可以看到,Eureka集羣起來之後再啓動UserServe服務器發現只註冊到3002上面,其他2個並沒有註冊
雖然UserServer配置了3個鏈接,也就是說UserServer在註冊中心註冊成功後不會再註冊到第二個上面,至於他們各自的數據都是再集羣中進行同步的
我們回到主題, 我們發現 集羣配置與單體不同的點在於 原來是把服務註冊到自己身上,而現在是註冊到其它服務身上
至於爲什麼不註冊自己了呢?,回到最上面我們說過,eureka的server會把自己的註冊信息與其他的server同步,所以這裏我們不需要註冊到自己身上,因爲另外兩臺服務器會配置本臺服務器。(這裏可能有點繞,可以參考一下剛剛那張集羣環境的圖,或者自己動手配置一下,另外兩臺eureka的配置與這個是差不多的,就不發出來了,只要注意是註冊到其他的服務上面就好了)
當三臺eureka配置好之後,全部啓動一下就可以看見效果了:
無論查詢3000,3001,3002都可以看到user服務
5.3 客戶端配置
defaultZone: http://localhost:3000/eureka,http://localhost:3001/eureka,http://localhost:3002/eureka
我們這裏只截取了要改動的那一部分。 就是 原來是註冊到那一個地址上面,現在是要寫三個eureka註冊地址,但是不是代表他會註冊三次,因爲我們eureka server的註冊信息是同步的,這裏只需要註冊一次就可以了,但是爲什麼要寫三個地址呢。因爲這樣就可以做到高可用的配置:打個比方有3臺服務器。但是突然宕機了一臺, 但是其他2臺還健在,依然可以註冊我們的服務,換句話來講, 只要有一臺服務還建在,那麼就可以註冊服務,這裏 需要理解一下。
無論是客戶端這種配置還是服務器雙向註冊都是爲了高可用,這種配置即便Eureka3個掛掉2臺也是可以使用的
6. CAP理論
1998年,加州大學的計算機科學家 Eric Brewer 提出,分佈式系統有三個指標。
Consistency —一致性
Availability —可用性
Partition tolerance —分區容錯性
他們第一個字母分別是C,A,P
Eric Brewer 說,這三個指標不可能同時做到。這個結論就叫做 CAP 定理。
1. Partition tolerance
中文叫做"分區容錯"。
大多數分佈式系統都分佈在多個子網絡。每個子網絡就叫做一個區(partition)。分區容錯的意思是,區間通信可能失敗。比如,一臺服務器放在本地,另一臺服務器放在外地(可能是外省,甚至是外國),這就是兩個區,它們之間可能無法通信。
上圖中,S1 和 S2 是兩臺跨區的服務器。S1 向 S2 發送一條消息,S2 可能無法收到。系統設計的時候,必須考慮到這種情況。
一般來說,分區容錯無法避免,因此可以認爲 CAP 的 P 總是成立。CAP 定理告訴我們,剩下的 C 和 A 無法同時做到。
Consistency
Consistency 中文叫做"一致性"。意思是,寫操作之後的讀操作,必須返回該值。舉例來說,某條記錄是 v0,用戶向 S1 發起一個寫操作,將其改爲 v1。
接下來用戶讀操作就會得到v1。這就叫一致性。
問題是,用戶有可能會向S2發起讀取操作,由於S2的值沒有發生變化,因此返回的是v0,所以S1和S2的讀操作不一致,這就不滿足一致性了
爲了讓S2的返回值與S1一致,所以我們需要在往S1執行寫操作的時候,讓S1給S2也發送一條消息,要求S2也變成v1
Availability
Availability 中文叫做"可用性",意思是隻要收到用戶的請求,服務器就必須給出迴應。
用戶可以選擇向 S1 或 S2 發起讀操作。不管是哪臺服務器,只要收到請求,就必須告訴用戶,到底是 v0 還是 v1,否則就不滿足可用性。
簡單一句話概括: 就是對S1寫操作的時候對S2是否進行鎖操作,如果鎖就不能進行滿足可用性,如果不鎖就不能滿足一致性
Consistency 和 Availability 的矛盾
一致性和可用性,爲什麼不可能同時成立?答案很簡單,因爲可能通信失敗(即出現分區容錯)。
如果保證 S2 的一致性,那麼 S1 必須在寫操作時,鎖定 S2 的讀操作和寫操作。只有數據同步後,才能重新開放讀寫。鎖定期間,S2 不能讀寫,沒有可用性不。
如果保證 S2 的可用性,
7 eureka對比Zookeeper:
Zookeeper在設計的時候遵循的是CP原則,即一致性,Zookeeper會出現這樣一種情況,當master節點因爲網絡故障與其他節點失去聯繫時剩餘節點會重新進行leader選舉,問題在於,選舉leader的時間太長:30~120s,且選舉期間整個Zookeeper集羣是不可用的,這就導致在選舉期間註冊服務處於癱瘓狀態,在雲部署的環境下,因網絡環境使Zookeeper集羣失去master節點是較大概率發生的事情,雖然服務能夠最終恢復,但是漫長的選舉時間導致長期的服務註冊不可用是不能容忍的。
Eureka在設計的時候遵循的是AP原則,即可用性。Eureka各個節點(服務)是平等的, 沒有主從之分,幾個節點down掉不會影響正常工作,剩餘的節點(服務) 依然可以提供註冊與查詢服務,而Eureka的客戶端在向某個Eureka註冊或發現連接失敗,則會自動切換到其他節點,也就是說,只要有一臺Eureka還在,就能註冊可用(保證可用性), 只不過查詢到的信息不是最新的(不保證強一致),除此之外,Eureka還有自我保護機制,如果在15分鐘內超過85%節點都沒有正常心跳,那麼eureka就認爲客戶端與註冊中心出現了網絡故障,此時會出現一下情況:
1: Eureka 不再從註冊列表中移除因爲長時間沒有收到心跳而過期的服務。
2:Eureka 仍然能夠接收新服務的註冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點可用)
3: 當網絡穩定後,當前實例新的註冊信息會被同步到其它節點中
結合我們平時生活中遇到的情況想想是ap原則還是cp原則:
比如:1雙十一大家都在搶同一個產品,搶到時候有但是付款的時候提示無貨? AP
2.12306搶票的時候可以搶到,但是付款是提醒佔座失敗? AP
3.京東,淘寶的秒殺…AP
4.付款時沒遇到過數據變化的吧 CP
…這種要求數據準確性比較高的必須是CP原則