PAYATHON 2026

设计 DWaaS:与 Databricks、Snowflake、Fabric 的架构差距

支付小周

明确结论

现有的 ETL、元数据和数据质量平台可以作为 DWaaS 的基础,但只有 pipeline orchestration 还不能称为 DWaaS。以下五项能力缺一不可:

  1. 持久、可共享的数据存储层;
  2. 面向租户的 SQL 查询服务;
  3. 计算资源生命周期和工作负载管理;
  4. 覆盖查询、存储与元数据的安全隔离;
  5. 可观测、可计量、可恢复的控制平面。

在生产环境中,compute/storage separation、弹性扩缩容和高可用通常也必不可少,但第一版不需要达到 Snowflake 的成熟度。流处理、语义层、自动优化、跨区域复制和精细化计费,可以在后续阶段逐步加入。

较稳妥的演进方式是保留现有 ETL 和 metadata layer,将其升级为统一控制平面。同时尽早引入 SQL query engine,先提供基于共享存储的查询服务,再逐步完善租户隔离、弹性计算、治理和计量。

什么才算 DWaaS

DWaaS 的判断标准不是平台是否拥有数据仓库组件,而是能否把数据仓库能力作为服务交付。用户提交 SQL 或 API 请求后,平台应完成身份验证、资源分配、查询执行、故障恢复、权限检查和用量记录,无需用户直接管理集群。

1. 统一且持久的数据存储

数据必须独立于单个计算节点存在。常见方案包括:

  • 对象存储加开放表格式,例如 S3-compatible storage + Apache Iceberg;
  • 云对象存储加平台自有表格式;
  • 分布式数据库或分析型数据库自身的持久化存储。

第一版可以不做完全无状态的计算层,但不能只把业务数据保存在临时计算节点的本地磁盘上。否则,集群扩缩容、故障恢复以及多个计算集群共享数据都会变得困难。

2. 可持续提供的 SQL 查询服务

DWaaS 至少需要一个稳定的查询入口,涵盖:

  • SQL endpoint、JDBC、ODBC 或 REST API;
  • 查询解析、规划、执行和结果返回;
  • 查询取消、超时、重试和状态查询;
  • 并发控制与资源配额;
  • 统一的 catalog、schema 和 table 命名空间。

语义层不是前置条件。初期可以直接提供表、视图和 SQL,指标定义、业务模型及 BI semantic model 后续再做。

3. Compute abstraction

用户看到的应该是 warehouse、endpoint、pool 或 cluster 这类逻辑资源,而不是 Kubernetes Pod、worker IP 或底层虚拟机。

一个计算抽象至少需要描述:

warehouse:
  name: analytics-medium
  tenant_id: tenant-a
  engine: trino
  size: medium
  min_workers: 0
  max_workers: 20
  auto_suspend_seconds: 300
  concurrency_limit: 30
  queue_timeout_seconds: 120
  catalog_policy: analytics-readonly

控制平面要把这份逻辑配置转换成实际资源,并负责:

  1. 创建或唤醒计算资源;
  2. 把查询路由到正确的 coordinator;
  3. 根据队列长度、CPU、内存等指标扩缩容;
  4. 在资源空闲后将其暂停或销毁;
  5. 记录查询消耗;
  6. 向用户隐藏底层节点变化。

早期没有必要实现任意规模的瞬时扩容。先支持固定规格、手动扩缩容和空闲暂停,通常足以验证产品模型。

4. 多租户安全边界

仅在 API 中携带 tenant_id 并不能形成可靠隔离。租户上下文必须贯穿整个请求链:

Identity
  → Tenant context
  → Warehouse routing
  → Catalog authorization
  → Object storage credentials
  → Query audit and usage metering

至少要覆盖:

  • 身份认证和 tenant membership;
  • warehouse、catalog、schema、table 级授权;
  • 凭证隔离;
  • 查询与数据访问审计;
  • CPU、内存、并发数和扫描量配额;
  • 元数据过滤,避免租户看到无权访问的对象;
  • 网络隔离或运行时隔离。

早期可以让多个租户共享计算集群,但资源配额和数据访问隔离必须到位。对于安全要求较高的客户,可以提供独占 warehouse、独立 namespace、独立云账号或独立集群。

5. 控制平面与可观测性

控制平面需要管理:

  • 租户和身份;
  • warehouse 定义与生命周期;
  • catalog 和数据对象;
  • 查询状态;
  • 策略和权限;
  • 作业与调度;
  • 用量和审计事件。

重要状态需要持久化,API 操作也应尽量保持幂等。例如,创建 warehouse 时可以使用幂等键,避免客户端重试产生重复资源:

POST /v1/warehouses
Idempotency-Key: 7aa1c37e-8b44-4f94-b94e-f4ef519aac86
Content-Type: application/json
{
  "name": "analytics-medium",
  "tenantId": "tenant-a",
  "size": "medium",
  "autoSuspendSeconds": 300
}

可观测性也需要从一开始建设。缺少 query ID、trace、资源指标和审计日志,就很难排查慢查询、资源争抢、错误计费或越权访问。

Snowflake 一类平台如何抽象计算资源

Snowflake 的内部实现包含专有设计。外部只能根据公开的架构说明做高层概括,不能把它简单等同于某个开源组件。

从整体上看,这类平台通常分为三层:

Cloud services / control plane
  ├─ Authentication and authorization
  ├─ Metadata and transaction coordination
  ├─ Query parsing, optimization and routing
  └─ Resource lifecycle and metering

Independent compute
  ├─ Warehouse A: BI workload
  ├─ Warehouse B: ETL workload
  └─ Warehouse C: data science workload

Shared storage
  ├─ Table data
  ├─ Metadata
  └─ Persistent intermediate state

warehouse abstraction 是控制平面提供的逻辑计算边界。每个 warehouse 有自己的执行资源、并发状态和缓存,可以独立扩缩或暂停。数据保存在共享持久层,因此暂停计算不会造成数据丢失。

compute/storage separation 并不意味着计算节点上完全没有本地状态。执行节点通常仍会使用内存、本地磁盘缓存、shuffle 数据和临时结果。真正需要分离的是数据的持久所有权。即使计算资源被销毁,权威数据仍然存在,其他计算资源也能重新访问。

自建平台可以参考这种模型,但不需要复制具体实现。第一阶段可以将一个 warehouse 映射为:

  • 一个独立 Trino cluster;
  • 一个 Kubernetes namespace 中的 engine deployment;
  • 一个共享集群中的 resource group;
  • 一个 ClickHouse、StarRocks 或 Doris compute group。

不同方案的隔离强度和成本也不同。将每个 warehouse 映射为独立集群,隔离边界清楚,但启动速度较慢。共享集群成本更低,不过对 workload management 的要求更高。

是否应该尽早引入 query engine

应该尽早引入,但不必立即把所有 ETL 都交给它。

ETL-first 是合理的起点,特别是在数据接入、清洗和质量控制还不稳定的时候。但在查询引擎出现之前,平台只能证明自己能够生产数据,无法证明它可以持续交付仓库服务。查询引擎还会提前暴露一些纯 pipeline 模式难以发现的问题:

  • 多用户并发;
  • 小查询和大查询争抢资源;
  • catalog 一致性;
  • schema evolution;
  • 权限下推;
  • 大规模 scan、join、shuffle 和 spill;
  • 查询取消与超时;
  • 成本归属。

建议保留两条执行路径,不必强行统一:

Batch path:
API → Orchestrator → Spark/Flink/dbt → Shared tables

Interactive path:
JDBC/REST → Query gateway → Trino/other engine → Shared tables

两条路径共用 catalog、权限、表格式和审计体系。这样既能保留现有的 pipeline 投资,也能尽早验证 DWaaS 的核心假设。

如果主要场景是交互式联邦查询,Trino 是常见选项。如果希望由单一引擎同时承担高并发分析和数据写入,也可以评估 ClickHouse、Apache Doris 或 StarRocks。选型时不能只比较 SQL 覆盖率,还要测试并发能力、写入语义、事务能力、资源隔离和运维复杂度。

转型过程中最常见的扩展瓶颈

元数据控制面

pipeline 系统访问元数据的并发通常不高。查询平台则可能在每次解析、优化和授权时读取大量表、分区及统计信息。常见问题有:

  • catalog 单点;
  • 高频 list partitions;
  • 大表统计信息读取缓慢;
  • schema cache 失效风暴;
  • 元数据数据库锁竞争。

catalog 服务应与业务编排数据库解耦,并支持缓存、分页、版本号以及事件驱动的 cache invalidation。不要让每个查询都直接扫描 pipeline metadata 表。

并发和资源争抢

最先遇到的瓶颈未必是总数据量,往往是查询并发。一个失控的大型 join 就可能耗尽集群内存,拖慢所有租户。

以下能力需要尽早建立:

  • admission control;
  • resource group;
  • per-tenant quota;
  • 查询优先级;
  • memory limit;
  • spill 策略;
  • 超时和取消;
  • ETL 与 BI 工作负载隔离。

对象存储请求与小文件

共享对象存储容量很大,但文件数量、请求次数和读取放大会直接影响延迟与成本。频繁的小批次写入容易制造大量小文件,拖慢 planning 和 scan。

compaction、snapshot expiration、orphan file cleanup 和统计信息收集应作为平台维护任务统一执行,不能全部交给用户处理。

Shuffle、网络和数据倾斜

大规模聚合与 join 会产生大量网络传输。热点 key、错误的 join order 或不准确的统计信息,都可能让少数 worker 过载。

除扩容以外,还需要:

  • 成本优化器和统计信息;
  • partition pruning;
  • dynamic filtering;
  • broadcast join 限制;
  • 数据倾斜检测;
  • local spill 和 remote spill 规划。

多租户隔离

共享集群中的 noisy neighbor 会同时影响性能和成本。只根据 CPU 扩缩容,无法解决内存、网络、对象存储带宽及 coordinator 压力。

可以把隔离分为三个级别:

隔离方式成本隔离强度适用场景
共享集群 + resource group低中低开发环境、小租户
独立 warehouse 集群中高生产分析、重要客户
独立账号或基础设施高很高强合规、监管场景

计量准确性

usage-based billing 不能只统计集群运行时间。在共享集群中,还需要确定 CPU、内存、扫描字节、对象存储请求和空闲资源的分摊方式。

第一阶段可以先建立一套容易解释的内部计量:

{
  "tenantId": "tenant-a",
  "warehouseId": "wh-42",
  "queryId": "q-20260901-001",
  "startedAt": "2026-09-01T02:10:00Z",
  "durationMs": 18420,
  "cpuMs": 73110,
  "peakMemoryBytes": 2147483648,
  "processedBytes": 68719476736,
  "spilledBytes": 0,
  "status": "SUCCEEDED"
}

先确保事件不会重复,而且可以追踪和重放,再设计价格模型。否则计费规则发生变化后,很难根据历史数据重新计算。

可组合的开源组件

以下组件是架构候选,不是一套可以直接拼成 Snowflake 的固定清单。不同组件之间的权限、事务和元数据语义,都需要经过实际集成验证。

Query engine

  • Trino:适合交互式 SQL、联邦查询和多 catalog 场景;
  • Apache Spark:适合大规模批处理、复杂转换和机器学习;
  • Apache Flink:适合流处理、持续计算和低延迟状态计算;
  • ClickHouse:适合低延迟 OLAP 和高并发聚合;
  • Apache Doris / StarRocks:适合实时分析、物化视图和面向 BI 的服务。

第一阶段不建议同时引入多个交互式 SQL 引擎。应先确定一个主查询引擎,再由 Spark 或 Flink 处理它不擅长的任务。

Table format 和 catalog

  • Apache Iceberg:适合开放湖仓表、snapshot、schema evolution 和多引擎访问;
  • Delta Lake:与 Spark 生态结合紧密;
  • Apache Hudi:适合增量写入、CDC 和数据湖更新场景;
  • Project Nessie:提供面向数据湖 catalog 的版本管理能力;
  • Hive Metastore:兼容范围广,但大规模部署时需要谨慎处理扩展性和缓存;
  • OpenMetadata / DataHub:适合数据发现、技术元数据和 lineage 展示。

table catalog 和 metadata discovery catalog 是两个不同的概念。前者参与查询正确性与表事务,后者主要用于搜索、治理和数据资产管理。搜索型 metadata 产品不能替代事务性 catalog。

Governance 和授权

  • Apache Ranger:用于集中策略管理,并可与部分引擎集成;
  • Open Policy Agent:适合通用策略判断和 API authorization;
  • OpenLineage + Marquez:适合采集及展示作业 lineage;
  • Keycloak:可用于 OIDC、身份认证和组织映射。

权限必须在实际读取数据的位置执行。只在 UI 或 API gateway 中隐藏表名,无法阻止用户通过 JDBC 或其他引擎读取数据。

Orchestration、质量和可观测性

  • Apache Airflow / Dagster:用于批处理编排;
  • Argo Workflows:Kubernetes-native workflow;
  • dbt Core:用于 SQL transformation 和模型依赖管理;
  • Great Expectations / Soda Core:用于数据质量检查;
  • Prometheus + Grafana:用于基础指标;
  • OpenTelemetry:用于跨 API、调度器和执行引擎的 trace;
  • OpenSearch:用于检索查询日志和审计事件。

如果现有 orchestration 和 quality 模块运行稳定,没有必要为了平台化而全部替换。更需要做的是让这些模块使用统一的事件、身份和资源标识,并产出统一的 lineage。

推荐的分阶段实施顺序

第一阶段:建立共享数据平面

确定对象存储和主表格式,统一 catalog,并让现有 ETL 产出的表可以被其他引擎读取。先处理 schema evolution、原子提交、小文件治理和失败恢复。

第二阶段:引入查询服务

部署一个主 SQL engine,提供 JDBC、ODBC 或 REST endpoint,并加入查询状态、取消、超时、结果分页和审计日志。完成这些工作后,平台便具备了最小的 DWaaS 形态。

第三阶段:形成 warehouse abstraction

在查询引擎之上增加 warehouse API、资源规格、路由、队列、自动暂停和租户配额。初期可以只提供 small、medium、large 等少量离散规格,这比一开始就支持任意资源组合更容易运营。

第四阶段:强化隔离和治理

加入 RBAC、行列级策略、凭证隔离、资源组、独占 warehouse 和端到端 lineage。对于高敏感租户,则提供更强的基础设施边界。

第五阶段:弹性和计费

积累真实 workload 后,再调整 autoscaling。扩缩容不能只参考 CPU,还要考虑:

  • queued queries;
  • running queries;
  • memory pressure;
  • split backlog;
  • coordinator load;
  • cache warm-up cost;
  • cluster startup latency。

最后,再把已经验证的 usage event 转换成账单。计量系统和支付系统应彼此独立。前者记录事实,后者应用价格和折扣规则。

需要避免的架构误区

第一,不要把 Kubernetes 当作 compute abstraction。Kubernetes 负责资源编排,但 warehouse 的状态、路由、策略、暂停和计量仍然要由平台控制平面实现。

第二,不要过早承诺 “serverless”。如果查询冷启动需要数分钟,扩缩容会中断查询,或者空闲资源无法可靠回收,那么 managed warehouse 是更准确的描述。

第三,不要让每个引擎各自维护权限和表定义。多个 catalog、身份模型和策略来源很快就会出现不一致。控制平面应保留统一的身份和策略来源,同时明确哪些策略可以下推到执行引擎。

第四,不要先设计复杂计费,再处理资源隔离。如果没有稳定的 query attribution 和资源边界,再精细的价格规则也无法保证公平。

最终目标不是复制 Databricks、Snowflake 或 Fabric 的所有功能,而是先打通一条完整链路:租户创建 warehouse 并提交 SQL,平台安全地分配资源、访问共享数据、返回结果,同时记录完整用量。这条链路稳定后,其他能力都可以围绕它逐步完善。

备注:内容仅供参考。