1. 程式人生 > >跟我學Spring Cloud(Finchley版)-06-服務註冊與服務發現-Eureka深入

跟我學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 ,只需按表格向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/

乾貨分享

全是乾貨