数据开放平台架构设计(一):从 SQL2API 到数据开放平台的演进
数据开放平台本质上是把"数据变成服务"这件事系统化。我一开始做的是 SQL2API:页面上写 SQL、配置参数,系统自动生成接口。这个工具确实能省掉很多重复 CRUD,但一旦拿去给多个业务方长期使用,问题就不只是"能不能查出数据"了。
真实落地时,大家会马上追问:谁能调这个接口?能看到哪些字段?一次上限查多少?慢查询谁负责?数据源密码放哪?字段改名会影响哪些接口?有没有审计记录?这些都不是 SQL2API 本身能顺手解决的问题。
这一篇聊背景:为什么要从一个 SQL2API 工具,继续往数据开放平台演进,以及平台的架构怎么拆。
一、从 SQL2API 到数据开放平台
SQL2API 解决的是一个很具体的问题:把 SQL 变成 API,省掉 CRUD 的模板代码。 这个能力很有价值,但它只是数据开放链路里的一个环节。
真实场景里,一个完整的数据开放链路长这样:
- 数据接入:连各种数据源(MySQL、PostgreSQL、ES、Hive、API),把数据接进来
- 数据加工:字段映射、格式转换、数据脱敏、聚合计算
- 服务发布:把加工后的数据发布成 API,支持多种协议(REST、gRPC、WebSocket)
- 访问控制:AK/SK 认证、租户隔离、流量控制、配额管理
- 监控治理:调用链追踪、慢查询告警、数据血缘、审计日志
- 运维管理:灰度发布、容灾备份、SDK 生成、文档管理
SQL2API 只覆盖了第 3 步的一部分。要从"工具"升级为"平台",需要把这六步都串起来,而且要能长期运维。
类比一下:SQL2API 是一个厨师,能把食材做成菜。数据开放平台是一个餐厅,从采购(数据接入)、备菜(数据加工)、烹饪(服务发布)、上菜(访问控制)、品控(监控治理)到运营(运维管理),全流程都有。
1.1 为什么不直接开放数据库
有人会问:既然本质是查数据,为什么不直接给业务方一个只读账号,让他们连库查?
这个方案短期速度高,长期更麻烦:
- 权限太粗:数据库账号一般按库、表授权,很难细到"这个应用只能看订单表里的 5 个字段"。
- 审计断层:只能看到某个账号执行了 SQL,很难还原到具体应用、具体接口、具体业务场景。
- 流量不可控:一个全表扫描或者大分页,就可能把线上库拖慢。
- 数据口径失控:每个调用方自己写 SQL,同一个指标可能有三种算法。
- 变更风险大:表结构改了,谁受影响靠猜,没人愿意拍胸脯。
所以数据库可以作为底座,但不应该直接暴露给调用方。平台要把权限、限流、审计、口径和 SLA 都挡在前面。
1.2 为什么也不能只靠网关
API Gateway 很重要,但它解决的是入口问题:认证、限流、路由、协议转换。它不知道某个接口背后查了哪些表,也不知道手机号字段该不该脱敏,更不知道这个 SQL 是否会扫全表。
数据开放平台需要补的是数据侧能力:
- 权限:应用级、API 级、字段级、数据范围级权限。
- 审计:谁在什么时间,用什么参数,访问了什么数据。
- 限流与配额:保护平台,也保护底层数据库。
- 元数据:数据源、表、字段、接口、参数、返回结构都要可管理。
- 血缘:一个字段变更,要知道影响哪些 API 和调用方。
- 数据源管理:连接池、密钥、健康检查、备用数据源不能散落在代码里。
- SLA:接口超时、成功率、慢查询、告警都要有明确指标。
这些能力靠网关很难补齐,必须下沉到数据服务平台本身。
二、整体架构
先把全貌拉出来:

整体分四层:
- 接入层:API Gateway 做统一入口,负责鉴权、限流、路由、协议转换。所有外部请求先过这一层,过滤掉非法流量再转发到服务层。
- 服务层:核心业务逻辑,包括 SQL 转 API 引擎、数据转换引擎、数据聚合引擎。这三个引擎各司其职,通过 Pipeline 串联起来。
- 数据层:动态数据源路由,支持连接多种数据库。用户配置 API 时选择数据源,运行时自动路由。
- 治理层:监控、审计、血缘、配置管理。保障平台的可观测性和可运维性。
三、核心模块说明
3.1 SQL 转 API 引擎
这是平台的核心能力,继承自 SQL2API。用户在页面上写 SQL、配参数、选数据源,系统自动生成 API 端点。
和原来的 SQL2API 相比,做了几个升级:
- 多数据源支持增强:不只是关系型数据库,还支持 ES、MongoDB 等 NoSQL
- SQL 模板引擎升级:支持更复杂的 DSL 语法,包括
<choose>、<trim>、<foreach>等 - 结果格式化:支持嵌套对象、数组聚合等复杂返回结构
- 发布前校验:保存 SQL 时做只读校验、参数校验、超时校验,避免问题在调用时才暴露
- 运行时管控:执行时绑定调用方、租户、限流和审计上下文,接口不是裸跑 SQL
3.2 数据转换引擎
原始数据查出来之后,往往不能直接给调用方。需要做字段映射(下划线转驼峰)、数据脱敏(手机号打星号)、格式转换(日期格式统一)、聚合计算(求和、平均、计数)。
数据转换引擎用规则驱动,用户在界面上配置转换规则,运行时自动执行:
@Component
public class DataTransformEngine {
@Autowired
private List<TransformRule> rules;
public List<Map<String, Object>> transform(TransformConfig config,
List<Map<String, Object>> rawData) {
return rawData.stream()
.map(row -> applyRules(config, row))
.collect(Collectors.toList());
}
private Map<String, Object> applyRules(TransformConfig config,
Map<String, Object> row) {
Map<String, Object> result = new LinkedHashMap<>(row);
for (TransformRule rule : rules) {
if (rule.supports(config)) {
result = rule.apply(config, result);
}
}
return result;
}
}3.3 鉴权与流控
鉴权用 AK/SK 机制:每个调用方分配一对 Access Key 和 Secret Key,请求时带上签名,服务端验签。比单纯的 Token 认证更安全,密钥不在网络上传输,只有签名。
流控用令牌桶算法,按调用方维度限制 QPS。超限直接返回 429,不排队不等待:
@Component
public class FlowControlInterceptor implements HandlerInterceptor {
private final Map<String, RateLimiter> limiterMap = new ConcurrentHashMap<>();
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String appKey = request.getHeader("X-App-Key");
if (appKey == null) return true;
RateLimiter limiter = limiterMap.computeIfAbsent(appKey, key -> {
FlowConfig config = flowConfigService.getByAppKey(key);
return RateLimiter.create(config.getQps());
});
if (!limiter.tryAcquire()) {
response.setStatus(429);
response.getWriter().write("{\"code\":429,\"message\":\"请求频率超限\"}");
return false;
}
return true;
}
}3.4 监控与治理
每个 API 调用都记录详细日志:谁调的、传了什么参数、执行了什么 SQL、返回了什么结果、耗时多少。这些日志写入 ELK,可以做全链路追踪。
慢查询自动告警:SQL 执行超过阈值(比如 3 秒)自动触发告警,推送到钉钉/飞书。数据血缘记录每个 API 涉及哪些表和字段,方便做影响分析。
3.5 数据源与元数据管理
这一块很容易被低估。早期我也觉得"存个 JDBC URL 就行",后面才发现数据源管理做不好,平台会变成一堆隐形风险:
- 数据源密码要加密存储,不能出现在配置文件和日志里。
- 连接池要按数据源隔离,避免一个慢库拖垮全部接口。
- 数据源要有健康检查和备用地址,发布 API 前先验证连通性。
- 表、字段、字段类型、敏感级别要沉淀成元数据,给权限、脱敏、文档和血缘复用。
- API 要绑定负责人、调用方、SLA、下线时间,不能只存一段 SQL。
这些不是锦上添花。只要平台开始被多个团队依赖,它们就是日常运维的基本盘。
四、技术选型
| 组件 | 选型 | 理由 |
|---|---|---|
| 应用框架 | Spring Boot 3.x | 生态成熟,团队熟悉 |
| 数据库访问 | JdbcTemplate | 适合运行时动态 SQL,返回结构也够灵活 |
| API Gateway | Spring Cloud Gateway | 和 Spring 生态无缝集成 |
| 注册中心 | Nacos | 服务注册 + 配置管理一体 |
| 缓存 | Redis | 高性能,支持分布式锁 |
| 监控 | Prometheus + Grafana | 业界标准,社区活跃 |
| 日志 | ELK Stack | 全文检索,分析能力强 |
| 限流 | Guava RateLimiter + Sentinel | 单机用 Guava,集群用 Sentinel |
JdbcTemplate 为什么适合这个场景,上一个系列已经详细分析过了,这里不重复。核心原因就一个:SQL2API 需要在运行时执行 SQL 模板,JPA/MyBatis 都更偏向编译期确定结构,JdbcTemplate 反而更轻。
五、核心设计原则
设计这个平台的时候,有几个原则一直贯穿始终:
配置驱动,代码只写框架。 平台的核心逻辑是通用的(鉴权、流控、数据转换),具体业务通过配置驱动。用户在界面上配置 SQL、参数、转换规则,系统自动生成服务。不写一行业务代码。
分层解耦,可独立扩展。 接入层、服务层、数据层、治理层各自独立,可以单独扩展。比如数据源从 MySQL 扩展到 ES,只需要在数据层加一个 ES 的 Driver,上层代码不用动。
安全第一,默认安全。 所有 API 默认需要鉴权,默认开启 SQL 注入防护,默认开启数据脱敏。安全不是可选项,是默认行为。
可观测性是刚需。 每个 API 调用都有完整日志、指标、追踪。出了问题能快速定位,不用翻代码加日志。
六、和 SQL2API 的关系
简单说,SQL2API 是数据开放平台的一个子模块。数据开放平台在 SQL2API 的基础上,扩展了鉴权、流控、数据转换、监控治理等能力。
原来的 SQL2API 系列文章聊的是"怎么把 SQL 变成 API",这个系列聊的是"怎么把数据变成服务"。范围更大,但核心思想没变,配置驱动、减少重复、提升效率。
后面几篇会逐一深入每个模块的实现细节。