(16) SpringCloud-Eureka的REST API及API擴充套件

JIAN2發表於2022-10-24

本節我們講解了一些經常用到的配置資訊及 Eureka 的 REST API,透過 API 可以做一些擴充套件。

Eureka REST API
Eureka 作為註冊中心,其本質是儲存了每個客戶端的註冊資訊,Ribbon 在轉發的時候會獲取註冊中心的服務列表,然後根據對應的路由規則來選擇一個服務給 Feign 來進行呼叫。如果我們不是 Spring Cloud 技術選型,也想用 Eureka,可以嗎?完全可以。

如果不是 Spring Cloud 技術棧,筆者推薦用 Zookeeper,這樣會方便些,當然用 Eureka 也是可以的,這樣的話就會涉及如何註冊資訊、如何獲取註冊資訊等操作。其實 Eureka 也考慮到了這點,提供了很多 REST 介面來給我們呼叫。

我們舉一個比較有用的案例來說明,比如對 Nginx 動態進行 upstream 的配置。

推薦分散式架構原始碼

在架構變成微服務之後,微服務是沒有依賴的,可以獨立部署,埠也可以隨機分配,反正會註冊到註冊中心裡面,呼叫方也無須關心提供方的 IP 和 Port,這些都可以從註冊中心拿到。

但是有一個問題:API 閘道器的部署能這樣嗎?API 閘道器大部分會用 Nginx 作為負載,那麼 Nginx 就必須知道 API 閘道器有哪幾個節點,這樣閘道器服務就不能隨便啟動了,需要固定。

當然閘道器是不會經常變動的,也不會經常釋出,這樣其實也沒什麼大問題,唯一不好的就是不能自動擴容了。

其實利用 Eureka 提供的 API 我們可以獲取某個服務的例項資訊,也就是說我們可以根據 Eureka 中的資料來動態配置 Nginx 的 upstream。

這樣就可以做到閘道器的自動部署和擴容了。網上也有很多的方案,結合 Lua 指令碼來做,或者自己寫 Sheel 指令碼都可以。

下面舉例說明如何獲取 Eureka 中註冊的資訊。具體的介面資訊請檢視官方文件““。

獲取某個服務的註冊資訊,可以直接 GET 請求::8761/eureka/apps/eureka-client-user-service。其中,eureka-client-user-service 是應用名稱,也就是 spring.application.name。

在瀏覽器中,資料的顯示格式預設是 XML 格式的,如圖 1 所示。

如果想返回 Json資料的格式,可以用一些介面測試工具來請求,比如 Postman,在請求頭中新增下面兩行程式碼即可。

Content-Type:application/json Accept:application/json


如果 Eureka 開啟了認證,記得新增認證資訊,使用者名稱和密碼必須是 Base64 編碼過的 Authorization:Basic 使用者名稱:密碼,其餘的介面就不做過多講解了,大家可以自己去嘗試。Postman 直接支援了 Basic 認證,將選項從 Headers 切換到 Authorization,選擇認證方式為 Basic Auth 就可以填寫使用者資訊了。

填寫完之後,直接發起請求就可以了。我們切換到 Headers 選項中,就可以看到請求頭中已經多了一個 Authorization 頭。

後設資料使用
Eureka 的後設資料有兩種型別,分別是框架定好了的標準後設資料和使用者自定義後設資料。標準後設資料指的是主機名、IP 地址、埠號、狀態頁和健康檢查等資訊,這些資訊都會被髮布在服務登錄檔中,用於服務之間的呼叫。自定義後設資料可以使用 eureka.instance.metadataMap 進行配置。

自定義後設資料說得通俗點就是自定義配置,我們可以為每個 Eureka Client 定義一些屬於自己的配置,這個配置不會影響 Eureka 的功能。

自定義後設資料可以用來做一些擴充套件資訊,比如灰度釋出之類的功能,可以用後設資料來儲存灰度釋出的狀態資料,Ribbon 轉發的時候就可以根據服務的後設資料來做一些處理。當不需要灰度釋出的時候可以呼叫 Eureka 提供的 REST API 將後設資料清除掉。

下面我們來自定義一個簡單的後設資料,在屬性檔案中配置如下:

eureka.instance.metadataMap.biancheng=zhangsan


上述程式碼定義了一個 key 為 biancheng 的配置,value 是 zhangsan。重啟服務,然後透過 Eureka 提供的 REST API 來檢視剛剛配置的後設資料是否已經存在於 Eureka 中,如圖 2 所示。

EurekaClient 使用
當我們的專案中整合了 Eureka 之後,可以透過 EurekaClient 來獲取一些我們想要的資料,比如剛剛上面講的後設資料。我們就可以直接透過 EurekaClient 來獲取(程式碼如下所示),不用再去呼叫 Eureka 提供的 REST API。

@Autowired
private EurekaClient eurekaClient;
@GetMapping("/article/infos")
public Object serviceUrl() {
    return eurekaClient.getInstancesByVipAddress( "eureka-client-user-service", false);
}

透過 PostMan 來呼叫介面看看有沒有返回我們想要的資料。這時我們會發現,透過 EurekaClient 獲取的資料跟我們自己去掉 API 獲取的資料是一樣的,從使用角度來說前者比較方便。除了使用 EurekaClient,還可以使用 DiscoveryClient(程式碼如下所示),這個不是 Feign 自帶的,是 Spring Cloud 重新封裝的,類的路徑為

org.springframework.cloud.client.discovery.DiscoveryClient。
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/article/infos")
public Object serviceUrl() {
    return discoveryClient.getInstances("eureka-client-user-service");
}


健康檢查
預設情況下,Eureka 客戶端是使用心跳和服務端通訊來判斷客戶端是否存活,在某些場景下,比如 MongoDB 出現了異常,但你的應用程式還是存在的,這就意味著應用可以繼續透過心跳上報,保持應用自己的資訊在 Eureka 中不被剔除掉。

Spring Boot Actuator 提供了 /actuator/health 端點,該端點可展示應用程式的健康資訊,當 MongoDB 異常時,/actuator/health 端點的狀態會變成 DOWN,由於應用本身確實處於存活狀態,但是 MongoDB 的異常會影響某些功能,當請求到達應用之後會發生操作失敗的情況。

在這種情況下,我們希望可以將健康資訊傳遞給 Eureka 服務端。這樣 Eureka 中就能及時將應用的例項資訊下線,隔離正常請求,防止出錯。透過配置如下內容開啟健康檢查:

eureka.client.healthcheck.enabled=true


我們可以透過擴充套件健康檢查的端點來模擬異常情況,定義一個擴充套件端點,將狀態設定為 DOWN,程式碼如下所示。

@Component
public class CustomHealthIndicator extends AbstractHealthIndicator {
    @Override
    protected void doHealthCheck(Builder builder) throws Exception {
        builder.down().withDetail("status", false);
    }
}


擴充套件好後我們訪問 /actuator/health 可以看到當前的狀態是 DOWN,如圖 3 所示。

Eureka 中的狀態是 UP,這種情況下請求還是能轉發到這個服務中,下面我們開啟監控檢查,再次檢視 Eureka 中的狀態,發現狀態變為 DOWN(1)。

服務上下線監控
在某些特定的需求下,我們需要對服務的上下線進行監控,上線或下線都進行郵件通知,Eureka 中提供了事件監聽的方式來擴充套件。

目前支援的事件如下:

EurekaInstanceCanceledEvent 服務下線事件。
EurekaInstanceRegisteredEvent 服務註冊事件。
EurekaInstanceRenewedEvent 服務續約事件。
EurekaRegistryAvailableEvent Eureka 註冊中心啟動事件。
EurekaServerStartedEvent Eureka Server 啟動事件。

基於 Eureka 提供的事件機制,可以監控服務的上下線過程,在過程發生中可以傳送郵件來進行通知。下面程式碼只是演示了監控的過程,並未傳送郵件。

@Component
public class EurekaStateChangeListener {
    @EventListener
    public void listen(EurekaInstanceCanceledEvent event) {
        System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服務下線 ");
    }
    @EventListener
    public void listen(EurekaInstanceRegisteredEvent event) {
        InstanceInfo instanceInfo = event.getInstanceInfo();
        System.err.println(instanceInfo.getAppName() + " 進行註冊 ");
    }
    @EventListener
    public void listen(EurekaInstanceRenewedEvent event) {
        System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服務進行續約 ");
    }
    @EventListener
    public void listen(EurekaRegistryAvailableEvent event) {
        System.err.println(" 註冊中心啟動 ");
    }
    @EventListener
    public void listen(EurekaServerStartedEvent event) {
        System.err.println("Eureka Server啟動 ");
    }
}


注意:在 Eureka 叢集環境下,每個節點都會觸發事件,這個時候需要控制下傳送通知的行為,不控制的話每個節點都會傳送通知。

需要框架原始碼的朋友可以看我個人簡介聯絡我


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70006413/viewspace-2919890/,如需轉載,請註明出處,否則將追究法律責任。

相關文章