目前,诸多企业拥有各种软件业务系统,随即产生了大量的生产数据,但是这些数据却“散落”在不同的“地方”。如何将这些数据进行统一的管理,或者进行快速地查询以便深度挖掘数据的潜力是很多开发者面临的问题。因此,根据我们在数据平台工作的一些经验,提出一个基于”云原生“的构建数据查询API的框架,来解决一些这样的问题。
我们很快意识到我们必须构建一个满足以下要求的系统:
我们构建的系统被称为“达芬奇”(DaVinci)(以纪念这位天才500周年诞辰),它是一项无所不包的服务,可实现信息检索(报表)API的创建,管理和执行。在此强调,它不是数据处理平台,因为它已经假设要检索的数据已先后由其他系统(例如ETL管道和其他数据处理应用程序)转换和管理。
在设计达芬奇时,我们分析了数据报表API接口的“解剖”,并仔细查看了对应接口周围的元数据。有没有一种方法可以使接口的描述形式化,以便我们可以自动创建和维护接口,从而减轻开发人员的负担?答案是肯定的: 一个查询API接口始终具有以下特征:
于是,我们提出了JSON语法来定义报表接口的元数据,并将其称为报表接口组件(Reporting Endpoint Package: REP)。基本上看起来像这样:
{
"rep_name": "xxxx", //组件名称
"category": "xxxx", //目录名称
"display_name": "xxxxxx", //显示名称(我们将它考虑前端展示使用)
"description": "xxxxxxxx", //此接口的描述
"endpoint": "/sample-api", // URL 定义, 例如 diva-qa.marqeta.com/fraud_score
"maxrows": 2000, // 默认返回最大行数
"csv_download": false,
"default_filter": "{ \"column\" : \"xxxxx\", \"operator\" : \"xxxx\", \"value\": xxx }", // 默认的过滤器
"data_getter_type": "SQL", //数据获取的种类 SQL或NoSQL,或者API
"data_getter_data_source": "Athena",
"data_getter_template": "SELECT @columns@ FROM xxxxx @where@", //数据获取的模板
"acl_endpoint": "{\"xxxxxx\":[\"xxxxxx\"]}", //访问控制模块的接口定义
"acl_columns": "{\"acting_user_token\": [\"departments\":[\"Risk\"]}", // 访问控制的字段查询
"columns": [ // 字段定义
{
"column_name": "acting_user_token",
"column_type": "string",
"display_name": "Acting User Token",
"description": "A unique string that identifies a card holder",
"filterable": true,
"return_by_default": true,
"pii": true
},
{
"column_name": "amount",
"column_type": "float",
"display_name": "Amount",
"description": "Transaction Amount",
"filterable": true,
"return_by_default": true,
"pii": false
},
...
]
}
达芬奇的基础基于其自己的DSL之上,报表接口组件和Serverless计算(AWS Lambda)的概念。下图显示了高级架构:
因为Marqeta所有的基础设施都基于AWS(亚马逊云计算服务),所以我们也选择“云原生”的理念来建立应用,我们主要用到的AWS 服务以及重要概念为:
同样,我们也能在阿里云上找到上述类似的服务。比如:
我们使用了单独的访问控制服务,其本身也是一个面对内部服务的API,用于管理公司内部数据系统(包括数据应用程序和API)的安全性。其提供服务包括:管理组织机构及其用户的操作,用户身份验证以及API访问令牌的管理。
具体来说,访问控制API包含的服务有如下:
通过单独的访问权限控制,我们可以严格的限制使用API的权限,以及针对不同组织机构或者用户类型返回不同的可查询字段。
“过滤器”的基本概念其实是需要针对每个请求执行的查询。为了扩展灵活性,我们提出了”过滤器“协议,将嵌套的JSON结构转换为SQL语法。这种灵活的过滤器允许用户按需定制查询语句。 “过滤器”的背后是一个简单的DFS,用于解析JSON对象,因此,为了使其工作,它需要开发人员定义的数个关键词。
"single" : "代表有且只有一个查询条件",
”AND/OR“:”类似于SQL逻辑运算符“,
{"column": "字段名称", "operator": ">,<, !=, ==, >=, <= 运算符", "value": "在此限制条件的值"}
以下,我们举例说明过滤器的使用方法:
SELECT 消费额 from 账单表 WHERE 消费额 > 20.00
在"过滤器"中格式为:
filter = {
"single": {"column": "消费额", "operator": ">", "value": 20.00},
}
SELECT 测试字段1,测试字段2,测试字段3 from 测试表 WHERE (测试字段1 > 20.0 or 测试字段2 > 30.0 or ((测试字段2 > 10.0 and 测试字段3 = 'sqr') and 测试字段1 > 40.0))
在"过滤器"中格式为:
filter = {
"or": [
{"column": "测试字段1", "operator": ">", "value": 20.00},
{"column": "测试字段2", "operator": ">", "value": 30.00},
{
"and": [
{"and": [
{"column": "测试字段2", "operator": ">", "value": 10.00},
{"column": "测试字段3", "operator": "=", "value": "sqr"}
]},
{"column": "测试字段1", "operator": ">", "value": 40.00}
]
}
]
}
在我们的设计中,由于过滤器是高度可定制的,并且不绑定与某一个数据源,所以我们不直接处理查询语法的检查,而是由相应数据源(例如,MySQL)来处理它或者返回相应错误代码。
我们构建"达芬奇"的目的是替换Marqeta旧的数据报表API系统,以使其具有可扩展性。我们决定将基础架构迁移到"Serverless"架构中,主要是因为有以下四个好处:
AWS API Gateway 官方文档有详细的工作原理和使用优势,能够无缝集成 Lambda
因为Serverless 为事件驱动型架构,下图通过请求一个报表API的事件,举例说明了Lambda Function(a.k.a Serverless)响应的执行步骤。
在设计达芬奇的过程中,我们运用了Configuration as a Service的思想 - 无需更改代码即可动态更改软件系统行为的能力。这样的好处是显而易见的,之前对于一个API接口的维护和管理,通常需要完成需求确定,新增代码,审核测试,到部署这一系列为期2周左右的流程。REP 组件作为达芬奇的核心基础,我们提供了组件的全周期管理【增,删,查,改】,并且可以通过 ,以及通过API Gateway 动态增加或更改URL Path,将这取消一大部分这样的流程。