共计 3784 个字符,预计需要花费 10 分钟才能阅读完成。
上一篇博客 未来实现 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":"zzz@163.com"
,"hotal":"0001"
,"room":"biger1"
,"time_start":"20191019"
,"time_end":"20191020"
}
}
2. 查询用户详情的 API,返回数据称为 json2,内容如下:
{
"status":"000000",
"data":{
"account":"goku@eolinker.com",
"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":"goku@eolinker.com",
"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":{},}
那么从原始数据到处理后的数据需要经过以下操作:
1. 字段黑名单
字段黑名单的作用是排除某些字段,支持数组形式。
在网关的 Step3 里配置如下:
经过网关处理后,实际的返回数据如下,可以看到 data 对象里的 id 字段已经被过滤掉:
{
"status":"000000",
"data":{
"type":"星级酒店",
"name":"","address":"",
"location":{},}
}
2. 字段拆包
拆包是指将指定对象的内容提取出来作为该步骤(step)的返回结果。其中匹配目标只能为 object,匹配目标为空时,结果为 {},可用于清除数据。
在网关的 Step 里配置如下:
经过网关处理后,实际的返回数据如下,可以看到 data 对象被拆开,最终数据仅保留了 data 对象里面的字段:
{
"type":"星级酒店",
"name":"","address":"",
"location":{},}
3. 封包
字段封包会将当前的数据整体打包为最终返回数据中的一个对象,不支持 *,不支持数组。
在网关的 Step 里配置如下:
经过网关处理后,实际的返回数据如下,数据被整体打包为 hotelinfo 对象:
{
"hotelinfo":{
"type":"星级酒店",
"name":"","address":"",
"location":{},}
}
经过三个步骤,就可以将原始数据变成最终的数据。
本文仅列举了编排过程中部分数据处理的操作,如需了解更多编排细则,可以在评论区留言。欢迎提出任何建议和想法。最后给出相关的链接,有条件实践的可以去 github 下载试试。项目地址:https://github.com/eolinker/g…