# 系统架构
- 整体架构图
- 服务编排架构图
# 服务清单
模块 | 工程名 | 端口 |
---|---|---|
网关节点 | fizz-gateway-node | 8600 |
管理后台 | fizz-manager-professtional | 8000 |
# 中间件清单
资源类型 | 数据库 |
---|---|
Redis | 10 |
MySQL | fizz-manager |
# 数据库设计
# Mysql
# E-R图
- 服务编排
- 路由
- 流控
- 开放文档
# 中间件
# Redis
key | key中文名 | 值类型 | 描述 |
---|---|---|---|
fizz_api_config_route | api配置 | hash | api配置存放Hash的Key |
fizz_api_config_app_set_size | api配置app集合个数 | hash | api配置app集合个数存放Hash的Key |
fizz_aggregate_config | 聚合配置 | hash | 聚合配置存放Hash的Key |
fizz_rpc_service | RPC服务信息 | hash | RPC服务信息存放Hash的Key |
fizz_app | 应用权限 | hash | RPC服务信息存放Hash的Key |
fizz_gateway_group | 网关分组 | hash | 网关分组存放Hash的Key |
fizz_plugin_config | 插件 | hash | 插件存放Hash的Key |
fizz_api_pairing_doc | 文档集配对配置 | hash | 文档集配对配置存放Hash的Key |
fizz_rate_limit | 流控配置 | hash | 流控配置存放Hash的Key |
fizz_api_config_app:%s_%s | api配置app | set | api配置app存放Set的Key模式{fizz_api_config_app:apiId_index} |
fizz_manager_url | 管理后台地址 | string | 管理后台地址 |
fizz_api_pairing_info | 配对信息 | hash | 配对信息存放Hash的Key |
fizz_global_resource | 公共参数 | hash | 公共参数存放Hash的Key |
# MQ设计
消息类型 | TAG | GID | BODY字段描述 | 说明 |
---|---|---|---|---|
Redis | fizz_api_config_channel_route | api配置Channel | ||
Redis | fizz_api_config_app_channel | api配置app关联Channel | ||
Redis | fizz_plugin_config_channel | 插件固定配置Channel | ||
Redis | fizz_aggregate_channel | 聚合配置Channel | ||
Redis | fizz_rpc_service_channel | RPC服务信息Channel | ||
Redis | fizz_app_channel | 应用权限Channel | ||
Redis | fizz_gateway_group_channel | 网关分组Channel | ||
Redis | fizz_api_pairing_doc_channel | 文档集配对配置Channel | ||
Redis | fizz_rate_limit_channel | 流控配置Channel | ||
Redis | fizz_global_resource_channel | 公共参数Channel | ||
Redis | fizz_api_pairing_info_channel | 配对信息Channel |
【说明】
- 消息类型:kafka、rocketMq、activeMq、Redis
- TAG*:指的是Topic*
- GID*:指的是消费组*
- BODY*:消息具体的格式,为便于扩展,通常为JSON格式。消费者需要考虑兼容JSON消息体可能扩展的情况*
- 说明:描述消息
# 服务编排设计
# 配置文件设计
// 接口配置
export const aggrAPIConfig = {
name: "input name", // 自定义的聚合接口名
debug: false, // 是否为调试模式,默认false(v1.1.4后已废弃使用,于列表统一设置debugMode)
type: "REQUEST", // 类型,REQUEST/MYSQL
method: "GET", // HTTP方法,GET/POST等
path: "/aggr/aggr-hotel/hotel/rates", // 格式:/aggr/+分组名+路径, 分组名以aggr-开头,表示聚合接口
headersDef: { // 可选,定义聚合接口header部分参数,使用JSON Schema规范(详见:http://json-schema.org/specification.html),用于参数验证,接口文档生成
"type": [
"object",
"null"
],
"properties": {
appId: {
type: "string",
title: "应用ID",
description: "描述"
}
},
"required": ["appId"]
},
paramsDef: { // 可选,定义聚合接口parameter部分参数,使用JSON Schema规范(详见:http://json-schema.org/specification.html),用于参数验证,接口文档生成
"type": [
"object",
"null"
],
"properties": {
lang: {
type: "string",
title: "语言",
description: "描述"
}
},
"required": []
},
bodyDef: { // 可选,定义聚合接口body部分参数,使用JSON Schema规范(详见:http://json-schema.org/specification.html),用于参数验证,接口文档生成
"type": [
"object",
"null"
],
"properties": {
userId: {
type: "string",
title: "用户名",
description: "描述"
}
},
"required": ["userId"]
},
// TODO (所有脚本相关 都是同一处理) 脚本内容另外存储 传参用脚本id替换
scriptValidate: { // 可选,用于headersDef、paramsDef、bodyDef无法覆盖的入参验证场景
"aggregate_config_script_id": 12
// 以下是脚本具体内容
// type: "", // groovy
// source: "", // 脚本返回List<String>对象,null:验证通过,List:错误信息列表
// consts: { // 常量
// },
// variables: { // 环境变量
// }
},
validateResponse: {// 入参验证失败响应,处理方式同dataMapping.response
fixedBody: { // 固定的body
"code": -411
},
fixedHeaders: {// 固定header
"a": "b"
},
headers: { // 引用的header
},
body: { // 引用的header
"errorMsg": "string validateMsg", // 默认值
},
script: {
"aggregate_config_script_id": 2
}
},
langDef: {
"langParam": "input.request.body.languageCode",
"langMapping": {
"zh": "0",
"en": "1"
}
},
dataMapping: {// 聚合接口数据转换规则
response: {
fixedBody: { // 固定的body
"code": "b"
},
fixedHeaders: {// 固定header
"a": "b"
},
headers: { // 引用的header,默认为源数据类型,如果要转换类型则以目标类型+空格开头,如:"int "
"abc": "int step1.requests.request1.headers.xyz"
},
body: { // 引用的header,默认为源数据类型,如果要转换类型则以目标类型+空格开头,如:"int "
"abc": "int step1.requests.request1.response.id",
"inn.innName": "step1.requests.request2.response.hotelName",
},
script: { // 脚本计算body的值
"aggregate_config_script_id": 1
// 脚本内容另外存储 用脚本id替换
// type: "", // groovy
// source: ""
}
}
},
"edges": [ // 连接列表
{
"properties": {}, // 连线属性
"sourceNodeName": "START_100", // 连接开始节点
"targetNodeName": "REQUEST_1" // 连线结束节点
}
// ...
],
"nodes": [ // 节点列表
{
"properties": {}, // 节点自定义属性
"type": "START", // 节点类型
"name": "START_100", // 节点标识ID
"text": {
"value": "开始" // 节点名称
}
},
{
"properties": { // 节点自定义属性
"dataMapping": { // 数据转换规则
"request": {
"contentType": "application/json",
"fixedHeaders": [],
"headers": [],
"fixedParams": [],
"params": [
{
"key": "mobile",
"value": "input.request.params.mobile"
}
],
"script": {}
},
"response": {
"contentType": "auto",
"fixedHeaders": {},
"headers": {},
"fixedBody": {},
"body": {},
"script": {}
}
},
"name": "REQUEST_1", // 节点标识ID
"condition": {},
"components": [], // 组件配置
"fallback": {},
"type": "REQUEST", // 节点类型
"method": "GET", // 请求方法
"protocol": "http", // 协议
"serviceType": 2, // 服务类型
"serviceName": "api-example", // 服务名
"path": "/proxy/api-example/getMobileInfo", // API路径
"nodeSize": {
"width": 220,
"height": 100
}
},
"type": "REQUEST",
"name": "REQUEST_1",
"x": 400,
"y": 190
},
{
"properties": {},
"name": "END_101",
"type": "END",
"x": 930,
"y": 190,
"text": {
"value": "结束"
}
}
],
stepConfigs: [{ // step的配置
name: "step1", // 步骤名称
stop: false, // 是否在执行完当前step就返回
dataMapping: {// step response数据转换规则 配置结果
response: {
fixedBody: { // 固定的body
"a": "b"
},
body: { // step result
"abc": "step1.requests.request1.response.id",
"inn.innName": "step1.requests.request2.response.hotelName"
},
script: {// 脚本计算body的值
"aggregate_config_script_id": 1
// 脚本内容另外存储 用脚本id替换
// type: "", // groovy
// source: ""
}
}
},
// 添加组件
components: [
{
"type": "condition",
"desc": "如:判断是否会员",
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
// 比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "", // 固定值:fixed 引用值: ref
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
},
{
"type": "circle",
"desc": "", // 描述 如:循环调用10次
"dataSourceType": "", // 固定值:fixed 引用值: ref
"dataSource": "", // int or string
// 循环条件
"execConditions": [
{
"type": "condition",
"desc": "", // 描述: 如:判断是否会员
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
// 比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
}
],
// 退出条件
"breakConditions": [
{
"type": "condition",
"desc": "如:判断是否会员",
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
//比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
}
]
}
],
requests: [ //每个step可以调用多个接口
{
name: "request1", // 接口名,格式request+N
type: "REQUEST", // 类型,RESTful接口-REQUEST | Dubbo接口-DUBBO | gRPC接口-GRPC
serviceName: 'com.abc.UserService', // [Dobbo/gRPC接口]
version: '1.2', // 仅Dubbo
group: '', // 仅Dubbo
paramTypes: 'int,java.lang.String,com.abc.entity.Depart',// 仅Dubbo
method: "GET", // [RESTful接口] HTTP方法,GET/POST等
// 'method': 'getUserInfo', // [Dobbo/gRPC接口] 自定义方法:如'getUserInfo' 已有复用字段
url: "", // [仅RESTful接口] 默认url,当环境url为null时使用
devUrl: "http://baidu.com", // 仅RESTful接口
testUrl: "http://baidu.com", // 仅RESTful接口
preUrl: "http://baidu.com", // 仅RESTful接口
prodUrl: "http://baidu.com", // 仅RESTful接口
timeout: 3000, // 超时时间 单位毫秒,允许1-10000秒之间的值,不填或小于1毫秒取默认值3秒,大于10秒取10秒
condition: { // 预处理 脚本配置
"aggregate_config_script_id": 1
},
fallback: {
mode: "stop", // stop|continue当请求失败时是否继续执行
defaultResult: "" // 当mode=continue时,可设置默认的响应报文(json string)
},
dataMapping: { // 数据转换规则
request: {
fixedBody: {},
fixedHeaders: {},
fixedParams: {},
headers: {//默认为源数据类型,如果要转换类型则以目标类型+空格开头,如:"int "
"abc": "step1.requests.request1.headers.xyz"
},
body: {
"*": "input.request.body", // * 用于透传一个json对象
"inn.innId": "step1.requests.request1.response.id" // 默认为源数据类型,如果要转换类型则以目标类型+空格开头,如:"int "
},
params: {//默认为源数据类型,如果要转换类型则以目标类型+空格开头,如:"int "
"userId": "input.requestBody.userId"
},
script: {// 脚本计算body的值
"aggregate_config_script_id": 1
// 脚本内容另外存储 用脚本id替换
// type: "", // groovy
// source: ""、
}
},
response: {
fixedBody: {},
fixedHeaders: {},
headers: {
"abc": "step1.requests.request1.headers.xyz"
},
body: {
"inn.innId": "step1.requests.request1.response.id"
},
script: {// 脚本计算body的值
"aggregate_config_script_id": 1
// 脚本内容另外存储 用脚本id替换
// type: "", // groovy
// source: ""
}
},
// 添加组件 (请求内)
components: [
{
"type": "condition",
"desc": "如:判断是否会员",
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
// 比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "", // 固定值:fixed 引用值: ref
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
},
{
"type": "circle",
"desc": "", // 描述 如:循环调用10次
"dataSourceType": "", // 固定值:fixed 引用值: ref
"dataSource": "", // int or string
// 循环条件
"execConditions": [
{
"type": "condition",
"desc": "", // 描述: 如:判断是否会员
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
// 比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
}
],
// 退出条件
"breakConditions": [
{
"type": "condition",
"desc": "如:判断是否会员",
"value1": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
},
//比较符: eq gt ge lt le ne contains notContain containsAny isNull isNotNull isBlank isNotBlank isEmpty isNotEmpty
"operator": "",
"value2": {
"type": "fixed/ref",
"fixedDataType": "", // 固定值的数据类型: number/string/boolean
"refDataType": "", // 引用值的数据类型:int/long/float/double/string/boolean/array
"value": null
}
}
]
}
]
}
}
]
}]
};
# 上下文设计
// 上下文数据结构设计
// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果
var context = {
// 是否DEBUG模式
debug: false,
// 各个操作的耗时
elapsedTimes: [{
[actionName]: 123, // 操作名称:耗时
}],
// exception info
exceptionMessage: "",
exceptionStacks: "",
exceptionData: "",
// 客户输入和接口的返回结果
input: {
request: {
path: "",
method: "GET/POST",
headers: {},
body: {},
params: {}
},
response: { // 聚合接口的响应
headers: {},
body: {}
}
},
node: {
[node id]: {
request: {
url: "",
method: "GET/POST",
headers: {},
body: {}
},
// 根据转换规则转换后的接口响应
response: {
headers: {},
body: {}
},
// 请求循环组件当前循环对象
item: null,
// 请求循环组件当前循环对象的下标
index: null,
// 请求循环的结果
circle: [
{
// 循环对象
item: null,
// 循环对象的下标
index: null,
// 请求相关参数
request: {
url: "",
method: "GET/POST",
headers: {},
body: {}
},
// 根据转换规则转换后的接口响应
response: {
headers: {},
body: {}
}
}
],
// 条件组件的执行结果
conditionResults: [
{
'我的条件1': true
}
]
}
},
// 步骤
step1: {
requests: { // 接口1
request1: { // 请求相关参数
request: {
url: "",
method: "GET/POST",
headers: {},
body: {}
},
// 根据转换规则转换后的接口响应
response: {
headers: {},
body: {}
},
// 请求循环组件当前循环对象
item: null,
// 请求循环组件当前循环对象的下标
index: null,
// 请求循环的结果
circle: [{
// 循环对象
item: null,
// 循环对象的下标
index: null,
// 请求相关参数
request: {
url: "",
method: "GET/POST",
headers: {},
body: {}
},
// 根据转换规则转换后的接口响应
response: {
headers: {},
body: {}
}
}],
// 条件组件的执行结果
conditionResults: [
{
'我的条件1': true
}
]
},
// 接口2
request2: {
// ... 字段网关接口1
}
//... 其它接口,字段同上
},
// 步骤结果
result: {},
// 步骤循环组件当前循环对象
item: null,
// 步骤循环组件当前循环对象的下标
index: null,
// 步骤循环的结果
circle: [{
// 循环对象
item: null,
// 循环对象的下标
index: null,
// 步骤结果
result: {}
}]
}
}