Eureka

本文作者:@Ryan Miao本文鏈接:https://www.cnblogs.com/woshimrf/p/springclout-eureka.html版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 許可協議。轉載請註明出處!

目錄

前言
Eureka介紹
爲什麼需要Eureka
Eureka和AWS ELB有什麼不同
Eureka和Route 53有什麼不同
Eureka如何使用?
Eureka使用時機?
Eureka架構
非Java服務和客戶端
可配置
彈性
多區域
監控
Eureka服務治理體系
服務註冊
服務發現
Eureka服務端
Eureka客戶端
註冊中心
創建Eureka Server
高可用服務註冊中心
構建服務註冊中心集羣
失效剔除
自我保護
region(地域)與zone(可用區)
安全驗證
服務提供者 微服務集羣
服務註冊
服務同步
服務續約
創建並註冊服務提供者 Eureka Client
服務消費者 另一個微服務集羣
獲取服務
服務調用
服務下線
配置詳解
服務實例類配置
端點配置
元數據
健康檢測
其他配置
通訊協議
參考

由於樣式兼容性問題,本文後半部分被截斷,可到個人博客找到本文: https://blog.rmiao.top/springcloud-eureka/

前言

Oracle轉讓Java,各種動態語言的曝光率上升,Java工程師的未來在哪裏?我覺得Spring Cloud讓未來有無限可能。拖了半年之久的Spring Cloud學習就從今天開始了。中文教材不多,而且大多都是簡單的離散的信息,想要找到企業級的一體化解決方案很少。不過,對於入門來說,簡單就夠了,等到用的時候自然而然的彙總起來。

目標是把springcloud的子項目過一遍。

ComponentEdgware.SR2Finchley.M7Finchley.BUILD-SNAPSHOT
spring-cloud-aws1.2.2.RELEASE2.0.0.M42.0.0.BUILD-SNAPSHOT
spring-cloud-bus1.3.2.RELEASE2.0.0.M62.0.0.BUILD-SNAPSHOT
spring-cloud-cli1.4.1.RELEASE2.0.0.M12.0.0.BUILD-SNAPSHOT
spring-cloud-commons1.3.2.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-contract1.2.3.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-config1.4.2.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-netflix1.4.3.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-security1.2.2.RELEASE2.0.0.M22.0.0.BUILD-SNAPSHOT
spring-cloud-cloudfoundry1.1.1.RELEASE2.0.0.M32.0.0.BUILD-SNAPSHOT
spring-cloud-consul1.3.2.RELEASE2.0.0.M62.0.0.BUILD-SNAPSHOT
spring-cloud-sleuth1.3.2.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-streamDitmars.SR3Elmhurst.RC1Elmhurst.BUILD-SNAPSHOT
spring-cloud-zookeeper1.2.0.RELEASE2.0.0.M62.0.0.BUILD-SNAPSHOT
spring-boot1.5.10.RELEASE2.0.0.RC22.0.0.BUILD-SNAPSHOT
spring-cloud-task1.2.2.RELEASE2.0.0.M32.0.0.RELEASE
spring-cloud-vault1.1.0.RELEASE2.0.0.M62.0.0.BUILD-SNAPSHOT
spring-cloud-gateway1.0.1.RELEASE2.0.0.M72.0.0.BUILD-SNAPSHOT
spring-cloud-openfeign 2.0.0.M12.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服務治理體系

以下參考《Spring Cloud Eureka詳解》, 作者 大道化簡, 然而,後面發現是程序員dd的書籍裏的內容。在此正名,以下出自《Spring Cloud 微服務實戰》,作者翟永超。

大概讀完Eureka的簡介,應該可以知道Eureka是負責微服務架構中服務治理的功能,負責各個微服務實例的自動註冊和發現。

服務註冊

在服務治理框架中,通常都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供的服務,包括服務的主機與端口號、服務版本號、通訊協議等一些附加信息。註冊中心按照服務名分類組織服務清單,同時還需要以心跳檢測的方式去監測清單中的服務是否可用,若不可用需要從服務清單中剔除,以達到排除故障服務的效果。

服務發現

在服務治理框架下,服務間的調用不再通過指定具體的實例地址來實現,而是通過服務名發起請求調用實現。服務調用方通過服務名從服務註冊中心的服務清單中獲取服務實例的列表清單,通過指定的負載均衡策略取出一個服務實例位置來進行服務調用。

Eureka服務端

Eureka服務端,即服務註冊中心。它同其他服務註冊中心一樣,支持高可用配置。依託於強一致性提供良好的服務實例可用性,可以應對多種不同的故障場景。

Eureka服務端支持集羣模式部署,當集羣中有分片發生故障的時候,Eureka會自動轉入自我保護模式。它允許在分片發生故障的時候繼續提供服務的發現和註冊,當故障分配恢復時,集羣中的其他分片會把他們的狀態再次同步回來。集羣中的的不同服務註冊中心通過異步模式互相複製各自的狀態,這也意味着在給定的時間點每個實例關於所有服務的狀態可能存在不一致的現象。

Eureka客戶端

Eureka客戶端,主要處理服務的註冊和發現。客戶端服務通過註冊和參數配置的方式,嵌入在客戶端應用程序的代碼中。在應用程序啓動時,Eureka客戶端向服務註冊中心註冊自身提供的服務,並週期性的發送心跳來更新它的服務租約。同時,他也能從服務端查詢當前註冊的服務信息並把它們緩存到本地並週期行的刷新服務狀態。


註冊中心

在服務治理框架中,通常都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供的服務,包括服務的主機與端口號、服務版本號、通訊協議等一些附加信息。註冊中心按照服務名分類組織服務清單,同時還需要以心跳檢測的方式去監測清單中的服務是否可用,若不可用需要從服務清單中剔除,以達到排除故障服務的效果。

創建Eureka Server

測試代碼: https://github.com/Ryan-Miao/eureka-server

Eureka Server是基於springboot的,只要啓動一個springboot就可以了。start.spring.io提供了一系列啓動模板,而且Spring又和Idea比較曖昧,所以使用Idea可以超級簡單的搭建和集成Spring項目。

在Idea裏,新建項目,選擇Spring initializer.

然後,勾選你想要的組件就行了。這裏搜索Eureka Server, 選擇

當然,創建好項目後記得先修改編碼爲UTF8, 不然萬惡的GBK...

我的pom如下:


<?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中加入配置信息:

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

@EnableEurekaServer
@SpringBootApplication
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

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


server.port=1111

eureka.instance.hostname=master

eureka.client.serviceUrl.defaultZone=http://backup1:1112/eureka/,http://backup2:1113/eureka/

application-peer2.properties

server.port=1112

eureka.instance.hostname=backup1

eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup2:1113/eureka/

application-peer3.properties

server.port=1113

eureka.instance.hostname=backup2


eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup1:1112/eureka/

由於是本地開發環境,我們直接以maven啓動。當然,也可以選擇jar啓動。

分別打開3個命令行

mvn spring-boot:run -Dspring.profiles.active=peer1
mvn spring-boot:run -Dspring.profiles.active=peer2
mvn spring-boot:run -Dspring.profiles.active=peer3

注意,由於啓動的時候會去指定zone註冊,而另外的server還沒啓動,這時候會報錯,Cannot execute request on any known server, 不用理會,接着啓動後兩個即可。

全部啓動成功後,訪問http://master:1111/

可以看到2個備份,在線的server有3個Availability Zones。Availability Zones在AWS中是指可用區,是在不同region裏的不同機房。

註冊中心高可用集羣demo搭建完畢。

失效剔除

有些時候,我們的服務實例並不一定會正常下線,可能由於內存溢出、網絡故障等原因使服務不能正常運作。而服務註冊中心並未收到“服務下線”的請求,爲了從服務列表中將這些無法提供服務的實例剔除,Eureka Server在啓動的時候會創建一個定時任務,默認每隔一段時間(默認爲60秒)將當前清單中超時(默認爲90秒)沒有續約的服務剔除出去。

自我保護

服務註冊到Eureka Server後,會維護一個心跳連接,告訴Eureka Server自己還活着。Eureka Server在運行期間會統計心跳失敗的比例在15分鐘以之內是否低於85%,如果出現低於的情況,Eureka Server會將當前實例註冊信息保護起來,讓這些實例不會過期。這樣做會使客戶端很容易拿到實際已經不存在的服務實例,會出現調用失敗的情況。因此客戶端要有容錯機制,比如請求重試、斷路器。

以下是自我保護相關的屬性:

eureka.server.enableSelfPreservation=true. 可以設置改參數值爲false,以確保註冊中心將不可用的實例刪除

region(地域)與zone(可用區)

region和zone(或者Availability Zone)均是AWS的概念。在非AWS環境下,我們可以簡單地將region理解爲地域,zone理解成機房。一個region可以包含多個zone,可以理解爲一個地域內的多個不同的機房。不同地域的距離很遠,一個地域的不同zone間距離往往較近,也可能在同一個機房內。

region可以通過配置文件進行配置,如果不配置,會默認使用us-east-1。同樣Zone也可以配置,如果不配置,會默認使用defaultZone。

Eureka Server通過eureka.client.serviceUrl.defaultZone屬性設置Eureka的服務註冊中心的位置。

指定region和zone的屬性如下:

(1)eureka.client.availabilityZones.myregion=myzone# myregion是region

(2)eureka.client.region=myregion

Ribbon的默認策略會優先訪問通客戶端處於同一個region中的服務端實例,只有當同一個zone中沒有可用服務端實例的時候纔會訪問其他zone中的實例。所以通過zone屬性的定義,配合實際部署的物理結構,我們就可以設計出應對區域性故障的容錯集羣。

安全驗證

剛纔的demo中,我們註冊中心的面板是公開訪問的。這裏可以簡單加入用戶名密碼,讓訪問更安全。當然,你可以自己實現sso。
pom添加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然後,爲了簡單演示,事實上也應該這樣。我們將3個server的用戶名密碼設置一致。即,在application.properties裏添加:

security.user.name=admin
security.user.password=123456

然後,在我們其他三個配置文件中的eureka.client.serviceUrl.defaultZone添加自己的url並加入用戶名密碼,
以peer1爲例子

eureka.client.serviceUrl.defaultZone=http://${security.user.name}:${security.user.password}@${eureka.instance.hostname}:${server.port}/eureka/,http://backup1:1112/eureka/,http://backup2:1113/eureka/

服務提供者 微服務集羣

服務註冊

服務提供者在啓動的時候會通過REST請求的方式將自己註冊到Eureka Server上,同時帶上自身服務的一些元數據信息。Eureka Server接收到這個Rest請求之後,將元數據信息存儲在一個雙層結構的Map中,其中第一層的key是服務名。第二層的key 是具體服務的實例名。

在服務註冊時,需要確認一下eureka.client.register-with-eureka=true參數是否正確,該值默認爲true。若設置爲fasle將不會啓動註冊操作。

服務同步

從eureka服務治理體系架構圖中可以看到,不同的服務提供者可以註冊在不同的服務註冊中心上,它們的信息被不同的服務註冊中心維護。

此時,由於多個服務註冊中心互相註冊爲服務,當服務提供者發送註冊請求到一個服務註冊中心時,它會將該請求轉發給集羣中相連的其他註冊中心,從而實現服務註冊中心之間的服務同步。通過服務同步,提供者的服務信息就可以通過集羣中的任意一個服務註冊中心獲得。

服務續約

在註冊服務之後,服務提供者會維護一個心跳用來持續高速Eureka Server,“我還在持續提供服務”,否則Eureka Server的剔除任務會將該服務實例從服務列表中排除出去。我們稱之爲服務續約。

下面是服務續約的兩個重要屬性:

(1)eureka.instance.lease-expiration-duration-in-seconds

leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之後,等待下一次心跳的超時時間,在這個時間內若沒收到下一次心跳,則將移除該instance。

默認爲90秒

如果該值太大,則很可能將流量轉發過去的時候,該instance已經不存活了。
如果該值設置太小了,則instance則很可能因爲臨時的網絡抖動而被摘除掉。
該值至少應該大於leaseRenewalIntervalInSeconds

(2)eureka.instance.lease-renewal-interval-in-seconds

leaseRenewalIntervalInSeconds,表示eureka client發送心跳給server端的頻率。如果在leaseExpirationDurationInSeconds後,server端沒有收到client的心跳,則將摘除該instance。除此之外,如果該instance實現了HealthCheckCallback,並決定讓自己unavailable的話,則該instance也不會接收到流量。

默認30秒

創建並註冊服務提供者 Eureka Client

項目代碼: https://github.com/Ryan-Miao/eureka-client

Eureka Server是註冊中心,我們的客戶端也要集成Eureka client來自我註冊。我們client項目也是基於Springboot的。同樣創建一個新的項目 eureka-client. 這次,要引入Eureka Discovery以及健康檢查Actuator。最終pom如下:

<?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-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-client</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</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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>

然後,啓動類添加@EnableDiscoveryClient

@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }
}

最後,添加配置信息:

spring.application.name=eureka-client-service-provider
server.port=2001
eureka.client.serviceUrl.defaultZone=http://admin:123456@master:1111/eureka/,http://admin:123456@backup1:1112/eureka/,http://admin:123456@backup2:1113/eureka/

這裏,我們把三個註冊中心的地址都加上。然後,爲保證高可用,我們的服務提供者也需要集羣部署。真實生產環境中肯定是部署到不同的機器上,在本地模擬的話,我們只好以不同端口來模擬了。

啓動端口2001

mvn spring-boot:run -Dserver.port=2001

啓動端口2002

mvn spring-boot:run -Dserver.port=2002

然後,查看註冊中心面板。


服務消費者 另一個微服務集羣

獲取服務

消費者服務啓動時,會發送一個Rest請求給服務註冊中心,來獲取上面註冊的服務清單。爲了性能考慮,Eureka Server會維護一份只讀的服務註冊清單來返回給客戶端,同時該緩存清單默認會每隔30秒更新一次。

下面是獲取服務的兩個重要的屬性:

(1) eureka.client.fetch-registry

是否需要去檢索尋找服務,默認是true

(2)eureka.client.registry-fetch-interval-seconds

表示eureka client間隔多久去拉取服務註冊信息,默認爲30秒,對於api-gateway,如果要迅速獲取服務註冊狀態,可以縮小該值,比如5秒

服務調用

服務消費者在獲取服務清單後,通過服務名可以獲取具體提供服務的實例名和該實例的元數據信息。因爲有這些服務實例的詳細信息,所以客戶端可以根據自己的需要決定具體調用哪個實例,在Ribbon中會默認採用輪詢的方式進行調用,從而實現客戶端的負載均衡。

等學到Ribbon之後再繼續服務消費。

服務下線

在系統運行過程中必然會面臨關閉或重啓服務的某個實例的情況,在服務關閉操作時,會觸發一個服務下線的Rest服務請求給Eureka Server,告訴服務註冊中心:“我要下線了。”服務端在接收到該請求後,將該服務狀態置位下線(DOWN),並把該下線事件傳播出去。

配置詳解

服務實例類配置

端點配置

eureka實例的狀態頁面和健康監控的url默認爲spring boot actuator提供的/info端點和/health端點。我們必須確保Eureka客戶端的/health端點在發送元數據的時候,是一個能夠被註冊中心訪問到的地址,否則服務註冊中心不會根據應用的健康檢查來更改狀態(僅當開啓了healthcheck功能時,以該端點信息作爲健康檢查標準)。而如果/info端點不正確的話,會導致在Eureka面板中單擊服務時,無法訪問到服務實例提供的信息接口。

大多數情況下,我們不需要修改這個幾個url配置。但是當應用不使用默認的上下文(context path或servlet path,比如配置server.servletPath=/test),或者管理終端路徑(比如配置management.contextPath=/admin)時,我們需要修改健康檢查和狀態頁的url地址信息。

application.yml配置文件如下:

server.context-path=/helloeureka

//下面配置爲相對路徑,也支持配置成絕對路徑,例如需要支持https

eureka.instance.health-check-url-path=${server.context-path}/health

eureka.instance.status-page-url-path=${server.context-path}/info

元數據

元數據是Eureka客戶端在向服務註冊中心發送註冊請求時,用來描述自身服務信息的對象,其中包含了一些標準化的元數據,比如服務名稱、實例名稱、實例IP、實例端口等用於服務治理的重要信息;以及一些用於負載均衡策略或是其他特殊用途的自定義元數據信息。

我們可以通過eureka.instance.<properties>=<value>的格式對標準化元數據直接進行配置,其中<properties>就是EurekaInstanceConfigBean對象中的成員變量。而對於自定義元數據,可以通過eureka.instance.metadataMap.<key>=<value>的格式來進行配置。比如:

eureka.instance.metadataMap.zone=tianjin

//隨機生成實例名

eureka.instance.metadataMap.instanceId=${spring.application.name}:${random.value}

健康檢測

默認情況下,Eureka中各個服務實例的健康檢測並不是通過spring-boot-acturator模塊的/health端點來實現的,而是依靠客戶端心跳的方式來保持服務實例的存活。在Eureka的服務續約與剔除機制下,客戶端的健康狀態從註冊到註冊中心開始都會處於UP狀態,除非心跳終止一段時間之後,服務註冊中心將其剔除。默認的心跳實現方式可以有效檢查客戶端進程是否正常運作,但卻無法保證客戶端應用能夠正常提供服務。

在Spring Cloud Eureka中,可以把Eureka客戶端的健康檢測交給spring-boot-actuator模塊的health端點,以實現更加全面的健康狀態維護,設置方式如下:

(1) 在pom.xml中引入spring-boot-starter-actuator模塊的依賴

(2) 在application.properties中增加參數配置eureka.client.healthcheck.enabled=true

這裏,Idea裏並沒有提示eureka.client.healthcheck.enabled這個屬性,並且還顯示黃色,讓以爲是不是哪裏錯了,根本不敢嘗試。不過百度後,發現有人做了類似實驗,成功了。好吧,可能對這個的學習還不夠,或者就應該給Idea提一個issue。下面給出自定義health check來替換Eureka自帶心跳測試。

自己實現HealthChecker

根據自己health的定義,自己實現一個HealthChecker。這裏簡單模擬。
在eureka-client創建MyHealthChecker,

@Component
public class MyHealthChecker implements HealthIndicator {


    private volatile boolean up = true;

    @Override
    public Health health() {
        if (up) {
            return new Health.Builder().withDetail("aaa_cnt", 10) //自定義監控內容
                    .withDetail("bbb_status", "up").up().build();
        } else {
            return new Health.Builder().withDetail("error", "client is down").down().build();
        }

    }

    public boolean isUp() {
        return up;
    }

    public void setUp(boolean up) {
        this.up = up;
    }
}

然後,暴露出一個接口來控制up狀態。


@RestController
public class HealthSettingController {

    @Autowired
    MyHealthChecker myHealthChecker;

    @RequestMapping("/health/{status}")
    public String up(@PathVariable("status") Boolean status) {
        myHealthChecker.setUp(status);

        return status.toString();
    }

}

然後在我們的客戶端eureka-clientp配置文件裏新增eureka.client.healthcheck.enabled=true

重新啓動,訪問http://localhost:2001/health/false來把我們client端中一個instance設置爲down。然後,刷新eureka server面板,即訪問http://master:1111/, 可以看到,我們的client確實下線了。

其他配置

除了上述配置參數外,下面整理了一些EurekaInstanceConfigBean中定義的配置參數以及對應的說明和默認值,這些參數均以eureka.instance爲前綴。

通訊協議

默認情況下,Eureka使用Jersey和XStream配合JSON作爲Server與Client之間的通訊協議。也可以選擇實現自己的協議來代替。

參考


發佈了26 篇原創文章 · 獲贊 11 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章