跟我學Spring Cloud(Finchley版)-06-服務註冊與服務發現-Eureka深入

跟我學Spring Cloud(Finchley版)-05-服務註冊與服務發現-Eureka入門 一節中,已經編寫了一個Eureka Server,並將服務提供者與消費者都註冊到了Eureka Server上。

本節,來深入探討Eureka的高級特性。

Eureka原理

本節來探討Eureka的原理。

Region & Availability Zone

下面分析一下Eureka原理,在分析原理前,先來了解一下Region和Availability Zone,如下圖。

圖-Region And Availibility Zone

衆所周知,Netflix公司將他們的應用都部署在了AWS上,所以Eureka的架構使用到了AWS中的一些概念——不用擔心,這不是說Eureka和AWS環境綁定,Eureka可以部署在任意環境

Region和Availability Zone均是AWS的概念。

  • Region表示AWS中的地理位置,例如us-east-1、us-east-2、eu-west-1等;
  • 每個Region都有多個Availability Zone,彼此內網打通
  • 各個Region之間完全隔離,彼此內網不打通
  • AWS通過這種方式實現了最大的容錯和穩定性。

Spring Cloud中,默認使用的Region是us-east-1 。非AWS環境下,可將將Region理解爲內網沒有打通的機房,將Availability Zone理解成相同機房的不同機架(內網打通)。

拓展閱讀

Eureka架構詳解

Eureka架構

如圖是Eureka集羣的工作原理。圖中的組件非常多,概念也比較抽象,我們先來用通俗易懂的文字翻譯一下:

  • Application Service:服務提供者;
  • Application Client:服務消費者;
  • Make Remote Call調用RESTful API;
  • us-east-1c、us-east-1d等都是Availability Zone,它們都屬於us-east-1這個region。

由圖可知,Eureka包含兩個組件:Eureka Server 和 Eureka Client,它們的作用如下:

  • Eureka Server提供服務發現的能力,各個微服務啓動時,會向Eureka Server註冊自己的信息(例如IP、端口、微服務名稱等),Eureka Server會存儲這些信息;
  • Eureka Client是一個Java客戶端,用於簡化與Eureka Server的交互;
  • 微服務啓動後,會週期性(默認30秒)地向Eureka Server發送心跳以續約自己的“租期”;
  • 如果Eureka Server在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會註銷該實例(默認90秒);
  • 默認情況下,Eureka Server同時也是Eureka Client。多個Eureka Server實例,互相之間通過增量複製的方式,來實現服務註冊表中數據的同步。Eureka Server默認保證在90秒內,Eureka Server集羣內的所有實例中的數據達到一致(從這個架構來看,Eureka Server所有實例所處的角色都是對等的,沒有類似Zookeeper、Consul、Etcd等軟件的選舉過程,也不存在主從,所有的節點都是主節點。Eureka官方將Eureka Server集羣中的所有實例稱爲“對等體(peer)”)
  • Eureka Client會緩存服務註冊表中的信息。這種方式有一定的優勢——首先,微服務無需每次請求都查詢Eureka Server,從而降低了Eureka Server的壓力;其次,即使Eureka Server所有節點都宕掉,服務消費者依然可以使用緩存中的信息找到服務提供者並完成調用。

綜上,Eureka通過心跳檢查、客戶端緩存等機制,提高了系統的靈活性、可伸縮性和可用性。

TIPS

事實上,這個官方架構圖是有一點問題的:Eureka Server本身也集成了Eureka Client,彼此通過Eureka Client同步數據給其它實例又或者從其他實例同步數據——現在,你應該能理解上一節中所使用的 register-with-eureka 以及fetch-registry 的作用了。

高可用

編寫高可用Eureka Server

下面來編寫一個雙節點Eureka Server集羣。編寫這個集羣非常簡單,只需修改單實例Eureka Server的配置即可:

  • 爲系統配置主機名:

    vim /etc/hosts
    # 添加如下內容
    127.0.0.1 peer1 peer2
    
    對於Windows系統,請修改C:\windows\system32\drivers\etc\hosts文件
  • 配置:

    spring:
    application:
      name: microservice-discovery-eureka-ha
    ---
    spring:
    profiles: peer1                                 # 指定profile=peer1
    server:
    port: 8761
    eureka:
    instance:
      hostname: peer1                               # 指定當profile=peer1時,主機名是peer1
    client:
      serviceUrl:
        defaultZone: http://peer2:8762/eureka/      # 將自己註冊到peer2這個Eureka上面去
    ---
    spring:
    profiles: peer2
    server:
    port: 8762
    eureka:
    instance:
      hostname: peer2
    client:
      serviceUrl:
        defaultZone: http://peer1:8761/eureka/

    由配置不難看出我們設置了兩個Profile:peer1、peer2。兩個Profile下各有一個Eureka Server,通過相互註冊的方式,構建了Eureka Server集羣。

  • 啓動:

    java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
    java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

    第一個實例會報錯,這是正常的,因爲它會嘗試連接第二個實例,但第二個實例尚未啓動,所以會報連接不上的異常。

注意點

  • 如果兩個Eureka Server實例在同一臺機器上啓動,那麼配置hosts的這一步不能少。原因:Eureka Server對端口是不敏感的,這意味着,如果直接用IP的形式(例如地址寫成http://127.0.0.1:8761/eureka/)相互註冊,Eureka Server誤認爲兩個Eureka Server實例是一個實例——這會造成Eureka Server首頁顯示不正常等一系列問題!!

拓展閱讀

TIPS

編寫Eureka Server集羣的簡寫方式:

spring:
  application:
    name: microservice-discovery-eureka-ha
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer2:8762/eureka/,http://peer1:8761/eureka/
---
spring:
  profiles: peer1
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
---
spring:
  profiles: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2

將應用註冊到Eureka Server集羣上

microservice-provider-user 項目爲例,只須修改eureka.client.serviceUrl.defaultZone,配置多個Eureka Server地址,就可以將其註冊到Eureka Server集羣了。示例:

eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/

這樣就可以將服務註冊到Eureka Server集羣上了。

當然,微服務即使只配置Eureka Server集羣中的某個節點,也能正常註冊到Eureka Server集羣,因爲多個Eureka Server之間的數據會相互同步。例如:

eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/

正常情況下,這種方式與配置多個Server節點的效果是一樣的。不過爲適應某些極端場景,筆者建議在客戶端配置多個Eureka Server節點。

應用啓動後,訪問Eureka Server應能看到類似如下的界面:

Eureka集羣首頁

RESTful API

前文說過,Eureka本身是一個基於REST的服務。本節來探討Eureka Server的RESTful API。

下表展示了Eureka Server提供的RESTful API,來自<https://github.com/Netflix/eureka/wiki/Eureka-REST-operations&gt; ,只需按表格向Eureka Server發送請求,即可操作Eureka Server中的數據。

Operation HTTP action Description
Register new application instance POST /eureka/apps/appID Input:JSON/XMLpayload HTTPCode: 204 on success
De-register application instance DELETE /eureka/apps/appID/instanceID HTTP Code: 200 on success
Send application instance heartbeat PUT /eureka/apps/appID/instanceID HTTP Code: 200 on success 404 if instanceID doesn’t exist
Query for all instances GET /eureka/apps HTTP Code: 200 on success Output:JSON/XML
Query for all appIDinstances GET /eureka/apps/appID HTTP Code: 200 on success Output:JSON/XML
Query for a specificappID/instanceID GET /eureka/apps/appID/instanceID HTTP Code: 200 on success Output:JSON/XML
Query for a specificinstanceID GET /eureka/instances/instanceID HTTP Code: 200 on success Output:JSON/XML
Take instance out of service PUT /eureka/apps/appID/instanceID/status?value=OUT_OF_SERVICE HTTP Code: 200 on success 500 on failure
Put instance back into service (remove override) DELETE /eureka/apps/appID/instanceID/status?value=UP (The value=UP is optional, it is used as a suggestion for the fallback status due to removal of the override) HTTP Code: 200 on success 500 on failure
Update metadata PUT /eureka/apps/appID/instanceID/metadata?key=value HTTP Code: 200 on success 500 on failure
Query for all instances under a particular vip address GET /eureka/vips/vipAddress HTTP Code: 200 on success Output:JSON/XML 404 if thevipAddressdoes not exist.
Query for all instances under a particular secure vip address GET /eureka/svips/svipAddress HTTP Code: 200 on success Output:JSON/XML 404 if thesvipAddressdoes not exist.

調用示例

示例1:註冊一個服務:

  • 將以下文件存儲爲rest-api-test.xml

    <instance>
    <instanceId>itmuch:rest-api-test:9000</instanceId>
    <hostName>itmuch</hostName>
    <app>REST-API-TEST</app>
    <ipAddr>127.0.0.1</ipAddr>
    <vipAddress>rest-api-test</vipAddress>
    <secureVipAddress>rest-api-test</secureVipAddress>
    <status>UP</status>
    <port enabled="true">9000</port>
    <securePort enabled="false">443</securePort>
    <homePageUrl>http://127.0.0.1:9000/</homePageUrl>
    <statusPageUrl>http://127.0.0.1:9000/info</statusPageUrl>
    <healthCheckUrl>http://127.0.0.1:9000/health</healthCheckUrl>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
      <name>MyOwn</name>
    </dataCenterInfo>
    </instance>
  • 通過cURL調用Eureka Server

    cat ./rest-api-test.xml | curl -v -X POST -H "Content-type: application/xml" -d @- http://localhost:8761/eureka/apps/rest-api-test

示例2:查看指定服務的所註冊的信息

只需訪問:http://Eureka Server的地址/eureka/apps/microservice-provider-user 即可查看microdervice-provider-user 服務的信息。

RESTful API的意義

你可能會問:我們不是已經有Eureka Client了嗎?誰閒着沒事再去用RESTful API啊?

要知道,微服務的優勢之一就是允許使用異構的技術、異構的語言甚至異構的平臺解決你想解決的問題。

舉個例子,如果你有一個系統,一部分是Spring Cloud構建的,一部分是用世界上最好的語言PHP寫的!但是呢,你希望Java應用與PHP應用之間的通信也能享受服務發現所帶來的好處,此時就可編寫一個基於PHP的Eureka Client,將PHP應用也註冊到Eureka Server!

事實上,前文說的Eureka Client不過是一個用Jersey 1.x封裝了RESTful API的Jar包而已

拓展閱讀
事實上,業界已經有一些不同語言的Eureka Client,例如:

自我保護模式

自我保護模式是Eureka的重要特性,筆者之前已經專題寫過文章詳解了,所以本系列不再贅述,詳見:理解Eureka的自我保護模式

用戶認證

Finchley版本相對之前的版本有些改動,比較重要。詳見: 跟我學Spring Cloud(Finchley版)番外-01-Eureka安全詳解

配套代碼

本文首發

http://www.itmuch.com/spring-cloud/finchley-6/

乾貨分享

全是乾貨

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章