上一章節,講解了在單機模式下的服務註冊與發現的相關知識點及簡單示例。而在實際生產或者在這種微服務架構的分佈式環境中,須要考慮發生故障時,各組件的高可用。而其實高可用,個人簡單粗俗理解就是,經過系統的冗餘進行高可用,或者是進行集羣部署,保證一臺服務不可用時,會進行自動轉移至可用的服務中。今天的章節,就來講說關於
Eureka
的高可用吧。html
講解前,咱們先來聊聊在使用
Dubbo
時耳聞能詳的Zookeeper
和Eureka
之間的區別吧。java
根據百度百科的定義,CAP定理又稱CAP原則,指的是在一個分佈式系統中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),最多隻能同時三個特性中的兩個,三者不可兼得。git
在分佈式領域,你們應該對CAP
理論不陌生了吧(瞭解但也是沒有深刻了解過⊙﹏⊙‖∣)。github
如下摘至百度百科:web
● 一致性(C):在分佈式系統中的全部數據備份,在同一時刻是否一樣的值。(等同於全部節點訪問同一份最新的數據副本)spring
● 可用性(A):在集羣中一部分節點故障後,集羣總體是否還能響應客戶端的讀寫請求。(對數據更新具有高可用性)api
● 分區容錯性(P):以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇。瀏覽器
至於爲什麼不能同時知足,以上在分區容錯性也有簡單的說明了,通常來講,分區容錯沒法避免,所以能夠認爲CAP
的P
老是成立,而對於一致性和可用性爲什麼不能同時知足,簡單來講就是:存在可能通訊失敗狀況,即:出現分區容錯,至於更詳細具體的,你們能夠看下大佬阮一峯的這篇文章:CAP 定理的含義。這裏就不闡述了,不是很瞭解~緩存
對於Eureka而言,其是知足
AP
的,而Zookeeper而言,是知足CP
的。安全
Eureka是知足AP
的:
Zookeeper是知足AP
的:
個人簡單理解:因爲Zookeeper
有loader選舉策略,使其能夠保證數據的一致性。而Eureka
,本事沒有選舉策略,各服務是獨立運行的,至少在某一時刻,各服務之間的數據是不一致的,而在可用性方面,Zookeeper
也是因爲選舉策略緣由,在選舉期間是,整個zookeeper
是不可用的,會形成短暫(看選舉時長)的服務不可用。而對於Eureka
而言,服務是獨立運行的,因此不會由於某臺服務不可用致使了其餘服務不可用狀況。感受上面有點繞,簡單來講,就是Zookeeper
經過選舉策略保證數據的一致性,但缺失了可用性,Eureka
因爲服務獨立運行,經過心跳等通訊策略進行數據同步,存在數據不一致性,但保證了服務的可用性。
因此,綜上所述,做爲服務註冊中心而言,可用性原則是比數據一致性更重要的,同時上一章節也有說過,因爲Eureka
有自我保護模式,可保護服務註冊表中的信息不被剔除,因此Eureka
能夠很好的應對因網絡故障致使節點失去聯繫的狀況。
官網中,關於Eureka
的高可用部分是這麼描述的:
因此能夠獲悉,Eureka Server
能夠運行多個實例來構建集羣,解決單點問題,Eureka Server
採用的是Peer to Peer對等通訊。這是一種去中心化的架構,無master/slave區分,每個Peer都是對等的。在這種架構中,節點經過彼此互相註冊來提升可用性,每一個節點須要添加一個或多個有效的serviceUrl指向其餘節點。每一個節點均可被視爲其餘節點的副本。
若是某臺Eureka Server
宕機,Eureka Client
的請求會自動切換到新的Eureka Server
節點,當宕機的服務器從新恢復後,Eureka
會再次將其歸入到服務器集羣管理之中。當節點開始接受客戶端請求時,全部的操做都會進行replicateToPeer(節點間複製)
操做,將請求複製到其餘Eureka Server
當前所知的全部節點中。
因此,簡單來講,Eureka Server
的高可用,實際上就是將本身也做爲服務向其餘服務註冊中心進行註冊,這樣就能夠造成一組相互註冊的服務註冊中心,以實現服務清單的互相同步,達到高可用的效果。
另外,從官網文檔中有提到Zones
、Regions
,Region
和Zone
(或者Availability Zone)均是AWS的概念。在非AWS環境下,咱們能夠先簡單地將region理解爲Eureka集羣,zone理解成機房。下圖就能夠理解爲一個Eureka集羣被部署在了zone1機房和zone2機房中。
對這些概念的其餘相關知識,也深刻了解,你們感興趣,可自行搜索下吧。
示例前,先看看集羣模式下,Eureka的架構圖。
具體的原理分析,能夠看看這篇比較早的文章:https://nobodyiam.com/2016/06/25/dive-into-eureka/,雖然是比較早的文章,但寫的比較詳細,能夠看看。
接下來,以官網文檔demo,示例下。
經過點對點配置,註冊中心經過相互註冊來實現高可用配置。如下構建一個雙節點的集羣模式。
修改spring-cloud-eureka-server
項目。
0.建立一個application-ha.properties
配置文件,同時修改application.properties
文件。
application-ha.properties
spring.application.name=eureka-service-ha # 修改端口 server.port=1001 # 實例的主機名稱 eureka.instance.hostname=myPeer2 ## 不要向註冊中心註冊本身 #eureka.client.register-with-eureka=false ## 表示不去檢索其餘的服務,由於服務註冊中心自己的職責就是維護服務實例,它也不須要去檢索其餘服務 #eureka.client.fetch-registry=false # 指定服務註冊中心地址 eureka.client.service-url.defaultZone=http://myPeer1:1000/eureka
application.properties
spring.application.name=eureka-service-ha # 修改端口 server.port=1000 # 實例的主機名稱 eureka.instance.hostname=myPeer1 ## 不要向註冊中心註冊本身 #eureka.client.register-with-eureka=false ## 表示不去檢索其餘的服務,由於服務註冊中心自己的職責就是維護服務實例,它也不須要去檢索其餘服務 #eureka.client.fetch-registry=false # 指定服務註冊中心地址 eureka.client.service-url.defaultZone=http://myPeer2:1000/eureka #spring.profiles.active=ha
1.因爲是在同一臺進行模擬,首先修改hosts
文件,當瀏覽器請求一個地址時,首先會今後文件選擇對應對應的IP地址,找不到時才請求CDS域名解析服務器進行解析
C:\Windows\System32\drivers\etc\hosts
文件:
127.0.0.1 myPeer1 127.0.0.1 myPeer2
友情提示:若提示無修改權限,可根據如下網址進行相應修改:編輯hosts文件沒法保存怎麼辦
2.啓動應用,咱們這裏直接啓動兩個,可經過修改spring.profiles.active
值來啓動不一樣環境的應用,或者使用-jar xx.jar --spring.profiles.active=xx
來啓動。
題外話:第一個啓動的應用,後臺會報錯Connection refused: connect
,等第二個應用啓動後,就正常了~
客戶端只須要經過修改配置文件的
eureka.client.service-url.defaultZone
值便可。
修改spring-cloud-eureka-client
項目
0.修改配置文件application.properties
spring.application.name=eureka-client server.port=2000 # 註冊中心地址 eureka.client.service-url.defaultZone=http://myPeer1:1000/eureka,http://myPeer2:1001/eureka # 啓用ip配置 這樣在註冊中心列表中看見的是以ip+端口呈現的 eureka.instance.prefer-ip-address=true # 實例名稱 最後呈現地址:ip:2000 eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
固然,也可只註冊到某個節點上,其餘的節點也會有此服務列表的,通常建議以集羣方式進行配置,即多註冊中心配置。避免單點故障,Eureka在搜索註冊中心時,根據defaultZone列表,找到一個可用的,以後就不會繼續去下一個註冊中心地址拉取服務列表了,此時若其中一個註冊中心掛了,這個時候客戶端會繼續去第二個註冊中心拉取服務列表的。
啓動後,能夠看見eureka-client
註冊上去了。
如今咱們中止一個應用,能夠看出不可用的服務列表中已經有相關信息了
爲了驗證高可用性是否成功,建立一個
spring-cloud-eureka-server-ha-test
項目,做爲服務消費者使用RestTemplate+ribbon
進行調用spring-cloud-eureka-client
的服務。
建立spring-cloud-eureka-server-ha-test
項目 0.引入pom依賴
<!-- 客戶端依賴 --> <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-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!-- 引入web,提供一個簡單的api接口 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
1.配置文件,配置註冊中心地址
spring.application.name=eureka-ha-test server.port=8888 #指定註冊中心地址 eureka.client.serviceUrl.defaultZone=http://myPeer1:1000/eureka/,http://myPeer2:1001/eureka/ # 啓用ip配置 這樣在註冊中心列表中看見的是以ip+端口呈現的 eureka.instance.prefer-ip-address=true # 實例名稱 最後呈現地址:ip:2000 eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
2.啓動類,配置RestTemplate
Bean類,同時加入@LoadBalanced註解實現服務調用。
@SpringCloudApplication @EnableDiscoveryClient @Slf4j public class EurekaServiceHaApplication { public static void main(String[] args) throws Exception { SpringApplication.run(EurekaServiceHaApplication.class, args); log.info("spring-cloud-eureka-server-ha-test啓動!"); } //加入負載均衡能力 //同時可根據applicationName 來訪問服務 //如http://EUREKA-CLIENT/add @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
3.編寫一個控制類,簡單調用EUREKA-CLIENT
服務方法。
/** * 調用簡單示例 * @author oKong * */ @RestController public class DemoController { @Autowired private RestTemplate testTemplate; @GetMapping("/") public String index() { //訪問服務提供者 return testTemplate.getForObject("http://EUREKA-CLIENT/", String.class); } }
4.啓動應用類,訪問註冊中心和http://127.0.0.1:8888 。
可看見輸出spring-cloud-eureka-client!
代表調用成功。在控制檯也能夠看見,從註冊中心拉取了EUREKA-CLIENT
的服務地址:
這個時候,能夠試着中止其中一個甚至所有的Eureka Server
,再繼續訪問,能夠看見服務仍是能夠調用的,但要知道此時調用方是多是根據本地的緩存列表中直接獲取地址的,而不是從註冊服務中心,等待下次心跳機制時間到時,纔會去進行拉取最新的服務列表的。
關於RestTemplate
和Ribbon
相關知識點,會在下一章節進行闡述的,這裏就不敞開了。
第一次看官網文檔進行demo時,還在想經過設置端口號不就能夠了嗎,爲什麼還須要指定eureka.instance.hostname
呢,多麻煩?嘗試下使用ip或者不配置試試看。
eureka.instance.hostname
爲localhost
或者127.0.0.1
時,能夠看見,在DS Replicas
中是空的,說明沒有可複製的服務,registered-replicas
和available-replicas
都是空的。
客戶端配置eureka.client.service-url.defaultZone
。
eureka.client.service-url.defaultZone=http://127.0.0.1:1001/eureka,http://127.0.0.1:1000/eureka
會發現,在1001
服務上有註冊上去,1000
服務沒有服務信息。(客戶端註冊是按順序進行優先註冊和獲取服務列表的)
1001服務:
1000服務:
這說明集羣模式是沒有生效的,註冊中心之間沒有相互複製服務列表。
127.0.0.1
,另外一個修改爲localhost
或者實際內網ip地址說明下: 1001對應hostname
爲:127.0.0.1 1000對應hostname
爲:192.168.81.1
1001服務:
1000服務:
會發現,集羣模式成功了。 接着咱們啓動客戶端。
1000服務:
1001服務:
能夠看見,和上面設置myPeer1
和myPeer2
效果是同樣的,都有被複制了。
從上面能夠大體獲悉,Eureka
互相註冊要求各個Eureka server
實例的eureka.instance.hostname
不一樣,若是相同,則會被Eureka
標記爲unavailable-replicas
(像本地設置爲127.0.0.1,乾脆就不顯示了,具體不明。。⊙﹏⊙‖∣),以前的同步就失效了。而對於客戶端的defaultZone
配置而言,是優先從第一個開始註冊和拉取服務的,成功聯通後就不會再繼續找下一個註冊服務了。
綜上所述:
Eureka server
服務時,設置每一個服務 的hostname
不一致,同時要設置eureka.instance.prefer-ip-address
爲false
,不使用IP地址進行註冊。hostname
爲本機的ip地址,可以使用spring.cloud.client.ip-address
變量進行賦值。同時設置eureka.instance.prefer-ip-address
爲true
。這樣的話,客戶端使用ip進行鏈接就方便了,否則還要去配置host有點坑了。defaultZone
建議仍是配置多個註冊中心地址。就算自己集羣模式無效,好歹其中一個不可用了,還能連其餘的註冊中心呀。在最後收尾時,搜索到一篇文章,也是大體的意思,你們能夠點擊看一看:構建高可用Eureka註冊中心
其源碼地址:https://github.com/wangfei0904306/eureka-HA
以上可能理解有誤差,還但願知道的同窗能不吝賜教下,謝謝了!
默認狀況下,訪問註冊中心頁面是匿名訪問的,不須要一些認證。在生產中,爲了安全性,可加入身份認證功能。
添加認證很簡單,官網文檔也有說明:
0.加入pom依賴:
<!-- 開啓認證 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
1.修改配置文件,設置用戶名和密碼及集羣狀態下,註冊至其餘服務中心時,加入用戶名和密碼:
# 設置賬號密碼 # 若不設置 默認賬號是user,密碼隨機,啓動時會打印在控制檯上 spring.security.user.name=oKong spring.security.user.password=123456 # 加入用戶名和密碼 eureka.client.service-url.defaultZone=http://oKong:123456@127.0.0.1:1001/eureka
友情提示:不設置name和password時,默認用戶是user,密碼是隨機的,啓動時會打印在控制檯上的:
2.修改啓動類,根據官網的提示,關閉/eureka/**
的CSRF的令牌。
/** * Eureka服務端 * @author oKong * */ @SpringBootApplication @EnableEurekaServer @Slf4j public class EureakServiceApplication { public static void main(String[] args) throws Exception { SpringApplication.run(EureakServiceApplication.class, args); log.info("spring-cloud-eureka-service啓動!"); } /** * 忽略此路徑下的CSRF令牌 * @author oKong * */ @EnableWebSecurity static class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().ignoringAntMatchers("/eureka/**"); super.configure(http); } } }
3.啓動應用。再次訪問:http:127.0.0.1:1000 時,就須要輸入用戶名和密碼了。
4.客戶端也是相似的,修改defaultZone
加入用戶名和密碼便可:
eureka.client.service-url.defaultZone=http://oKong:123456@127.0.0.1:1001/eureka,http://oKong:123456@127.0.0.1:1000/eureka
本章節主要是
Eureka
服務的高可用進行了簡單的介紹了下。對於集羣模式下的一些最佳實踐仍是有待商討的,還但願你們能說說自個的方案!至於一些其餘的特性,如元數據
配置等,這裏就不闡述了,用的很少。同時,本章節利用RestTemplate+ribbon
進行了簡單的服務調用,沒有敞開說,下一章節就是開始講解服務消費者
相關知識點,應該也會分紅兩章節來描述,由於涉及到了Ribbon
和Feign
相關知識點。我一直以爲使用都是很簡單的,只有理解裏面的原理之類的,這樣纔是一通百通吧,加深印象!使用起來也能比較順利。
目前互聯網上大佬都有分享
SpringCloud
系列教程,內容可能會相似,望多多包涵了。原創不易,碼字不易,還但願你們多多支持。若文中有錯誤之處,還望提出,謝謝。
499452441
lqdevOps
我的博客:http://blog.lqdev.cn
源碼示例:https://github.com/xie19900123/spring-cloud-learning
原文地址:http://blog.lqdev.cn/2018/09/09/SpringCloud/chapter-three/