什么是服務(wù)編排/數(shù)據(jù)聚合?
服務(wù)編排/數(shù)據(jù)聚合 指的是可以通過(guò)一個(gè)請(qǐng)求來(lái)依次調(diào)用多個(gè)微服務(wù),并對(duì)每個(gè)服務(wù)的返回結(jié)果做數(shù)據(jù)處理,最終整合成一個(gè)大的結(jié)果返回給前端。
例如一個(gè)服務(wù)是“查詢用戶預(yù)定的酒店”,前端僅需要傳一個(gè)訂單ID,后端會(huì)返回整個(gè)訂單的信息,包括用戶信息、酒店信息和房間信息等。
這個(gè)服務(wù)背后可能對(duì)應(yīng)著以下幾個(gè)操作:
- 請(qǐng)求訂單詳情,返回訂單對(duì)應(yīng)的用戶ID、酒店ID、房間ID;
- 根據(jù)各類ID查詢對(duì)應(yīng)的信息;
- 將數(shù)據(jù)做過(guò)濾、移動(dòng)等操作,最后整合起來(lái);
- 將整合好的數(shù)據(jù)返回給前端。

編排的優(yōu)勢(shì)
微服務(wù)架構(gòu)上對(duì)功能做了解耦,使用服務(wù)編排可以快速?gòu)母黝惙?wù)上獲取需要的數(shù)據(jù),對(duì)業(yè)務(wù)實(shí)現(xiàn)快速響應(yīng)??偟膩?lái)說(shuō),編排有以下幾點(diǎn)優(yōu)勢(shì):
- 功能解耦,服務(wù)能夠被復(fù)用;
- 對(duì)前端友好,無(wú)需多次請(qǐng)求;
- 業(yè)務(wù)響應(yīng)速度快,服務(wù)能夠被快速生成;
- 返回?cái)?shù)據(jù)有改動(dòng)的話,請(qǐng)求接口無(wú)影響;
- 老系統(tǒng)改動(dòng)的情況下,不需要改動(dòng)前端,可以通過(guò)網(wǎng)關(guān)對(duì)數(shù)據(jù)做兼容。
使用工具:Goku API Gateway
Goku API Gateway (中文名:悟空 API 網(wǎng)關(guān))是一個(gè)基于 Golang 開(kāi)發(fā)的微服務(wù)網(wǎng)關(guān),能夠?qū)崿F(xiàn)高性能 HTTP API 轉(zhuǎn)發(fā)、服務(wù)編排、多租戶管理、API 訪問(wèn)權(quán)限控制等目的,擁有強(qiáng)大的自定義插件系統(tǒng)可以自行擴(kuò)展,并且提供友好的圖形化配置界面,能夠快速幫助企業(yè)進(jìn)行 API 服務(wù)治理、提高 API 服務(wù)的穩(wěn)定性和安全性。
Goku API Gateway支持一個(gè)編排API對(duì)應(yīng)多個(gè)后端服務(wù),每個(gè)后端服務(wù)的請(qǐng)求參數(shù)可以使用前端傳入的參數(shù),也可以在編排里自定義(寫靜態(tài)參數(shù)或從返回?cái)?shù)據(jù)里獲得)。每個(gè)后端服務(wù)的返回?cái)?shù)據(jù)支持過(guò)濾、刪除、移動(dòng)、重命名、拆包和封包等操作;編排API能夠設(shè)定編排失敗時(shí)的異常返回。
Goku API Gateway 的社區(qū)版本(CE)同時(shí)擁有完善的使用指南和二次開(kāi)發(fā)指南,內(nèi)置的插件系統(tǒng)也能夠讓企業(yè)針對(duì)自身業(yè)務(wù)進(jìn)行定制開(kāi)發(fā)。
項(xiàng)目地址:https://github.com/eolinker/goku-api-gateway
官網(wǎng)地址:https://www.eolinker.com
如何在Goku上做服務(wù)編排?
我們將編排的整個(gè)操作放到網(wǎng)關(guān)進(jìn)行,由網(wǎng)關(guān)對(duì)數(shù)據(jù)做處理與轉(zhuǎn)換,這樣無(wú)需對(duì)后端服務(wù)做改動(dòng)。一個(gè)請(qǐng)求到達(dá)網(wǎng)關(guān),網(wǎng)關(guān)調(diào)用多個(gè)后端服務(wù),并且在網(wǎng)關(guān)上對(duì)各個(gè)服務(wù)的返回?cái)?shù)據(jù)做處理(操作有過(guò)濾、移動(dòng)、重命名、封包、拆包,后面會(huì)對(duì)各操作做詳細(xì)解釋),最后由網(wǎng)關(guān)將數(shù)據(jù)整合好返回給前端。

操作概覽
- 在網(wǎng)關(guān)上,新建API的類型可以選擇服務(wù)編排:

- 配置 查詢預(yù)定酒店 API的請(qǐng)求信息:

- 添加并配置Step:
網(wǎng)關(guān)將編排過(guò)程中對(duì) API的轉(zhuǎn)發(fā)處理過(guò)程(轉(zhuǎn)發(fā)->獲取返回?cái)?shù)據(jù)->數(shù)據(jù)處理)稱為一個(gè) Step。
添加一個(gè)轉(zhuǎn)發(fā)服務(wù),該服務(wù)為 查詢訂單詳情API,配置相應(yīng)的轉(zhuǎn)發(fā)地址、傳入的參數(shù)、對(duì)返回?cái)?shù)據(jù)做何種處理等。

由于篇幅原因,后續(xù)的Step(查詢用戶詳情、查詢酒店詳情、查詢房間詳情)就不一一展示了。
(一)編排的兩種傳遞參數(shù)方式
網(wǎng)關(guān)將編排過(guò)程中對(duì) API的轉(zhuǎn)發(fā)處理過(guò)程(轉(zhuǎn)發(fā)->獲取返回?cái)?shù)據(jù)->數(shù)據(jù)處理)稱為一個(gè) Step。
我們將處理查詢訂單詳情API稱為 Step1,其中Step1的返回?cái)?shù)據(jù)有:用戶ID、酒店ID、房間ID。同理,將查詢用戶信息這步稱為 Step2,將查詢酒店信息稱為 Step3,將查詢房間信息稱為 Step4。
傳參規(guī)則:
- 使用前端傳入的參數(shù)可以寫成:body.參數(shù)名、header.參數(shù)名
- 使用Step1里的返回?cái)?shù)據(jù)作為參數(shù)可以寫成:body1.參數(shù)名、header1.參數(shù)名
- 以此類推
1.在轉(zhuǎn)發(fā)路徑傳參
以下為轉(zhuǎn)發(fā)路徑的傳參寫法:
-
例如Step1要接收前端傳入的orderID參數(shù),還有Authorization參數(shù)。
Step1的轉(zhuǎn)發(fā)路徑可以寫成:/getOrderInfo/{{body.orderID}}/{{header.Authorization}}
-
例如Step2 接收 Step1 里的返回用戶ID參數(shù)(userID),同時(shí)接收前端傳入的Authorization參數(shù)。
Step2的轉(zhuǎn)發(fā)路徑可以寫成:/getUserInfo/{{body1.userID}}/{{header.Authorization}}
2.在Step里配置請(qǐng)求參數(shù)
Step2中需要接收Step1里返回的userID作為參數(shù),同時(shí)需要接收前端傳入的Authorization參數(shù)
在網(wǎng)關(guān)里Step2的請(qǐng)求參數(shù)配置如下所示,請(qǐng)求參數(shù)存在多個(gè)的話用換行表示:

(二)返回?cái)?shù)據(jù)處理
1.查詢訂單詳情的API,返回?cái)?shù)據(jù)稱為json1,內(nèi)容如下:
{
"status":"000000",
"data":{
"id":"201910180009x"
,"user_account":"zzz@163.com"
,"hotal":"0001"
,"room":"biger1"
,"time_start":"20191019"
,"time_end":"20191020"
}
}
2.查詢用戶詳情的API,返回?cái)?shù)據(jù)稱為json2,內(nèi)容如下:
{
"status":"000000",
"data":{
"account":"goku@eolinker.com",
"full_name":"",
"phone":""
}
}
3.查詢酒店詳情的返回?cái)?shù)據(jù),稱為json3,內(nèi)容如下:
{
"status":"000000",
"data":{
"id":"001",
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
}
4.查詢房間詳情的返回?cái)?shù)據(jù),稱為json4,內(nèi)容如下:
{
"status":"000000",
"data":{
"name":"豪華大床房"
,"window":1
,"floor":"10-12"
,"nosmoke":1
}
}
5.可以在每一個(gè)Step里對(duì)返回Json做處理,網(wǎng)關(guān)會(huì)將處理過(guò)的數(shù)據(jù)最后整合起來(lái),再返回前端,例如這是通過(guò)網(wǎng)關(guān)返回的最終數(shù)據(jù):
"id":"201910180009x"
,"userInfo":{
"account":"goku@eolinker.com",
"full_name":"",
"phone":""
}
,"hotelinfo":{
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
, "roominfo":{
"name":"豪華大床房"
,"window":1
,"floor":"10-12"
,"nosmoke":1
}
}
這里以查詢酒店詳情API的返回?cái)?shù)據(jù)json3為例,講解網(wǎng)關(guān)如何在編排過(guò)程中對(duì)返回?cái)?shù)據(jù)做處理。
查詢酒店詳情API返回的原始數(shù)據(jù)如下:
{
"status":"000000",
"data":{
"id":"001",
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
}
從網(wǎng)關(guān)返回給前端的數(shù)據(jù)中截取酒店信息的數(shù)據(jù)如下:
"hotelinfo":{
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
從原始數(shù)據(jù)到處理后的數(shù)據(jù)需要經(jīng)過(guò)以下操作:
- 字段黑名單
字段黑名單的作用是排除某些字段,支持?jǐn)?shù)組形式。
在網(wǎng)關(guān)的Step3里配置如下:

經(jīng)過(guò)網(wǎng)關(guān)處理后,實(shí)際的返回?cái)?shù)據(jù)如下,可以看到data對(duì)象里的id字段已經(jīng)被過(guò)濾掉:
{
"status":"000000",
"data":{
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
}
- 字段拆包
拆包是指將指定對(duì)象的內(nèi)容提取出來(lái)作為該步驟(step)的返回結(jié)果。其中匹配目標(biāo)只能為object,匹配目標(biāo)為空時(shí),結(jié)果為 {},可用于清除數(shù)據(jù)。
在網(wǎng)關(guān)的Step里配置如下:

經(jīng)過(guò)網(wǎng)關(guān)處理后,實(shí)際的返回?cái)?shù)據(jù)如下,可以看到data對(duì)象被拆開(kāi),最終數(shù)據(jù)僅保留了data對(duì)象里面的字段:
{
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
- 封包
字段封包會(huì)將當(dāng)前的數(shù)據(jù)整體打包為最終返回?cái)?shù)據(jù)中的一個(gè)對(duì)象,不支持*,不支持?jǐn)?shù)組。
在網(wǎng)關(guān)的Step里配置如下:

經(jīng)過(guò)網(wǎng)關(guān)處理后,實(shí)際的返回?cái)?shù)據(jù)如下,數(shù)據(jù)被整體打包為hotelinfo對(duì)象:
{
"hotelinfo":{
"type":"星級(jí)酒店",
"name":"",
"address":"",
"location":{},
}
}
經(jīng)過(guò)三個(gè)步驟,就可以將原始數(shù)據(jù)變成最終的數(shù)據(jù)。
本文僅列舉了編排過(guò)程中部分?jǐn)?shù)據(jù)處理的操作,如需了解更多編排細(xì)則,可通過(guò)文末給出的教程鏈接。
相關(guān)鏈接
- 項(xiàng)目地址:https://github.com/eolinker/goku-api-gateway
- 官網(wǎng)地址:https://www.eolinker.com
- 相關(guān)教程: 服務(wù)編排
轉(zhuǎn)載自:https://blog.csdn.net/qq_40579834/article/details/102661837