springcloud-eureka詳解
前言
Oracle轉讓Java,各種動態語言的曝光率上升,Java工程師的未來在哪裡?我覺得Spring Cloud讓未來有無限可能。拖了半年之久的Spring Cloud學習就從今天開始了。中文教材不多,而且大多都是簡單的離散的資訊,想要找到企業級的一體化解決方案很少。不過,對於入門來說,簡單就夠了,等到用的時候自然而然的彙總起來。
目標是把springcloud的子專案過一遍。
Component | Edgware.SR2 | Finchley.M7 | Finchley.BUILD-SNAPSHOT |
---|---|---|---|
spring-cloud-aws | 1.2.2.RELEASE | 2.0.0.M4 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-bus | 1.3.2.RELEASE | 2.0.0.M6 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-cli | 1.4.1.RELEASE | 2.0.0.M1 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-commons | 1.3.2.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-contract | 1.2.3.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-config | 1.4.2.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-netflix | 1.4.3.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-security | 1.2.2.RELEASE | 2.0.0.M2 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-cloudfoundry | 1.1.1.RELEASE | 2.0.0.M3 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-consul | 1.3.2.RELEASE | 2.0.0.M6 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-sleuth | 1.3.2.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-stream | Ditmars.SR3 | Elmhurst.RC1 | Elmhurst.BUILD-SNAPSHOT |
spring-cloud-zookeeper | 1.2.0.RELEASE | 2.0.0.M6 | 2.0.0.BUILD-SNAPSHOT |
spring-boot | 1.5.10.RELEASE | 2.0.0.RC2 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-task | 1.2.2.RELEASE | 2.0.0.M3 | 2.0.0.RELEASE |
spring-cloud-vault | 1.1.0.RELEASE | 2.0.0.M6 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-gateway | 1.0.1.RELEASE | 2.0.0.M7 | 2.0.0.BUILD-SNAPSHOT |
spring-cloud-openfeign | 2.0.0.M1 | 2.0.0.BUILD-SNAPSHOT |
本次學習服務註冊與發現, Eureka。
Eureka介紹
Eureka是一個基於REST(Representational State Transfer)的服務,主要用於AWS cloud, 提供服務定位(locating services)、負載均衡(load balancing)、故障轉移(failover of middle-tier servers)。我們把它叫做Eureka Server. Eureka也提供了基於Java的客戶端元件,Eureka Client,內建的負載均衡器可以實現基本的round-robin負載均衡能力。在Netflix,一個基於Eureka的更復雜的負載均衡器針對多種因素(如流量、資源利用率、錯誤狀態等)提供加權負載均衡,以實現高可用(superior resiliency).
為什麼需要Eureka
在AWS Cloud,由於其天生的特性,伺服器經常變換。我們知道每個EC2掛掉後,重啟又是一個新的。不像傳統的固定IP,AWS的伺服器是變化的。因此需要更復雜的負載均衡方案來動態註冊和登出。由於AWS並沒有提供中間層負載均衡解決方案,Eureka填補了這個領域的巨大空白。
Eureka和AWS ELB有什麼不同
AWS ELB(Elastic Load Balancer)是面向終端使用者Web流量的邊緣服務的負載均衡解決方案。Eureka填補了對中間層負載均衡的需求。理論上,你可以把中間層服務放在AWS ELB之後,但在EC2模型中,你將會把他們直接暴露到外網,從而失去了AWS security groups的好處。(這裡有疑問,我現實使用的時候ELB也有區分VPC的,所以不會暴露到外網,不知道是不是本文釋出的時候AWS還沒這功能,所以感覺Eureka和ELB區別不大啊)。
AWS ELB也是一種傳統的基於代理的負載平衡解決方案,而Eureka則不同之處在於負載平衡發生在例項/伺服器/主機級別。客戶端例項知道他們需要與哪些伺服器互動的所有資訊。這樣的好壞取決於你怎麼看待它。如果你想要AWS現在提供的基於粘滯使用者session的負載均衡,Eureka沒有開箱即用的解決方案。在Netflix,我們更喜歡我們的服務是無狀態的(非粘性)。這有利於提供更好的擴充套件性,Eureka非常適合解決這個問題。(感覺這段也是吹水,現在的web互動大都是無狀態的,狀態通過redis,message queue等第三方維護,ELB照樣可以提供)。
使用Eureka區分基於代理的負載平衡和負載平衡的另一個重要方面是,您的應用程式可以靈活地處理負載平衡器的中斷,因為有關可用伺服器的資訊會快取在客戶端上。這確實需要少量的記憶體,但換得更好的彈性。
Eureka和Route 53有什麼不同
Route 53是一個域名服務,就像Eureka可以為中層伺服器提供相同的服務一樣,但僅此而已。 Route 53是一項DNS服務,即使對於非AWS資料中心,也可以託管您的DNS記錄。 Route 53還可以在AWS區域間執行基於延遲的路由。Eureka類似於內部DNS,與全世界的DNS伺服器無關。Eureka也是區域隔離的,因為它不知道其他AWS區域中的伺服器。儲存資訊的主要目的是在區域內進行負載平衡。
雖然你可以在Route 53中註冊你的中間層伺服器,並依賴AWS安全組保護你的伺服器不受外網訪問,但你的中間層伺服器身份仍然暴露於外網環境。它同樣帶有傳統基於DNS的負載均衡方案的缺點,其中流量仍然會被路由到已經不健康或已經不存在的伺服器上(在AWS雲中,伺服器隨時可能消失)。
Eureka如何使用?
在Netflix,Eureka不僅是中間層負載均衡關鍵部分,還有以下功能:
與Netflix Asgard一起提供紅/黑部署服務, Asgard是一個讓雲部署更方便的開源服務。Eureka會與Asgard搭配,讓應用在新/老版本部署切換,讓故障處理更快速和無縫,尤其是當啟動100個例項部署時要花費很長時間的時候。
當我們的cassandra需要維護時,停止Cassandra例項。
為我們的memcached快取服務提供識別環上例項列表功能。
為特定的應用提供因意外導致故障儲存元資訊的服務。
Eureka使用時機?
當你的服務執行在AWS雲上並且你不希望使用AWS ELB註冊或暴露給外網。你要麼需要使用類似round-robin這種簡單的負載均衡方案或者想要寫一個基於Eureka包裝過的符合要求的負載均衡器。你沒有session粘性,沒有session繫結機制和在外部快取(例如 memcached)載入會話資料的需要。更重要的是,如果你的架構風格適合一個基於客戶端的負載均衡模型,Eureka相當適合這個場景。
應用客戶端和應用服務端如何通訊?
通訊技術可以是任何你喜歡的。Eureka幫你找到你需要通訊的服務資訊但沒有引入任何通訊協議或方法的限制。比如,你可以用Eureka獲取目標伺服器地址並使用thrift,http(s)或其他RPC機制的協議。
Eureka架構
上面的架構圖描述了Eureka是如何在Netflix部署的,這也是Eureka叢集的執行方式。在每個區域(region)都有一個eureka叢集,它只知道該區域內的例項資訊。每個分割槽(zone)至少有一個eureka伺服器來處理本分割槽故障。
服務註冊在Eureka上並且每30秒傳送心跳來續租。如果一個客戶端在幾次內沒有重新整理心跳,它將在大約90秒內被移出伺服器登錄檔。註冊資訊和更新資訊會在整個eureka叢集的節點進行復制。任何分割槽的客戶端都可查詢註冊中心資訊(每30秒發生一次)來定位他們的服務(可能會在任何分割槽)並進行遠端呼叫。
非Java服務和客戶端
對於非Java的服務,你可以用其他語言實現eureka的客戶端部分。基於REST的服務也暴露給了所有操作給Eureka客戶端。非Java客戶端也可以使用REST服務來查詢其他服務的資訊。
可配置
有了Eureka,你可以動態新增刪除叢集節點。你可以調整內部配置,從超時到執行緒池。Eureka使用archaius並且如果你有一個配置源的實現,那麼很多配置可以動態調優。
彈性
在AWS雲中,構建彈性伸縮必不可少。Eureka是我們經驗的結晶,並且在客戶端和服務端都內建了彈效能力。
Eureka客戶端設計成可以處理一個或多個Eureka服務端的失敗場景。由於Eureka客戶端有登錄檔快取資訊,即使所有的eureka伺服器都掛了,服務也能正常執行。
Eureka伺服器對於其他eureka節點掛了也提供了足夠的彈性。即使服務端和客戶端之間產生了網路分割槽,伺服器也由內建的彈性策略來防止大規模的停機。
多區域
在多個AWS區域部署Eureka是一個很簡單的工作。不同區域之間Eureka叢集並不通訊。
監控
Eureka使用servo來跟蹤服務端和客戶端的資訊,包括效能,監控和報警。資料儲存在JMX中並暴露給Amazon Cloud Watch。
Eureka服務治理體系
大概讀完Eureka的簡介,應該可以知道Eureka是負責微服務架構中服務治理的功能,負責各個微服務例項的自動註冊和發現。
盜圖一張, 畫的很好。
服務註冊
在服務治理框架中,通常都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供的服務,包括服務的主機與埠號、服務版本號、通訊協議等一些附加資訊。註冊中心按照服務名分類組織服務清單,同時還需要以心跳檢測的方式去監測清單中的服務是否可用,若不可用需要從服務清單中剔除,以達到排除故障服務的效果。
服務發現
在服務治理框架下,服務間的呼叫不再通過指定具體的例項地址來實現,而是通過服務名發起請求呼叫實現。服務呼叫方通過服務名從服務註冊中心的服務清單中獲取服務例項的列表清單,通過指定的負載均衡策略取出一個服務例項位置來進行服務呼叫。
Eureka服務端
Eureka服務端,即服務註冊中心。它同其他服務註冊中心一樣,支援高可用配置。依託於強一致性提供良好的服務例項可用性,可以應對多種不同的故障場景。
Eureka服務端支援叢集模式部署,當叢集中有分片發生故障的時候,Eureka會自動轉入自我保護模式。它允許在分片發生故障的時候繼續提供服務的發現和註冊,當故障分配恢復時,叢集中的其他分片會把他們的狀態再次同步回來。叢集中的的不同服務註冊中心通過非同步模式互相複製各自的狀態,這也意味著在給定的時間點每個例項關於所有服務的狀態可能存在不一致的現象。
Eureka客戶端
Eureka客戶端,主要處理服務的註冊和發現。客戶端服務通過註冊和引數配置的方式,嵌入在客戶端應用程式的程式碼中。在應用程式啟動時,Eureka客戶端向服務註冊中心註冊自身提供的服務,並週期性的傳送心跳來更新它的服務租約。同時,他也能從服務端查詢當前註冊的服務資訊並把它們快取到本地並週期行的重新整理服務狀態。
註冊中心
在服務治理框架中,通常都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供的服務,包括服務的主機與埠號、服務版本號、通訊協議等一些附加資訊。註冊中心按照服務名分類組織服務清單,同時還需要以心跳檢測的方式去監測清單中的服務是否可用,若不可用需要從服務清單中剔除,以達到排除故障服務的效果。
建立Eureka Server
Eureka Server是基於springboot的,只要啟動一個springboot就可以了。start.spring.io提供了一系列啟動模板,而且Spring又和Idea比較曖昧,所以使用Idea可以超級簡單的搭建和整合Spring專案。
在Idea裡,新建專案,選擇Spring initializer.
然後,勾選你想要的元件就行了。這裡搜尋Eureka Server, 選擇
當然,建立好專案後記得先修改編碼為UTF8, 不然萬惡的GBK…
我的pom如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>eureka-server</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka-server</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Edgware.SR2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
然後,在application.properties中加入配置資訊:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | spring.application.name=eureka-server #服務註冊中心埠號 server.port=1110 #服務註冊中心例項的主機名 eureka.instance.hostname=localhost #是否向服務註冊中心註冊自己 eureka.client.register-with-eureka=false #是否檢索服務 eureka.client.fetch-registry=false #服務註冊中心的配置內容,指定服務註冊中心的位置 eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ |
修改啟動類,新增@EnableEurekaServer
1 2 3 4 5 6 7 8 | public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } |
然後,啟動main方法即可。如果埠有衝突,修改合適的埠重啟。demo中埠為1110,啟動後,訪問http://localhost:1110/ 可以看到狀態控制檯。
前文也說了,上述demo是註冊中心,所有的微服務要向本server註冊以實現負載均衡。那麼,首先就要保證註冊中心的穩定,於是就必須搭建Eureka叢集的高可用方案。
高可用服務註冊中心
考慮到發生故障的情況,服務註冊中心發生故障必將會造成整個系統的癱瘓,因此需要保證服務註冊中心的高可用。
Eureka Server在設計的時候就考慮了高可用設計,在Eureka服務治理設計中,所有節點既是服務的提供方,也是服務的消費方,服務註冊中心也不例外。
Eureka Server的高可用實際上就是將自己做為服務向其他服務註冊中心註冊自己,這樣就可以形成一組互相註冊的服務註冊中心,以實現服務清單的互相同步,達到高可用的效果。
構建服務註冊中心叢集
Eureka Server的同步遵循著一個非常簡單的原則:只要有一條邊將節點連線,就可以進行資訊傳播與同步。可以採用兩兩註冊的方式實現叢集中節點完全對等的效果,實現最高可用性叢集,任何一臺註冊中心故障都不會影響服務的註冊與發現.
所以,下面建立3個Eureka Server兩兩互相註冊,形成叢集。由於核心程式碼一樣,我們只要將其部署在不同的機器上即可。因此,我需要3個不同的配置檔案。
為了本地模擬,修改host,虛擬3個域名
windows host 位置C:\Windows\System32\drivers\etc
1 2 3 | 127.0.0.1 master 127.0.0.1 backup1 127.0.0.1 backup2 |
然後,給我們的Eureka Server增加3個配置檔案。此時,應該將application.properties裡除了spring.application.name之外的配置註釋掉,我們後面3個配置暫時不用上面幾個開關。
application-peer1.properties
1 2 3 4 5 6 | server.port=1111 eureka.instance.hostname=master eureka.client.serviceUrl.defaultZone=http://backup1:1112/eureka/,http://backup2:1113/eureka/ |
application-peer2.properties
1 2 3 4 5 | server.port=1112 eureka.instance.hostname=backup1 eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup2:1113/eureka/ |
application-peer3.properties
1 2 3 4 5 6 | server.port=1113 eureka.instance.hostname=backup2 eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup1:1112/eureka/ |
由於是本地開發環境,我們直接以maven啟動。當然,也可以選擇jar啟動。
分別開啟3個命令列
1 2 3 | mvn spring-boot:run -Dsp
|