Snowflake 数据建模——掌握 Snowflake 架构

104 阅读20分钟

自数据库诞生以来,伴随数据规模与处理需求的增长,如何同时管理并发与可扩展性始终是反复出现的难题。多年来,人们尝试了许多创新设计,并取得了参差不齐的成效。然而,这些成功往往也伴随着新的权衡与代价。

Snowflake 团队意识到,要从根本上解决独立的数据存储与分析消费需求所带来的历史难题,必须采用一种全新的思路。他们决定设计一套能够原生运行在云计算平台之上的数据库,从而提供近乎无限的扩展能力。这一努力最终催生了 Snowflake 所称的“数据云(Data Cloud)”——一个通过存储与计算分离来实现实时数据共享与按需弹性算力分配的平台。

在本章中,我们将讨论以下主题:

  • 回顾数据库以往为实现可扩展性所做的尝试
  • 了解 Snowflake 如何构建一套原生运行于云端的可扩展数据库
  • 认识 Snowflake 创新架构所带来的独特功能
  • 理解 Snowflake “可变支出模式(variable spend mode)”的成本构成
  • 学会利用多种缓存以降低成本并提升性能

要真正理解 Snowflake 的成就,值得先回顾其之前的各类传统架构,以及它们试图克服的局限。

传统架构

要欣赏 Snowflake 数据云的创新,我们需要先退一步,回忆其前辈们的设计以及相关限制。早在云出现之前,数据库以本地物理设备(on-premises appliances)的形态存在,自问世之日起就直面同一挑战:可扩展性。

过去,数据库被局限在一台物理服务器上,并依赖该服务器的存储与计算能力。随着用量增长,内存会被占满,CPU 需求也会逼近上限,被迫加配硬件或直接购置新服务器。无论哪种选择,都意味着维护与停机,因此硬件采购必须具备前瞻性,按数年维度预估数据库的增长。

下图概述了传统数据库的结构与关键部件。尽管处理能力、内存与磁盘空间在一定程度上可定制,它们依然被打包在无法弹性扩展的物理机器之中。

image.png

图 3.1 —— 典型本地数据库服务器的示意图

在云架构开启软件即服务(SaaS)并引入“按使用付费”的可变支出定价之前,硬件采购往往需要投入可观的资本性支出(CapEx)。因此,硬件容量规划——即对当前与未来算力需求的预估——必须谨慎:估得过保守会导致更早的升级,估得过乐观则意味着为尖端设备支付高价,却在多年内都无法充分利用。虽然数据量与 CPU 需求通常会随业务同步增长,但存储或计算的突发峰值并不鲜见,同样令人头疼。正是在这种背景下,共享磁盘(shared-disk)与无共享(shared-nothing)等新架构应运而生,以突破单机扩展的极限。

首先,让我们看看共享磁盘架构相较传统设计引入了哪些变化,以及它带来的优势。

共享磁盘架构(Shared-disk Architecture)

共享磁盘方法采用一个中心化的存储位置,并将其提供给网络中的多个计算集群。这种设计思路简洁,但在实际落地时,当多方并发加锁与访问数据时会遭遇物理层面的实现难题。

下图展示了共享磁盘架构如何将数据存储从单机中外置出来,并让网络中的所有计算集群都可以访问。

image.png

图 3.2 —— 共享磁盘架构示意图

共享磁盘设计使得可以根据组织内不同工作负载,按需增加不同规模的计算集群。然而这也带来了不可避免的瓶颈:在共享磁盘架构中,添加的集群越多,对中央磁盘的争用就越严重。由于最关键的数据库资源——数据本身——成了瓶颈,这种设计未能兑现可扩展性的承诺。

在共享磁盘失利之处,“无共享”几乎成功。

无共享架构(Shared-nothing Architecture)

无共享架构(例如 AWS Redshift 和 Greenplum 采用的方式)通过将存储与计算集群绑定并隔离开来,规避了共享磁盘的问题。这种设计同样考虑到了组织内团队对资源消费的差异化需求,使数据库集群能够按需定制规模。不过,正如我们在小学就学到的那样,“什么都不共享”并不是协作的最佳策略。

下图展示了无共享架构如何构建自给自足、但彼此隔离的数据库集群。

image.png

图 3.3 —— 无共享架构的组成

在无共享架构中创建数据库集群,尤其是在虚拟化的云资源上创建,确实缓解了对前期物理硬件投资的依赖。然而,节点之间若要共享信息,必须进行数据传输,这会带来性能损耗。

将磁盘与整个集群强绑定还意味着需要在存储与计算模式之间寻找恰当的平衡,而这二者往往可以独立变化。例如,重计算的数据科学负载可能需要对相对较小的数据集投入大量算力;而进行 ETL 批量装载时则可能恰好相反。然而,无共享平台通常无法对这两类资源分别进行细粒度调优,且在运维与管理上也并不简单。

尽管无共享架构未能完全实现“无缝、易管理的可扩展性”的愿景,但它为 Snowflake 这类平台以云原生设计来应对云计算挑战奠定了道路。

Snowflake 的解决之道

为了解决自数据库诞生以来一直困扰其发展的可扩展性问题,Snowflake 团队选择制定一种不受既有设计局限的新路径。他们打造了一个原生为云而生的现代平台,利用云的独特能力来实现高并发、可扩展性与实时协作。

Snowflake 的创新云架构依然依赖于物理磁盘,但在逻辑层面对其进行整合,使集中式存储能够被各计算集群访问,同时避免并发瓶颈与数据复制开销。它吸收了共享磁盘与无共享两种范式所承诺的优点:将数据与计算负载彻底解耦,从而分别独立地按需提供与伸缩。

Snowflake 完全运行在云平台(亚马逊、微软与谷歌云)按虚拟化方式提供的资源之上。Snowflake 对与云厂商的交互进行透明处理,屏蔽底层虚拟资源细节,让客户通过统一的“三层架构”来管理自身数据。

Snowflake 的三层架构

Snowflake 的架构由三层组成:存储、计算与云服务。Snowflake 统一管理这三层,使得与底层云架构的交互对用户而言是透明的。

下图示意了 Snowflake 如何运行在云数据平台之上,将磁盘与虚拟计算集群分离,并同时管理一层独立的运行服务层(从而免去用户操心):

image.png

图 3.4 —— Snowflake 混合云架构

接下来先分别认识这三层,然后再说明它们如何协同,进而实现零拷贝克隆(zero-copy cloning)与时间回溯(Time Travel)等创新功能。

存储层(Storage layer)

存储层将数据物理地保存在承载该 Snowflake 账号的云服务商的磁盘上。数据加载进 Snowflake 后,会被压缩、加密,并在逻辑上组织为表、模式与数据库。用户定义数据库及其对象的逻辑层级,而底层的分区与存储由 Snowflake 负责。计费仅按实际存储的数据量收取,无需任何资源预配或容量规划。

后续章节将更详细介绍 Snowflake 如何管理与优化数据存储,以及其提供的备份与冗余选项。现在先来看计算与虚拟仓库(virtual warehouse)在 Snowflake 中如何工作。

计算层(Compute layer)

计算层(亦称处理层或虚拟仓库层)提供一组按虚拟化方式供给的 CPU 与临时内存资源,用以执行查询。这些集群被称为“仓库(warehouse)”,并以 T 恤尺码(XS 到 6XL 基准)来进行规格划分。通过“仓库”,Snowflake 用一个简洁的规则来抽象云端虚拟资源的消费:每提升一个仓库尺码,集群中的虚拟服务器数量翻倍,同时成本也翻倍。

将虚拟计算集群封装为以 T 恤尺码区分的“仓库”,屏蔽了底层云架构差异,确保无论 Snowflake 账号部署在哪个云平台上,都能以一致且简单的方式使用资源。由此,仓库的伸缩也更易追踪:纵向扩容(将仓库调至下一档尺码)会使集群服务器数量加倍;横向扩容则是在计算集群中新增同尺码的仓库以提升并发(可将“纵向扩”为“计算 ×2”,将“横向扩”为“计算 +1”来理解)。

服务层(Services layer)

在这种分层混合模型中,Snowflake 的服务层协调账号的全部活动,负责从安全、加密到元数据管理的一切。服务层涵盖查询解析与优化、数据共享与缓存等操作。从用户登录开始,服务层就贯穿其在仓库中的每一步操作。服务层所提供的大量省时自动化能力也体现在 Snowflake 的市场表述中:为用户承诺“近乎零运维”、低成本与卓越性能。

现在,让我们看看 Snowflake 的三层架构如何合而为一,为用户开启前所未有的可能。

Snowflake 的特性

凭借其革命性的云架构,Snowflake 持续推出超越“成名之初”的颠覆式性能增强,常常带给用户“愉快的惊喜”。以下并非穷尽清单,但涵盖了与数据建模密切相关、最令人兴奋的一些功能。

零拷贝克隆(Zero-copy cloning)

零拷贝克隆允许 Snowflake 用户在不进行物理复制的情况下克隆数据。由于无需搬移数据,克隆可瞬时完成——无论是克隆单张表还是整个数据库。被克隆对象起初是其源对象的“虚拟副本”,因此不产生存储费用。一旦在克隆或其源对象上发生数据变更,克隆便转化为物理对象并开始占用存储资源。

克隆非常适合用于创建系统备份与测试环境——几秒内完成过去要花上数天的工作。在对象层面,克隆也是在开发或调试时在不同环境间搬运数据的便捷方式。

另一项得益于创新列式存储技术(后续章节详解)的增强能力是 Time Travel(时间回溯)

时间回溯(Time Travel)

想象一下能“回到过去”:比如在你把以为是测试库的那张表误删到生产库之前。Snowflake 的 Time Travel 让这成为可能。

借助 Time Travel,用户可以查询或克隆某一历史时间点的数据,从而从误操作中恢复,或将当前状态与历史状态进行对比。Time Travel 是针对 Snowflake 对象的内置备份功能,因此会使用额外的存储,相较关闭该功能的对象会产生相应的存储成本。后续章节将介绍如何配置 Time Travel,以在成本与灵活性之间取得平衡。

接下来,我们把注意力从“表备份”转向一种完全不同的用表方式——来自 Snowflake 的最新创新之一。

混合型 Unistore 表(Hybrid Unistore tables)

数据仓库通常采用 OLAP(联机分析处理) 架构,以高效完成分析负载所需的大规模聚合与计算;而依赖单行操作或索引的场景在 OLTP(联机事务处理) 数据库中表现更佳。Snowflake 在 2022 年的 Snowflake Summit 上宣布了一种兼顾二者优势的新型表:Hybrid Unistore

Hybrid Unistore 表本质上是“一表两用”:在底层同时具备分析表与事务表,两者协同工作,为用户提供统一解决方案,兼获二者所长。与所有 Snowflake 对象一样,Hybrid 表也践行“近乎零运维”的承诺——由服务层自动将工作负载路由到最适合该任务的底层表。

Hybrid Unistore 表将在后续章节中单独展开。现在,让我们超越结构化数据,看看 Snowflake 的另一强项。

超越结构化数据(Beyond structured data)

Snowflake 以其在关系型表上的标杆级性能与处理半结构化数据的敏捷性闻名。甚至非结构化文件也可通过**外部表(external tables)**获得支持。用户可以在同一处对这些文件格式进行操作,方式与查询表一样熟悉且高效。

诸如日志、层次结构等以 JSON 或相近格式存储的半结构化文件,可加载至 Snowflake 并“像普通表一样”进行查询,几乎不牺牲性能。Snowflake 提供了丰富的函数库,既可直接处理半结构化记录,也可将其扁平化为结构化列。相关技术将在后续章节介绍。

非结构化数据同样受支持,其元数据可通过外部表进行查询——外部表是建立在外部 stage(存储区)之上的元数据对象。外部表为只读,但支持约束以满足关系建模需要。更多关于外部表的内容可参见 Snowflake 文档:docs.snowflake.com/en/user-gui…

这些强大功能再加上云的敏捷性,听起来成本一定高得惊人,对吧?事实上,由于零前期投入具竞争力的定价以及能够按需调整仓库规模、甚至完全暂停仓库,用户在 Snowflake 上的花费往往低于传统本地硬件的总成本。前提是:用户需要理解 Snowflake 的计费机制并有效进行成本管理

需要关注的成本

与一次性购买并在其生命周期内使用的本地数据库不同,Snowflake 采用按使用量计费的“可变支出(variable spend)”模式(常称为按量付费,pay-as-you-go)。可变支出使团队无需前期投入就能快速做原型或概念验证,并可通过监控与调整使用模式来控制成本。下面我们将拆解使用 Snowflake 平台涉及的各类成本,便于在后文做出更明智的设计决策。

先从在云中存储数据的成本谈起。

存储成本(Storage costs)

Snowflake 按平台内数据每日平均存量向客户计费。由于服务层会自动对数据进行压缩以优化存储,客户在不牺牲性能的前提下享受更低的存储成本。不过,计费不只计算原始数据;Time Travelfail-safe 备份(下一章详述)也在存储额度之内,需要一并考虑。

接下来谈谈处理数据的成本。

计算成本(Compute costs)

Snowflake 的计算消耗依据使用了多少个虚拟仓库运行时长以及仓库规格计费。处于激活状态的仓库按秒计费(最少 60 秒)。为简化仓库定价的计算,Snowflake 使用标准单位“credits(积分/点数) ”。

每点 credit 的确切费用取决于云服务商、托管区域以及 Snowflake 版本(如 Standard、Enterprise、Business Critical 或 VPS)。这些变量确定后,可以粗略将1 个 credit理解为1 小时 XS 规格仓库的费用。需要特别注意的是:只要仓库处于激活状态就会消耗 credit,与其是否正在执行查询无关。有效的成本策略应综合考虑何时启动与关闭仓库(可使用自动唤醒/自动挂起选项)以及特定负载所需的仓库规格

最后,还有运行与管理平台本身的成本。

服务成本(Service costs)

服务层负责访问控制、查询优化等关键操作,同时也会执行无服务器自动任务,如自动(重)聚簇、Snowpipe 流式装载与跨环境复制。许多由用户触发的动作(例如查询表元数据:count、sum、max,创建对象,或通过 show/describe 获取对象元数据)由服务层处理,无需激活仓库

服务层的成本在日常情况下包含在仓库 credit 中,只要其消耗不超过当日仓库消耗的 10% 。一旦超过 10% ,则按标准 credit 费率单独计费(即 XS 等效 1 credit/小时)。

在了解了 Snowflake 三层架构各自对应的成本之后,我们也应学习如何利用各类缓存来节省这些成本。

用“缓存”省“现金”(Saving cash by using cache)

在本地数据库中,低效操作会带来更长的执行时间;而在 Snowflake 的可变支出模型中,这些时间会直接转化为实际费用。除了编写高效 SQL,用户还应了解服务层与虚拟计算层中的各类缓存,以便在合适的场景复用预计算结果。对 Snowflake 缓存机制的深入理解,也将影响到建模与数据管道设计的决策。

先从服务层开始,熟悉它所管理并提供给用户的缓存。

服务层(Services layer)

服务层包含两种缓存:元数据缓存查询结果缓存

元数据缓存(Metadata cache)

服务层管理对象元数据,如结构、行数以及按列的去重值等。通过相关 SQL 函数或 Snowflake UI 查看这些元数据无需运行仓库,也不消耗 credit

Snowflake 在表级存储元数据(如表大小、创建日期),并在表的每个**微分区(micro-partition)**层面维护列统计信息(如 count、min/max、null 数)。

微分区(MICRO-PARTITIONS)
微分区是按列式组织的表内行分组。微分区使对大型表进行细粒度剪枝成为可能——一张大表可能包含数百万个微分区。随着对表执行 DML 操作,Snowflake 的服务层会自动创建与管理微分区。微分区与缓存将在后续章节详细说明;更多信息可参见官方文档 Micro-partitions & Data Clustering
docs.snowflake.com/en/user-gui…

服务层还会缓存对象定义与结构元数据,包括数据库对象的 DDL、列清单、数据类型(即便是视图)及约束。你可以通过 describeget_ddl 等 SQL 函数获取这些 DDL 细节,或直接查询 INFORMATION_SCHEMA。需要注意:查询 INFORMATION_SCHEMA 需要激活仓库并消耗 credit,而**describe/get_ddl 等由服务层直接处理**。

查询结果缓存(Query results cache)

Snowflake 账户中的所有查询结果会由服务层保留 24 小时,且可被其他用户复用。只要有查询命中缓存,24 小时计时会被重置,最长可持续 31 天,之后结果会被清除。除访问权限外,要想复用缓存结果,还需满足以下条件:

  • 查询在语法上等价
  • 未使用 current_date()动态函数
  • 底层表数据未发生变化
  • 用户对底层数据源拥有必要权限

与重新计算相比,命中结果缓存显然更优:几乎瞬时返回,且不消耗计算 credit。不同于传统数据库可能因内存紧张清空缓存,或因集群挂起而丢失缓存,Snowflake 的结果缓存会在上述条件满足前一直保留

理解结果缓存是高效使用 Snowflake 资源并做出设计选择的关键。但这并不是用户唯一可以利用的缓存。

仓库缓存(Warehouse cache)

虚拟仓库从集中式存储层(底层云的“远程磁盘”,如 AWS S3、Azure Blob、Google Cloud Storage)读取数据时,数据会被读入仓库缓存(基于 SSD 存储实现)。SSD 的容量取决于仓库规格

从 SSD 读取快于从远程磁盘读取,查询优化器(即服务层)会优先尝试使用缓存,无法命中时才回退到远程存储。不过,与服务层缓存不同,仓库缓存有两个重要差异:

  1. 缓存仅对该仓库可见
  2. 挂起仓库会清空其缓存

基于此,如果多个用户访问同一数据源,共享同一个仓库有利于命中缓存。但需要在保持仓库激活以保留缓存的 credit 成本每次从远程存储重读所需的 I/O 成本之间权衡。

当查询无法命中上述任一缓存时,Snowflake 必须访问存储层来完成操作。

存储层(Storage layer)

Snowflake 将数据存放在账户所在云平台的远程磁盘上。从远程磁盘读取不如从(SSD 上的)仓库缓存高效,更远不如直接获取预计算结果。存储层本身不提供缓存,当且仅当不存在可用缓存时才会作为最后途径被访问。

小结(Summary)

Snowflake 的云原生混合设计自底向上为云而建,实现了实时数据共享按需工作负载定尺,为用户提供了前所未有的灵活性,克服了以往数据库架构在可扩展性方面的诸多限制。它使得跨区域云厂商之间的安全数据共享几乎与同一账户下库与库之间一样迅捷。

通过理解 Snowflake 云架构的三层(存储、计算、服务),我们得以洞察其如何支撑 零拷贝克隆Time TravelHybrid UnistoreHTAP 表等强大能力,并打开了处理半结构化非结构化数据的大门。

本章还概述了这三层各自对应的成本,以及如何加以控制;同时讨论了 Snowflake 体系中多种缓存机制如何协同以节省成本、提升性能

凭借如此多的革命性特性,Snowflake 不把自己仅定位为一个数据库,而是一个数据云(Data Cloud) 。当你把它所使能的一切(例如数据与应用市场等服务)纳入考量,就不难理解为何需要新的术语来描述它。

既然我们已经一窥 Snowflake 的底层运作方式,接下来将更深入到数据库对象的内部机理。下一章我们将聚焦 Snowflake 的表:了解其各类类型与参数,以及可用作数据源并可纳入数据库设计建模的其他对象。掌握这些对象及其独特功能,将帮助你建模出可扩展且高效的数据库设计,充分发挥 Snowflake 的“武器库”。