31

如何更快理解和运用服务编排?(使用Goku API Gateway实现)

 4 years ago
source link: https://www.tuicool.com/articles/nEbQvqM
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

上一篇博客  未来实现API管理系统的几个关键词 发布后,有不少读者私信我,让我写一篇实际运用的文章,我周末趁着有空写了这篇有关“服务编排”的文章。用的是Goku API Gateway进行演示, 希望本文对读者有所启发。

什么是服务编排/数据聚合?

服务编排/数据聚合指的是可以通过一个请求来依次调用多个微服务,并对每个服务的返回结果做数据处理,最终整合成一个大的结果返回给前端。

例如一个服务是“查询用户预定的酒店”,前端仅需要传一个订单ID,后端会返回整个订单的信息,包括用户信息、酒店信息和房间信息等。

这个服务背后可能对应着以下几个操作:

  • 请求订单详情,返回订单对应的用户ID、酒店ID、房间ID;
  • 根据各类ID查询对应的信息;
  • 将数据做过滤、移动等操作,最后整合起来;
  • 将整合好的数据返回给前端。

下面的图可以帮你更好理解:

EzM3uiB.png!web

编排的优势

微服务架构上对功能做了解耦,使用服务编排可以快速从各类服务上获取需要的数据,对业务实现快速响应。总的来说,编排有以下几点优势:

  • 功能解耦,服务能够被复用;
  • 对前端友好,无需多次请求;
  • 业务响应速度快,服务能够被快速生成;
  • 返回数据有改动的话,请求接口无影响;
  • 老系统改动的情况下,不需要改动前端,可以通过网关对数据做兼容。

使用编排工具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上做服务编排?

我们将编排的整个操作放到网关进行,由网关对数据做处理与转换,这样无需对后端服务做改动。一个请求到达网关,网关调用多个后端服务,并且在网关上对各个服务的返回数据做处理(操作有过滤、移动、重命名、封包、拆包,后面会对各操作做详细解释),最后由网关将数据整合好返回给前端。通过下图查看会更加明白:

e6Nv2ib.png!web

操作步骤

1.在网关上,新建API的类型可以选择服务编排:

3uY3EvB.png!web

2.配置 查询预定酒店 API的请求信息:

QjYBRbU.png!web

3.添加并配置Step:

网关将编排过程中对 API的转发处理过程 (转发->获取返回数据->数据处理)称为一个 Step

添加一个转发服务,该服务为 查询订单详情API,配置相应的转发地址、传入的参数、对返回数据做何种处理等。

YZZJbeI.png!web

由于篇幅原因,后续的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的请求参数配置如下所示,请求参数存在多个的话用换行表示:

I7BJnye.png!web

(二)返回数据处理

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里配置如下:

EJvuM3N.png!web

经过网关处理后,实际的返回数据如下,可以看到data对象里的id字段已经被过滤掉:

{
"status":"000000",
"data":{
        "type":"星级酒店",
        "name":"",
        "address":"",
        "location":{},
}
}
  • 字段拆包

拆包是指将指定对象的内容提取出来作为该步骤(step)的返回结果。 其中匹配目标只能为object,匹配目标为空时,结果为 {},可用于清除数据。

在网关的Step里配置如下:

z26bMrN.png!web

经过网关处理后,实际的返回数据如下,可以看到data对象被拆开,最终数据仅保留了data对象里面的字段:

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

字段 封包 将当前的数据整体打包为最终返回数据中的 一个 对象 ,不支持*,不支持数组。

在网关的Step里配置如下:

jaiqAbz.png!web

经过网关处理后,实际的返回数据如下,数据被整体打包为hotelinfo对象:

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

经过三个步骤,就可以将原始数据变成最终的数据。

本文仅列举了编排过程中部分数据处理的操作,如需了解更多编排细则,可以在评论区留言。欢迎提出任何建议和想法。最后给出相关的链接,有条件实践的可以去github下载试试。项目地址: https://github.com/eolinker/goku-api-gateway


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK