1. 程式人生 > >如何更快理解和運用服務編排?(使用Goku API Gateway實現)

如何更快理解和運用服務編排?(使用Goku API Gateway實現)

上一篇部落格 未來實現API管理系統的幾個關鍵詞 釋出後,有不少讀者私信我,讓我寫一篇實際運用的文章,我週末趁著有空寫了這篇有關“服務編排”的文章。用的是Goku API Gateway進行演示, 希望本文對讀者有所啟發。

什麼是服務編排/資料聚合?

服務編排/資料聚合 指的是可以通過一個請求來依次呼叫多個微服務,並對每個服務的返回結果做資料處理,最終整合成一個大的結果返回給前端。

例如一個服務是“查詢使用者預定的酒店”,前端僅需要傳一個訂單ID,後端會返回整個訂單的資訊,包括使用者資訊、酒店資訊和房間資訊等。

這個服務背後可能對應著以下幾個操作:

  • 請求訂單詳情,返回訂單對應的使用者ID、酒店ID、房間ID;
  • 根據各類ID查詢對應的資訊;
  • 將資料做過濾、移動等操作,最後整合起來;
  • 將整合好的資料返回給前端。

下面的圖可以幫你更好理解:

編排的優勢

微服務架構上對功能做了解耦,使用服務編排可以快速從各類服務上獲取需要的資料,對業務實現快速響應。總的來說,編排有以下幾點優勢:

  • 功能解耦,服務能夠被複用;
  • 對前端友好,無需多次請求;
  • 業務響應速度快,服務能夠被快速生成;
  • 返回資料有改動的話,請求介面無影響;
  • 老系統改動的情況下,不需要改動前端,可以通過閘道器對資料做相容。

使用編排工具Goku API Gateway:

先簡單介紹一下,Goku API Gateway (中文名:悟空 API 閘道器)是一個基於 Golang 開發的微服務閘道器,能夠實現高效能 HTTP API 轉發、服務編排、多租戶管理、API 訪問許可權控制等目的,擁有強大的自定義外掛系統可以自行擴充套件,並且提供友好的圖形化配置介面,能夠快速幫助企業進行 API 服務治理、提高 API 服務的穩定性和安全性。

本次之所以採用Goku API Gateway來進行演示,因為它支援一個編排API對應多個後端服務,每個後端服務的請求引數可以使用前端傳入的引數,也可以在編排裡自定義(寫靜態引數或從返回資料裡獲得)。每個後端服務的返回資料支援過濾、刪除、移動、重新命名、拆包和封包等操作,而且編排API能夠設定編排失敗時的異常返回。

這次用的是Goku API Gateway 的社群版本(CE),也就是開源版本,我對內建的外掛系統進行部分改動也算是定製開發了。

專案地址:https://github.com/eolinker/goku-api-gateway

官網地址:https://www.eolinker.com

下面進入實際操作環節。

如何在Goku上做服務編排?

我們將編排的整個操作放到閘道器進行,由閘道器對資料做處理與轉換,這樣無需對後端服務做改動。一個請求到達閘道器,閘道器呼叫多個後端服務,並且在閘道器上對各個服務的返回資料做處理(操作有過濾、移動、重新命名、封包、拆包,後面會對各操作做詳細解釋),最後由閘道器將資料整合好返回給前端。通過下圖檢視會更加明白:

操作步驟

1.在閘道器上,新建API的型別可以選擇服務編排:

2.配置 查詢預定酒店 API的請求資訊:

3.新增並配置Step:

閘道器將編排過程中對 API的轉發處理過程(轉發->獲取返回資料->資料處理)稱為一個 Step。

新增一個轉發服務,該服務為 查詢訂單詳情API,配置相應的轉發地址、傳入的引數、對返回資料做何種處理等。

由於篇幅原因,後續的Step(查詢使用者詳情、查詢酒店詳情、查詢房間詳情)就不一一展示了。

編排的傳遞引數方式和資料處理

為了讓讀者更好的理解編排的實現方式,簡單說一下兩種傳遞引數方式:

(一)編排的兩種傳遞引數方式

閘道器將編排過程中對 API的轉發處理過程(轉發->獲取返回資料->資料處理)稱為一個 Step。

我們將處理查詢訂單詳情API稱為 Step1,其中Step1的返回資料有:使用者ID、酒店ID、房間ID。同理,將查詢使用者資訊這步稱為 Step2,將查詢酒店資訊稱為 Step3,將查詢房間資訊稱為 Step4。

傳參規則:

  • 使用前端傳入的引數可以寫成:body.引數名、header.引數名
  • 使用Step1裡的返回資料作為引數可以寫成:body1.引數名、header1.引數名
  • 以此類推
1.在轉發路徑傳參

以下為轉發路徑的傳參寫法:

  • 例如Step1要接收前端傳入的orderID引數,還有Authorization引數。

Step1的轉發路徑可以寫成:/getOrderInfo/{{body.orderID}}/{{header.Authorization}}

  • 例如Step2 接收 Step1 裡的返回使用者ID引數(userID),同時接收前端傳入的Authorization引數。

Step2的轉發路徑可以寫成:/getUserInfo/{{body1.userID}}/{{header.Authorization}}

2.在Step裡配置請求引數

Step2中需要接收Step1裡返回的userID作為引數,同時需要接收前端傳入的Authorization引數

在閘道器裡Step2的請求引數配置如下所示,請求引數存在多個的話用換行表示:

(二)返回資料處理

1.查詢訂單詳情的API,返回資料稱為json1,內容如下:

{
"status":"000000",
"data":{
"id":"201910180009x"
        ,"user_account":"[email protected]"
        ,"hotal":"0001"
        ,"room":"biger1"
        ,"time_start":"20191019"
        ,"time_end":"20191020"
}
}
  2.查詢使用者詳情的API,返回資料稱為json2,內容如下:
{
"status":"000000",
"data":{
"account":"[email protected]",
"full_name":"",
"phone":""
}
}
  3.查詢酒店詳情的返回資料,稱為json3,內容如下:
{
"status":"000000",
"data":{
"id":"001",
        "type":"星級酒店",
        "name":"",
        "address":"",
        "location":{},
}
}
  4.查詢房間詳情的返回資料,稱為json4,內容如下:
{
"status":"000000",
"data":{
"name":"豪華大床房"
        ,"window":1
        ,"floor":"10-12"
        ,"nosmoke":1
}
}

5.可以在每一個Step裡對返回Json做處理,閘道器會將處理過的資料最後整合起來,再返回前端,例如這是通過閘道器返回的最終資料:

{
    "id":"201910180009x"
    ,"userInfo":{
"account":"[email protected]",
"full_name":"",
"phone":""
    }
    ,"hotelinfo":{
"type":"星級酒店",
"name":"",
"address":"",
"location":{},
    }
    , "roominfo":{
        "name":"豪華大床房"
,"window":1
,"floor":"10-12"
,"nosmoke":1
    }
}
  這裡以查詢酒店詳情API的返回資料json3為例,講解閘道器如何在編排過程中對返回資料做處理。   查詢酒店詳情API返回的原始資料如下:
{
"status":"000000",
"data":{
"id":"001",
        "type":"星級酒店",
        "name":"",
        "address":"",
        "location":{},
}
}
從閘道器返回給前端的資料中擷取酒店資訊的資料如下:
"hotelinfo":{
"type":"星級酒店",
"name":"",
"address":"",
"location":{},
    }

 那麼從原始資料到處理後的資料需要經過以下操作:

  • 欄位黑名單

欄位黑名單的作用是排除某些欄位,支援陣列形式。

在閘道器的Step3裡配置如下:

經過閘道器處理後,實際的返回資料如下,可以看到data物件裡的id欄位已經被過濾掉:

{
"status":"000000",
"data":{
        "type":"星級酒店",
        "name":"",
        "address":"",
        "location":{},
}
}
  • 欄位拆包

拆包是指將指定物件的內容提取出來作為該步驟(step)的返回結果。其中匹配目標只能為object,匹配目標為空時,結果為 {},可用於清除資料。

在閘道器的Step裡配置如下:

經過閘道器處理後,實際的返回資料如下,可以看到data物件被拆開,最終資料僅保留了data物件裡面的欄位:

{
        "type":"星級酒店",
        "name":"",
        "address":"",
        "location":{},
}
  • 封包

欄位封包會將當前的資料整體打包為最終返回資料中的一個物件,不支援*,不支援陣列。

在閘道器的Step裡配置如下:

經過閘道器處理後,實際的返回資料如下,資料被整體打包為hotelinfo物件:

{
"hotelinfo":{
        "type":"星級酒店",
        "name":"",
        "address":"",
        "location":{},
}
}

經過三個步驟,就可以將原始資料變成最終的資料。

本文僅列舉了編排過程中部分資料處理的操作,如需瞭解更多編排細則,可以在評論區留言。歡迎提出任何建議和想法。最後給出相關的連結,有條件實踐的可以去github下載試試。專案地址:https://github.com/eolinker/goku-api-gateway