Snowflake 弹性数据仓库
Translate by Jeff Zhao
Benoit Dageville, Thierry Cruanes, Marcin Zukowski, Vadim Antonov, Artin Avanes, Jon Bock, Jonathan Claybaugh, Daniel Engovatov, Martin Hentschel, Jiansheng Huang, Allison W. Lee, Ashish Motivala, Abdul Q. Munir, Steven Pelley, Peter Povinec, Greg Rahn, Spyridon Triantafyllis, Philipp Unterbrunner
Snowflake Computing
摘要
我们生活在分布式计算的黄金时代。公共云平台现在可以按需提供几乎无限的计算和存储资源。同时,软件即服务(SaaS)模型将企业级系统带给了以前由于成本和复杂性而无法负担的用户。 las,传统的数据仓库系统正在努力适应这种新环境。一方面,它们是为固定资源而设计的,因此无法利用云的弹性。另一方面,它们对复杂的ETL管道和物理调整的依赖性与云的新型半结构化数据和快速发展的工作负载对灵活性和更新性的要求不一致。
我们认为必须进行基本的重新设计。我们的任务是为云构建企业就绪的数据仓库解决方案。结果就是Snowflake弹性数据仓库,简称为“ Snowflake”。 Snowflake是一个多租户,事务性,安全,高度可扩展且具有弹性的系统,具有完整的SQL支持和针对半结构化和无模式数据的内置扩展。该系统在Amazon云中作为即付即用服务提供。用户将其数据上传到云,并可以使用熟悉的工具和界面立即进行管理和查询。该项目于2012年底开始实施,自2015年6月起就可以普遍使用Snowflake。如今,越来越多的小型和大型组织都在生产中使用Snowflake。该系统每天在多个PB的数据上运行数百万个查询。
在本文中,我们描述了Snowflake的设计及其新颖的多集群共享数据体系结构。本文重点介绍了Snowflake的一些关键功能:极高的弹性和可用性,半结构化和无模式的数据,时间旅行以及端到端安全性。最后总结了经验教训,并对正在进行的工作进行了展望。
分类和主题
信息系统[数据管理系统]: 数据库管理引擎
关键字
数据仓库,数据库即服务,多集群共享数据架构
1. 介绍
云的出现标志着已经从本地服务器上的软件交付和执行转向了由平台提供商(如Amazon,Google或Microsoft)托管的共享数据中心和软件即服务解决方案。 云的共享基础架构有望带来规模经济,极高的可扩展性和可用性,以及按需付费的费用模型,以适应不可预测的使用需求。 但是,只有在软件本身能够在作为云的商品资源池中灵活扩展的情况下,才能获得这些优势。 传统的数据仓库解决方案早于云。 它们被设计为在性能良好的小型静态群集上运行,从而使其在架构上不适合使用。
但是,不仅平台发生了变化。 数据也发生了变化。 过去的情况是,数据仓库中的大多数数据来自组织内的来源:事务处理系统,企业资源计划(ERP)应用程序,客户关系管理(CRM)应用程序等。 数据的结构,数量和速率都是相当可预测的并且众所周知。 但是,有了云,大量的数据份额迅速增长,而来的则来自不可控制的或外部来源:应用程序日志,Web应用程序,移动设备,社交媒体,传感器数据(物联网)。 除了不断增长的数据外,这些数据还经常以无模式,半结构化的格式到达[3]。 传统的数据仓库解决方案正在努力处理这些新数据。 这些解决方案取决于深层的ETL管道和物理调整,这些调整从根本上假设了来自内部大量数据的可预测的,移动缓慢的数据以及易于分类的数据。
为了应对这些缺陷,数据仓库社区的一部分转向了诸如Hadoop或Spark之类的“大数据”平台。 尽管这些是用于数据中心规模的处理任务必不可少的工具,并且开源社区继续在进行诸如Stinger Initiative之类的重大改进,但它们仍然缺乏很多已建立的数据仓库技术的效率和功能集。但最重要的是,它们需要大量的工程工作才能推出和使用。
我们认为,有大量的用例和工作负载可以从云的经济性,弹性和服务方面受益,但传统数据仓库技术或大数据平台都无法很好地满足这些需求。因此,我们决定为云构建一个全新的数据仓库系统。该系统称为Snowflake弹性数据仓库或 “Snowflake”。 与云数据管理领域中的许多其他系统相比,Snowflake不基于Hadoop,PostgreSQL等。处理引擎和大多数其他零件都是从头开始开发的。
Snowflake的主要功能如下。
纯软件即服务(SaaS)的体验 用户无需购买机器,雇用数据库管理员或安装软件。用户要么已经将其数据存储在云中,要么上传(或发送电子邮件)数据。 然后,他们可以立即使用Snowflake的图形界面或标准化界面(例如ODBC)来操纵和查询数据。与其他数据库即服务(DBaaS)产品相比,Snowflake的服务方面扩展到了整个用户体验。 用户没有调节旋钮,没有物理设计,也没有存储整理任务。
关系型 Snowflake对ANSI SQL和ACID事务提供了全面的支持。 大多数用户几乎不需要更改就可以迁移现有工作。
半结构化 Snowflake提供了用于遍历,访问和嵌套半结构化数据的内置函数和SQL扩展,并支持JSON和Avro等流行格式。 自动模式发现和列式存储使对无模式,半结构化数据的操作几乎与对普通关系数据一样快,而无需任何用户的努力。
可伸缩 可以独立且无缝地扩展存储和计算资源,而不会影响数据可用性或并发查询的性能。
高可用 Snowflake可以承受节点,群集甚至整个数据中心的故障。在软件或硬件升级期间没有停机时间。
持久化 Snowflake具有极高的持久化属性,并具有防止意外数据丢失的额外保护措施:克隆,断开和跨区域备份。
低成本 Snowflake具有很高的计算效率,并且所有表数据都已压缩。 用户只需为其实际使用的存储和计算资源付费。
安全 包括临时文件和网络流量在内的所有数据都是端到端加密的。从来没有用户数据暴露给云平台。此外,基于角色的访问控制使用户能够在SQL级别上执行细粒度的访问控制。
Snowflake当前在Amazon云(Amazon Web Services,AWS)上运行,但是我们将来可能会将其移植到其他云平台。 在撰写本文时,Snowflake每天在多个PB的数据上执行数百万个查询,为来自不同领域的快速增长的小型和大型组织提供服务。
概述
本文的结构如下。 第2节介绍了Snowflake背后的关键设计选择:存储和计算的分离。 第3节介绍了最终的多集群共享数据体系结构。 第4节重点介绍了差异化功能:连续可用性,半结构化和无模式数据,时间旅行和克隆以及端到端安全性。 第5节讨论相关工作。 第6节总结了本文,并总结了经验教训和对正在进行的工作的展望。
2. 存储与计算
无共享架构已成为高性能数据仓库中的主要系统架构,其主要原因有两个:可扩展性和商用硬件。在非共享架构中,每个查询处理器节点都有自己的本地磁盘。表在节点之间水平划分,每个节点仅负责其本地磁盘上的行。对于星型模式查询,此设计很好地扩展,因为将很小的(广播的)维表与大的(分区的)事实表连接在一起所需的带宽很小。而且,由于几乎没有共享数据结构或硬件资源的争用,因此不需要昂贵的自定义硬件。
在完全不共享的架构中,每个节点都具有相同的职责,并在相同的硬件上运行。这种方法产生了易于推理的精美软件,并具有所有不错的次要效果。纯无内容架构却有一个重要的缺点:它将计算资源和存储资源紧密耦合在一起,这在某些情况下会导致问题。
异构的工作负载 虽然硬件是同质的,但工作负载通常不是。 对于批量加载(高I/O带宽,轻量计算)而言,理想的系统配置不适合复杂查询(低I / O带宽,重计算量),反之亦然。 因此,硬件配置需要在平均利用率较低的情况下进行权衡。
节点变更 如果节点集发生更改;由于节点故障或由于用户选择调整系统大小而造成的; 需要重新整理大量数据。由于完全相同的节点负责数据改组和查询处理,因此可以观察到对性能的重大影响,从而限制了弹性和可用性。
在线升级 尽管可以使用复制在某种程度上减轻小型成员身份更改的影响,但是软件和硬件升级最终会影响系统中的每个节点。 原则上可以实现在线升级,以使一个接一个的节点升级而没有任何系统停机,但是由于所有事物都紧密耦合并且期望是同质的,因此这变得非常困难。
在本地环境中,通常可以容忍这些问题。工作负载可能是异构的,但如果只有一个很小的固定节点池在其中运行,则几乎无能为力。节点升级很少,节点故障和系统调整大小也很少。云中的情况非常不同。诸如Amazon EC2之类的平台具有许多不同的节点类型。充分利用它们只是将数据带入正确类型的节点的问题。同时,即使在相同类型的节点之间,节点故障也更加频繁,并且性能可能会发生巨大变化。因此,成员资格变更并非例外,这是常态。最后,有强烈的动机来实现在线升级和弹性扩展。在线升级大大缩短了软件开发周期并提高了可用性。弹性扩展进一步提高了可用性,并允许用户将资源消耗与他们的瞬时需求相匹配。
由于这些原因及其他原因,Snowflake将存储和计算分开。这两个方面由两个松耦合,独立可伸缩的服务处理。计算是通过Snowflake的(专有)无共享引擎提供的。存储是通过Amazon S3提供的,尽管原则上任何类型的Blob存储都足够(Azure Blob存储,Google Cloud Storage)。为了减少计算节点和存储节点之间的网络流量,每个计算节点都会在本地磁盘上缓存一些表数据。
该解决方案的另一个好处是,本地磁盘空间不花在复制整个基础数据上,因为整个基础数据可能很大,而且大多是冷的(很少访问)。而是将本地磁盘专门用于临时数据和缓存,这两者都是热的(建议使用高性能存储设备,例如SSD)。因此,一旦缓存变暖,性能将接近甚至超过纯无共享系统的性能。我们称这种新颖的架构为多集群共享数据架构。
3. 架构
Snowflake旨在提供企业级服务,除了提供高度的可用性和互操作性外,企业级就绪还意味着高可用性。为此,Snowflake是一种面向服务的体系结构,由高度容错和可独立扩展的服务组成,这些服务通过RESTful接口进行通信并分为三个体系结构层:
数据存储 存储层使用Amazon S3存储数据表和查询结果
虚拟数仓 系统的“肌肉”。该层处理称为虚拟仓库的虚拟机弹性集群中的查询执行。
云服务 系统的“大脑”。该层是服务的集合,这些服务管理虚拟仓库,查询,事务以及所有相关的元数据:数据库架构,访问控制信息,加密密钥,使用情况统计信息等等。
图1展示了Snowflake的三个体系结构层及其主要组成部分。
3.1 数据存储
Amazon Web Services(AWS)已被选为Snowflake的初始平台,原因有两个。首先,AWS是云平台市场上最成熟的产品。第二(与第一点有关),AWS提供了最大的潜在用户池。然后,下一个选择是在使用S3或基于HDFS或类似产品开发我们自己的存储服务之间[46]。我们花了一些时间对S3进行了试验,发现尽管其性能可能有所不同,但其可用性,高可用性和强大的耐用性保证却无与伦比。因此,我们没有开发自己的存储服务,而是决定将精力投入到Virtual Warehouses层中的本地缓存和偏斜弹性技术上。
与本地存储相比,S3自然具有更高的访问延迟,并且与每个单个I / O请求相关的CPU开销也更高,尤其是在使用HTTPS连接的情况下。但更重要的是,S3是具有相对简单的基于HTTP(S)的PUT / GET / DELETE接口的Blob存储。对象(即文件)只能完全(过度)写入。甚至不可能将数据附加到文件末尾。实际上,文件的确切大小需要在PUT请求中预先声明。但是,S3确实支持对文件部分(范围)的GET请求。
这些属性对Snowflake的表格文件格式和并发控制方案有很大的影响(请参阅第3.3.2节)。表被水平划分为大的,不可变的文件,这些文件等效于传统数据库系统中的块或页面。在每个文件中,每个属性或列的值都被分组在一起并进行严重压缩,这是文献中称为PAX或混合列式的众所周知的方案[2]。每个表文件都有一个标头,其中除了其他元数据外,还包含文件中每一列的偏移量。由于S3允许对文件的某些部分进行GET请求,因此查询仅需要下载文件头和它们感兴趣的那些列。
Snowflake不仅将S3用于表数据。一旦本地磁盘空间用完以及大型查询结果,它还使用S3存储由查询运算符(例如,大规模联接)生成的临时数据。将临时数据溢出到S3,系统可以计算任意大的查询,而不会出现内存不足或磁盘错误的情况。将查询结果存储在S3中可以启用新形式的客户端交互,并简化查询处理,因为它消除了对传统数据库系统中服务器端游标的需求。
诸如目录对象之类的元数据由哪个S3文件,统计信息,锁,事务日志等组成,该表存储在可伸缩的事务性键值存储中,该存储是Cloud Services层的一部分。
图1:多集群共享数据架构
3.2 虚拟数仓
虚拟仓库层由EC2实例群集组成。 每个此类群集通过称为虚拟仓库(VW)的抽象形式呈现给其单个用户。 组成VW的各个EC2实例称为工作程序节点。 用户永远不会直接与工作程序节点进行交互。 实际上,用户不知道或不在乎哪个或多少个工作节点组成了虚拟数仓。虚拟数仓则采用抽象的“ T恤尺寸”,范围从XS到XXL。 这种抽象使我们能够独立于底层云平台来发展服务和定价。
3.2.1 弹性和隔离
虚拟数仓是纯计算资源。 它们可以根据需要随时创建,销毁或调整大小。 创建或销毁虚拟机不会影响数据库的状态。 完全合法(鼓励)用户在没有查询的情况下关闭其所有虚拟数仓。 这种弹性使用户可以将其计算资源动态地与使用需求相匹配,而与数据量无关。
每个单独的查询仅在一个虚拟数仓上运行。 不会在虚拟数仓之间共享工作节点,从而使查询具有强大的性能隔离性。 (话虽这么说,我们认识到共享工作节点是未来工作的重要领域,因为在性能隔离不是大问题的用例中,这将提高利用率并降低成本。)
提交新查询时,相应虚拟数仓中的每个工作程序节点(如果优化程序检测到小的查询,则为节点的子集)会产生一个新的工作程序进程。 每个工作进程仅在其查询期间有效。 辅助进程本身(即使是更新语句的一部分)也不会引起外部可见的影响,因为表文件是不可变的,请参见3.3.2节。 因此,工人的故障很容易得到遏制,并且可以通过重试常规解决。 不过,Snowflake当前不执行部分重试,因此,非常大且长期运行的查询是一个值得关注的领域,并且是未来的工作。
每个用户可以在任何给定时间运行多个虚拟数仓,每个虚拟数仓依次运行多个并发查询。每个虚拟数仓都可以访问相同的共享表,而无需物理复制数据。
共享的无限存储意味着用户可以共享和集成所有数据,这是数据仓库的核心原理之一。同时,用户受益于私有计算资源,避免了不同工作负载和组织单位的干扰,这是数据集市的原因之一。这种弹性和隔离性使一些新颖的使用策略成为可能。 Snowflake用户通常有多个虚拟数仓来查询来自不同组织单位的查询,这些查询通常连续运行,并定期启动按需虚拟数仓,例如用于批量加载。
与弹性有关的另一个重要观察结果是,通常可以以大致相同的价格获得更好的性能。例如,在具有4个节点的系统上花费15个小时进行数据加载,而在32个节点上可能仅花费2个小时。由于一个人需要支付计算时间,因此总成本非常相似,但用户体验却大不相同。因此,我们认为,大众弹性是Snowflake体系结构的最大好处和与众不同之处,它表明需要一种新颖的设计才能利用云的独特功能。
3.2.2 本地缓存和文件窃取
每个工作节点在本地磁盘上维护表数据的缓存。缓存是表文件的集合,即该节点过去已访问过的S3对象。确切地说,由于查询仅下载所需的列,因此缓存保留文件头和文件的各个列。
高速缓存在工作程序节点的持续时间内生存,并在并发和后续工作程序进程(即查询)之间共享。它只是看到文件和列请求的流,并且遵循简单的最近最少使用(LRU)替换策略,而忽略了单个查询。这个简单的方案出奇地好,但是我们将来可能会对其进行改进,以更好地匹配不同的工作负载。
为了提高命中率并避免在VW的工作节点上冗余存储单个表文件,查询优化器使用对表文件名的一致哈希将输入文件集分配给工作节点[31]。因此,访问同一表文件的后续查询或并发查询将在同一工作节点上执行此操作。
Snowflake中一致的哈希是懒惰的。当工作节点的集合发生更改时(由于节点故障或VW调整大小),不会立即对数据进行重新排序。相反,Snowflake依靠LRU替换策略来最终替换缓存内容。该解决方案分摊了在多个查询上替换缓存内容的成本,因此,与急需的缓存或纯无共享系统相比,可用性要好得多,后者或需要立即在节点上随机整理大量表数据的纯无共享系统。由于没有“降级”模式,因此也简化了系统。
除缓存外,偏斜处理在云数据仓库中尤其重要。由于虚拟化问题或网络争用,某些节点的执行速度可能比其他节点慢得多。在其他地方,Snowflake在扫描级别处理此问题。每当工作进程完成对输入文件集的扫描时,它都会向其对等方请求其他文件,这种技术称为文件窃取。如果对等方发现当这样的请求到达时其输入文件集中还有许多文件,它将通过在当前查询的持续时间和范围内转移一个剩余文件的所有权来回答该请求。然后,请求者直接从S3而不是从其对等方下载文件。这种设计通过在散乱的节点上增加额外的负载来确保文件窃取不会使情况变得更糟。
3.2.3 执行引擎
如果另一个系统可以同时使用10个这样的节点来执行查询,那么在1,000个以上的节点上执行查询几乎没有任何价值。 因此,尽管可伸缩性至关重要,但每个节点的效率同样重要。 我们希望为用户提供市场上任何数据库即服务产品的最佳性价比,因此,我们决定实施自己的最先进的SQL执行引擎。 我们构建的引擎是柱状,矢量化和基于推送的。
柱状 由于更有效地利用CPU缓存和SIMD指令,并且有更多的(轻量级)压缩机会,因此对于分析工作负载,通常认为行和执行优于行存储和执行。
向量化 执行是指,与MapReduce例如[42]相比,Snowflake避免了中间结果的实现。 而是以流水线方式处理数据,以列格式分批处理几千行。 由VectorWise(最初为MonetDB / X100 [15])率先采用的这种方法节省了I / O,并大大提高了缓存效率。
基于推送 执行是指关系运算符将其结果推送给下游运算符,而不是等待这些运算符提取数据的事实(经典的火山式模型[27])。 基于推的执行提高了缓存效率,因为它消除了紧密循环中的控制流逻辑[41]。 它还使Snowflake可以有效地处理DAG形的计划,而不仅仅是树木,从而为共享和流水化中间结果创造了更多的机会。
同时,Snowflake中不存在传统查询处理中的许多开销来源。 值得注意的是,在执行期间不需要事务管理。 就引擎而言,查询是针对一组固定的不可变文件执行的。 另外,没有缓冲池。 大多数查询会扫描大量数据。 在这里,使用内存进行表缓冲与操作是不平衡的。 但是,Snowflake确实允许所有主要运算符(连接,分组依据,排序)溢出到磁盘上,并在耗尽主内存时进行递归。 我们发现,一个纯粹的主内存引擎虽然更精简甚至更快,但对于处理所有有趣的工作负载却过于严格。 分析工作负载可以具有极大的联接或聚合功能。
3.3 云服务
虚拟仓库是临时的,特定于用户的资源。 相反,云服务层是大量的多租户。 该层的每个服务(访问控制,查询优化器,事务管理器等)都是长期存在的,并在许多用户之间共享。 多租户可提高利用率并减少管理开销,与传统架构相比,传统架构中的每个用户都拥有完全私有的系统,从而实现了更好的规模经济。 复制每个服务以获得高可用性和可伸缩性。 因此,尽管某些正在运行的查询可能会失败(并透明地重新执行),但单个服务节点的失败不会导致数据丢失或可用性降低。
3.3.1 查询管理和优化
用户发出的所有查询都通过Cloud Services层。这里,处理了查询生命周期的所有早期阶段:解析,对象解析,访问控制和计划优化。
Snowflake的查询优化器遵循典型的Cascadesstyle方法[28],并采用自上而下的基于成本的优化方法。用于优化的所有统计信息将在数据加载和更新时自动维护。由于Snowflake不使用索引(请参阅第3.3.3节),因此计划搜索空间比某些其他系统小。通过将许多决策推迟到执行时间(例如,联接的数据分发类型),进一步减少了计划空间。这种设计减少了优化器做出的错误决定的数量,从而以降低峰值性能为代价提高了鲁棒性。它还使系统更易于使用(性能变得更可预测),这与Snowflake对服务体验的总体关注相一致。
优化器完成后,将生成的执行计划分发到查询的所有工作节点。执行查询时,Cloud Services会持续跟踪查询的状态以收集性能计数器并检测节点故障。存储所有查询信息和统计信息,以进行审计和性能分析。用户可以通过Snowflake图形用户界面监视和分析过去和正在进行的查询。
3.3.2 并发控制
如前所述,并发控制完全由Cloud Services层处理。 Snowflake是专为分析工作负载而设计的,这些工作负载通常由大量读取,批量或点滴插入以及批量更新控制。像在此工作负载空间中的大多数系统一样,我们决定通过快照隔离(SI)[17]实现ACID事务。
在SI下,从事务开始时,事务的所有读取都将看到数据库的一致快照。按照惯例,SI是在多版本并发控制(MVCC)之上实现的,这意味着每个更改的数据库对象的副本都会保留一段时间。
鉴于表文件是不可变的,因此MVCC是自然的选择,这是使用S3进行存储的直接结果。只能通过用包含更改的其他文件替换文件来进行更改。随之而来的是,对表的写操作(插入,更新,删除,合并)通过添加和删除相对于先前表版本的整个文件来产生表的较新版本。在元数据中(在全局键值存储中)以允许非常高效地计算属于特定表版本的文件集的形式跟踪文件的添加和删除。
除了用于SI外,Snowflake还使用这些快照来实现时间旅行和数据库对象的高效克隆,有关详细信息,请参见第4.4节。
3.3.3 修剪
仅将访问限制为与给定查询相关的数据是查询处理的最重要方面之一。 从历史上看,数据库中的数据访问是通过使用B +树或类似数据结构形式的索引来限制的。 尽管这种方法对事务处理非常有效,但对于Snowflake之类的系统却提出了多个问题。 首先,它严重依赖于随机访问,由于存储介质(S3)和数据格式(压缩文件),这都是一个问题。 其次,维护索引会显着增加数据量和数据加载时间。 最后,用户需要显式创建索引,这与Snowflake的纯服务方法大相径庭。 即使在调整顾问的帮助下,维护索引也可能是一个复杂,昂贵且有风险的过程。
最近,另一种替代技术已在大规模数据处理中获得普及:基于最小-最大的修剪,也称为小型物化聚集体[38],区域图[29]和数据跳过[49]。在此,系统维护给定数据块(记录集,文件,块等)的数据分布信息,尤其是该块内的最小值和最大值。根据查询谓词,这些值可用于确定给定查询可能不需要给定数据块。例如,假设文件f1和f2在x列中分别包含值3..5和4..6。然后,如果查询的谓词WHERE x >= 6,我们知道仅需要访问f2。与传统索引不同,此元数据通常比实际数据小几个数量级,从而导致较小的存储开销和快速访问。
修剪完全符合Snowflake的设计原则:它不依赖于用户输入;它不依赖于用户输入。它可以很好地扩展;而且易于维护。而且,它对于大块数据的顺序访问非常有效,并且在加载,查询优化和查询执行时间上几乎没有增加开销。
Snowflake会为每个单独的表文件保留与修剪相关的元数据。 元数据不仅覆盖普通的关系列,而且还覆盖了半结构化数据内部的一系列自动检测列,请参见第4.3.2节。 在优化期间,针对查询谓词检查元数据,以减少(“修剪”)用于查询执行的输入文件集。 优化器不仅对简单的基值谓词执行修剪,而且还对更复杂的表达式(例如WEEKDAY(orderdate)IN(6,7))执行修剪。
除此静态修剪外,Snowflake在执行期间还会执行动态修剪。 例如,作为哈希联接处理的一部分,Snowflake收集有关构建侧记录中联接键分布的统计信息。 然后,此信息将被推送到探针侧,并用于过滤并可能跳过探针侧的整个文件。 这是除其他众所周知的技术(例如,bloom joins)之外的另一种方法[40]。
4. 亮点功能
Snowflake提供了关系数据仓库所期望的许多功能:全面的SQL支持,ACID事务,标准接口,稳定性和安全性,客户支持,当然还有强大的性能和可伸缩性。 此外,它还引入了许多其他有价值的功能,这些功能在相关系统中很少见或从未见过。 本节介绍了其中一些我们认为是技术上与众不同的功能。
4.1 纯软件即服务的体验
Snowflake支持标准数据库接口(JDBC,ODBC,Python PEP-0249),并且可以与Tableau,Informatica或Looker等各种第三方工具和服务一起使用。但是,它也提供了仅使用Web浏览器即可与系统进行交互的可能性。 Web用户界面看似微不足道,但很快就证明了自己是关键的区分因素。 Web UI使从任何位置和环境访问Snowflake变得非常容易,从而大大降低了引导和使用系统的复杂性。有了大量数据,它就使许多用户只需将Snowflake指向他们的数据并查询即可,而无需下载任何软件。
可以预料,UI不仅允许执行SQL操作,而且还提供对数据库目录,用户和系统管理,监视,使用信息等的访问。我们不断扩展UI功能,致力于在线协作,用户反馈和支持等方面。
但是,我们对易用性和服务体验的关注不仅仅停留在用户界面上。它扩展到系统体系结构的各个方面。没有故障模式,没有调节旋钮,没有物理设计,没有存储整理任务。这全都与数据和查询有关。
4.2 持续可用
过去,数据仓库解决方案是隐藏的后端系统,与世界上大多数地区隔离。 在这样的环境中,计划内(软件升级或管理任务)和计划外(故障)的停机时间通常不会对运营产生重大影响。 但是,随着数据分析对于越来越多的业务任务变得至关重要,连续可用性成为任何数据仓库的重要要求。 这种趋势反映了对现代SaaS系统的期望,其中大多数都是始终在线的,面向客户的应用程序,没有(计划的)停机时间。
Snowflake提供满足这些期望的持续可用性。 这方面的两个主要技术功能是故障恢复能力和在线升级。
4.2.1 容错能力
Snowflake可以容忍架构各个级别上的单个节点和相关节点故障,如图2所示。如今,Snowflake的数据存储层是S3,该数据跨多个数据中心复制,在亚马逊术语中称为“可用区”或AZ。跨可用区的复制使S3可以处理全部可用区故障,并保证99.99%的数据可用性和99.999999999%的持久性。与S3的架构相匹配,Snowflake的元数据存储也分布在多个可用区中,并在多个可用区中复制。如果一个节点发生故障,其他节点可以接管活动,而对最终用户没有太大影响。云服务层的其余服务由多个可用区中的无状态节点组成,负载平衡器在它们之间分配用户请求。随之而来的是,单个节点故障甚至整个可用区故障都不会对整个系统造成影响,甚至可能导致对当前连接到故障节点的用户的某些查询失败。这些用户将被重定向到其他节点以进行下一个查询。
图2:Snowflake的多数据中心实例
相反,虚拟仓库(VW)不在跨可用区分布。此选择是出于性能原因。高网络吞吐量对于分布式查询执行至关重要,并且在同一可用区域内,网络吞吐量显着更高。如果在查询执行期间工作节点之一失败,则查询会失败,但是会透明地重新执行,可以立即替换节点,也可以临时减少节点数。为了加速节点更换,Snowflake维护了一个小的备用节点池。 (这些节点也用于快速的大众配置。)
但是,如果整个可用区都不可用,则在该可用区的给定VW上运行的所有查询都将失败,并且用户需要在其他可用区中主动重新配置该VW。由于全可用区故障确实是灾难性的,并且是极为罕见的事件,因此我们今天接受这种部分系统不可用的情况,但希望将来能解决。
4.2.2 在线升级
Snowflake不仅在发生故障时而且在软件升级期间都可以提供连续的可用性。该系统旨在允许同时部署各种服务的多个版本,包括Cloud Services组件和虚拟仓库。所有服务实际上都是无状态的,这使之成为可能。所有硬状态都保存在事务键值存储中,并通过负责元数据版本控制和架构演变的映射层进行访问。每当我们更改元数据架构时,我们都将确保与先前版本的向后兼容性。
为了执行软件升级,Snowflake首先将服务的新版本与以前的版本一起部署。然后,将用户帐户逐步切换到新版本,每时每刻,由相应用户发出的所有新查询都将定向到新版本。允许对先前版本执行的所有查询运行完毕。一旦所有查询和用户使用完先前的版本,该版本的所有服务都将终止并退役。
图3显示了正在进行的升级过程的快照。 Snowflake有两个版本并排运行,版本1(浅色)和版本2(深色)。一个单一版本的Cloud Services有两个版本,可控制两个虚拟仓库(VW),每个虚拟仓库都有两个版本。负载平衡器将传入呼叫定向到适当版本的Cloud Services。一个版本的云服务仅与匹配版本的大众对话。 如前所述,两个版本的Cloud Services共享相同的元数据存储。而且,不同版本的VW可以共享相同的工作程序节点及其各自的缓存。因此,升级后无需重新填充缓存。整个过程对用户是透明的,不会造成停机时间或性能下降。
图3:在线升级
在线升级也对我们的开发速度以及我们如何处理Snowflake的关键错误产生了巨大影响。在撰写本文时,我们每周升级一次所有服务。这意味着我们每周都会发布功能和改进。为确保升级过程顺利进行,升级和降级均在Snowflake的特殊生产前化身中进行了持续测试。在极少数情况下,我们发现生产版本中存在严重错误(不一定在升级过程中),我们可以非常迅速地降级到以前的版本,或者实施修补程序并执行计划外的升级。这个过程并不像听起来那样可怕,因为我们不断地测试和练习升级/降级机制。它是高度自动化的,并且在这一点上得到了强化。
4.3 半结构化和非结构化数据
Snowflake用三种类型的半结构化数据扩展了标准SQL类型系统:VARIANT,ARRAY和OBJECT。 VARIANT类型的值可以存储任何本机SQL类型的值(DATE,VARCHAR等),以及值的可变长度ARRAY和类似JavaScript的对象,它们从字符串映射到VARIANT值。后者在文献中也称为文档,从而产生了文档存储的概念(MongoDB [39],Couchbase [23])。
ARRAY和OBJECT只是VARIANT类型的限制。内部表示是相同的:自我描述的紧凑二进制序列化,支持快速键值查找以及有效的类型测试,比较和哈希。因此,像任何其他列一样,VARIANT列可用作联接键,分组键和排序键。
VARIANT类型允许Snowflake以ELT(提取负载转换)方式使用,而不是传统的ETL(提取负载转换)方式使用。无需指定文档架构或在负载上执行转换。用户可以将其输入数据从JSON,Avro或XML格式直接加载到VARIANT列中; Snowflake处理解析和类型推断(请参阅第4.3.3节)。这种方法在文献中被恰当地称为“稍后模式”,它通过将信息生产者与信息消费者和任何中间人脱钩而实现了模式演变。相反,常规ETL管道中数据模式的任何更改都需要组织中多个部门之间的协调,这可能需要几个月的时间才能执行。
ELT和Snowflake的另一个优点是,以后,如果需要进行转换,可以使用并行SQL数据库的全部功能来执行,包括连接,排序,聚合,复杂谓词等操作,这些操作通常不存在或传统ETL工具链效率低下。在这一点上,Snowflake还具有具有完整JavaScript语法并与VARIANT数据类型集成的过程用户定义函数(UDF)。对过程UDF的支持进一步增加了可推入Snowflake的ETL任务的数量。
4.3.1 关系型操作
对文档最重要的操作是通过字段名称(对于对象)或通过偏移量(对于阵列)提取数据元素。 Snowflake提供功能性SQL表示法和类似于JavaScript的路径语法的提取操作。内部编码使提取非常有效。子元素只是父元素内部的指针;无需复制。提取后通常将结果VARIANT值转换为标准SQL类型。同样,编码使这些转换非常有效。 第二个常见操作是拉平,即将嵌套文档旋转为多行。 Snowflake使用SQL侧面视图表示展平操作。这种扁平化可以是递归的,从而可以将文档的层次结构完全转换为适合SQL处理的关系表。与扁平化相反的操作是聚合。为此,Snowflake引入了一些新的聚合和分析功能,例如ARRAY_AGG和OBJECT_AGG。
4.3.2 柱状储存和加工
对于半结构化数据,使用序列化(二进制)表示形式是将半结构化数据集成到关系数据库中的常规设计选择。不幸的是,按行表示使此类数据的存储和处理效率不及列式关系数据—这是将半结构化数据转换为纯关系数据的常见原因。
Cloudera Impala [21](使用Parquet [10])和Google Dremel [34]证明了半结构化数据的列式存储是可能且有益的。但是,Impala和Dremel(及其外部化BigQuery [44])要求用户提供用于列存储的完整表架构。为了实现无模式序列化表示的灵活性和列关系数据库的性能,Snowflake引入了一种新颖的自动方法来进行类型推断和列存储。
如第3.1节所述,Snowflake以混合列格式存储数据。当存储半结构化数据时,系统会自动对单个表文件中的文档集合进行统计分析,以执行自动类型推断并确定哪些(类型化)路径是常见的。然后,使用与本机关系数据相同的压缩列格式,将相应的列从文档中删除并单独存储。对于这些列,Snowflake甚至会计算出实体化聚合,以供修剪(请参阅第3.3.3节),以及纯关系数据。
在扫描期间,可以将各个列重新组装为VARIANT类型的单个列。但是,大多数查询只对原始文档的列的子集感兴趣。在这些情况下,Snowflake将投影和转换表达式向下推入扫描运算符,以便仅访问必要的列并将其直接转换为目标SQL类型。
上面描述的优化是针对每个表文件独立执行的,即使在架构演变下也可以进行有效的存储和提取。但是,它确实在查询优化(尤其是修剪)方面提出了挑战。假设查询具有路径表达式的谓词,并且我们想使用修剪来限制要扫描的文件集。路径和相应的列可能会出现在大多数文件中,但只有足够频繁才能保证某些文件中的元数据。保守的解决方案是简单地扫描所有没有合适元数据的文件。 Snowflake通过计算文档中存在的所有路径(不是值!)的Bloom过滤器来改进此解决方案。这些Bloom筛选器与其他文件元数据一起保存,并在修剪过程中由查询优化器进行探测。可以安全地跳过不包含给定查询所需路径的表文件。
4.3.3 乐观转换
由于某些本机SQL类型(尤其是日期/时间值)以JSON或XML之类的常见外部格式表示为字符串,因此需要在写入时(在插入或更新期间)或在写入时将这些值从字符串转换为其实际类型。读取时间(查询期间)。如果没有类型化的架构或等效的提示,则这些字符串转换需要在读取时执行,这在以读取为主的工作负载中,效率不如在写入期间执行一次转换。未类型化数据的另一个问题是缺少适合的修剪元数据,这在日期情况下尤其重要。 (分析工作负载通常在日期列上有范围谓词。)
但是在写入时应用自动转换可能会丢失信息。例如,包含数字产品标识符的字段实际上可能不是数字,而是带有重要的前导零的字符串。同样,看起来像日期的确可能是文本消息的内容。 Snowflake通过执行乐观的数据转换并在单独的列中保留转换结果和原始字符串(除非存在完全可逆转换)来解决该问题。如果以后查询需要原始字符串,则很容易检索或重建它。由于未加载和访问未使用的列,因此任何双重存储对查询性能的影响都将降至最低。
4.3.4 性能
为了评估柱状存储,乐观转换以及对半结构化数据的修剪对查询性能的综合影响,我们使用TPC-H-like4数据和查询进行了一组实验。
我们创建了两种类型的数据库模式。首先,是传统的关系式TPC-H模式。其次,“无模式”数据库模式,其中每个表都由一个类型为VARIANT的列组成。然后,我们生成了群集的(分类的)SF100和SF1000数据集(分别为100 GB和1 TB),以纯JSON格式(即,日期变成了字符串)存储了数据集,并使用关系和模式将数据加载到Snowflake中-less数据库模式。没有向系统提供有关无模式数据的字段,类型和集群的任何形式的提示,并且没有进行其他调整。然后,我们在无模式数据库的顶部定义了一些视图,以便能够对所有四个数据库运行完全相同的TPC-H查询集。 (在撰写本文时,Snowflake并未将视图用于类型推断或其他优化,因此,这纯粹是一种语法上的便利。)
最后,我们使用中等标准仓库针对四个数据库运行了所有22个TPC-H查询。图4显示了结果。在温暖的缓存下,通过三轮运行获得了数字。标准误差不明显,因此从结果中将其省略。
可以看出,除两个查询(SF1000上的Q9和Q17)外,所有其他内容的无模式存储和查询处理开销约为10%。对于这两个查询,我们确定减速的原因是次优联接顺序,这是由不同值估计中的已知错误引起的。我们将继续改进半结构化数据的元数据收集和查询优化。
总而言之,对具有相对稳定和简单模式的半结构化数据(即在实践中发现的大多数机器生成的数据)的查询性能几乎与传统关系数据的性能相当,享受了列式存储的所有优势,列执行和修剪-无需用户费力。
4.4 时间消耗及复制
在3.3.2节中,我们讨论了Snowflake如何在多版本并发控制(MVCC)之上实现快照隔离(SI)。 通过添加和删除整个文件,对表执行写操作(插入,更新,删除,合并)会生成该表的较新版本。
当文件被新版本删除时,它们会保留一段可配置的持续时间(当前最多90天)。 文件保留功能使Snowflake可以非常有效地读取表的早期版本。 也就是说,在数据库上执行时间旅行。 用户可以使用方便的AT或BEFORE语法从SQL访问此功能。 相对于当前时间或相对于先前的语句(ID引用),时间戳可以是绝对的。
SELECT * FROM my_table AT(TIMESTAMP => 'Mon, 01 May 2015 16:20:00 -0700'::timestamp);
SELECT * FROM my_table AT(OFFSET => -60*5); -- 5 min ago
SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
一个人甚至可以在单个查询中访问同一表的不同版本。
SELECT new.key, new.value, old.value FROM my_table new JOIN my_table AT(OFFSET => -86400) old -- 1 day ago
ON new.key = old.key WHERE new.value <> old.value;
基于相同的基础元数据,Snowflake引入了UNDROP关键字以快速恢复意外删除的表,模式或整个数据库。
DROP DATABASE important_db; -- whoops!
UNDROP DATABASE important_db;
Snowflake还实现了我们称为克隆的功能,该功能通过新关键字CLONE表示。 克隆表可以快速创建具有相同定义和内容的新表,而无需制作表文件的物理副本。 克隆操作只是复制源表的元数据。 克隆后,两个表都引用相同的文件集,但是此后两个表都可以独立修改。 克隆功能还支持整个架构或数据库,从而可以实现非常高效的快照。 在进行大量更新之前或执行冗长的探索性数据分析时,快照是一种很好的做法。 CLONE关键字甚至可以与AT和BEFORE组合使用,从而可以在事后创建此类快照。
CREATE DATABASE recovered_db CLONE important_db BEFORE( STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
4.5 安全性
Snowflake旨在保护用户数据免受包括云平台在内的系统级别的攻击。为此,Snowflake实现了双因素身份验证(客户端)加密数据导入和导出、安全数据传输和存储以及基于角色的数据库对象访问控制(RBAC)。在任何时候,数据在通过网络发送之前以及在写入本地磁盘或共享存储(S3)之前都是加密的。因此,Snowflake提供了完整的端到端数据加密和安全性。
4.5.1 密钥层次结构
Snowflake使用了加密性强的AES 256位加密,其分层密钥模型植根于AWS CloudHSM。加密密钥会key rotation并rekeying(“重新加密”),以确保密钥完成整个NIST 800-57加密密钥管理生命周期。加密和密钥管理对用户完全透明,不需要用户配置或管理。
Snowflake秘钥层次结构(如图5所示)有四个级别:根秘钥、帐户秘钥、表秘钥和文件秘钥。每层(父)密钥加密,即将下面的(子)密钥层包装起来。每个帐户键对应一个用户帐户,每个表秘钥对应一个数据库表,每个文件秘钥对应一个表文件。
分层密钥模型是很好的安全实践,因为它们限制了每个密钥保护的数据量。如图5中的框所示,每一层都缩小了它下面的键的范围。Snowflake的分层密钥模型确保了多租户体系结构中用户数据的隔离,因为每个用户帐户都有一个单独的帐户密钥。
图5:加密密钥层次结构
4.5.2 密钥的生命周期
每个密钥保证了保护的数据量,Snowflake还保证了密钥可用时间。加密密钥经历四个阶段:(1)操作前创建阶段,(2)操作阶段,其中密钥用于加密(发起者使用期)和解密(接收者使用期),(3)操作后阶段,其中密钥不再使用,(4)销毁阶段。阶段1、3和4的实现非常简单。第2阶段需要限制发起者和接收者的使用期限。只有当一个密钥不再加密任何所需的数据时,它才能转到第3和第4阶段。Snowflake使用key rotation限制发起者的使用周期,使用rekeying限制收件人的使用周期。
key rotation 以固定的间隔(例如,一个月)创建秘钥的新版本。在每个这样的间隔之后,将创建密钥的新版本,并且密钥的先前版本将“失效”。失效的版本仍然可用,但仅用于解密数据。在密钥层次结构中包装新的子密钥或写入表时,仅使用密钥的最新活动版本来加密数据。
rekeying 是用新密钥重新加密旧数据的过程。在特定的时间间隔(例如,一年)之后,使用失效密钥加密的数据将使用活动密钥重新加密。rekeying和key rotation不存在冲突。key rotation可确保密钥从活动状态(发起方使用)转移到失效状态(接收方使用),rekeying可确保密钥从失效状态转移到销毁状态。
图6显示了单个表秘钥的生命周期。假设每个月轮换一次秘钥,每年重新设置一次数据秘钥。表文件1和表文件2是在2014年4月创建的,使用键1版本1(k1v1)。2014年5月,将key1旋转为版本2(k1v2),并使用k1v2创建表文件3。2014年6月,key1被旋转到版本3(k1v3),并创建了另外两个表文件。2014年6月之后,不再对表进行插入或更新。2015年4月,k1v1已满一年,需要销毁。将创建一个新密钥,即密钥2版本1(k2v1),并使用k2v1重新设置与k1v1关联的所有文件的密钥。2015年5月,k1v2也发生了同样的情况,表文件3使用k2v2重新键入。2015年6月,表文件4和表文件5使用k2v3重新设置了密钥。
在帐户秘钥和表秘钥之间以及根秘钥和帐户秘钥之间实现了类似的方案。秘钥层次的每一级都会经历key rotation和rekeying,包括根秘钥。帐户密钥和根密钥的key rotation和rekeying不需要对文件进行重新加密。只需要重新加密较低级别的密钥。
不过,表秘钥和文件秘钥之间的关系是不同的。文件秘钥不由表秘钥包装。相反,文件密钥是从表密钥和(唯一的)文件名的组合加密派生的。因此,每当表密钥更改时,其所有相关的文件密钥都会更改,因此需要对受影响的表文件重新加密。然而,密钥派生的最大好处是,它消除了创建、管理和传递单个文件密钥的需要。像Snowflake这样的系统处理数十亿个文件,不然就必须处理GB级别的文件密钥。
我们选择这种设计也是因为Snowflake将存储和计算分离,它可以在不影响用户工作的情况下执行重新加密。rekeying是后台线程,rekeying与查询在不同的节点。在文件被重新加密之后,Snowflake会自动更新数据库表的元数据,以指向新加密的文件。所有正在进行的查询完成后,旧文件将被删除。
图6:table 秘钥的生命周期
4.5.3 端到端的安全性
Snowflake使用AWS CloudHSM作为防篡改、高度安全的方法来生成、存储和使用密钥层次结构的根密钥。AWS CloudHSM是一组硬件安全模块(hsm),它们连接到AWS中的虚拟私有集群。根密钥永远不会离开HSM设备。所有使用根密钥的加密操作都在HSMs本身中执行。因此,在未经授权访问HSM设备的情况下,不能打开较低级别的密钥。hsm还用于在帐户和表级别生成秘钥,包括在秘钥rotation和重建秘钥控期间。我们使用其高可用性配置中配置了AWS CloudHSM,从而保证最小化服务中断。
除数据加密外,Snowflake还通过以下方式保护用户数据:
1.通过访问S3时运用隔离存储策略。
2.用户帐户中基于角色的访问控制,用于对数据库对象进行细粒度的访问控制。
3.加密的数据导入和导出,云提供商(Amazon)也不知道数据的具体内容。
4.用于安全访问控制的双因素和联合身份验证。
总之,Snowflake提供了一个植根于AWS CloudHSM的分层密钥模型,并使用key rotation和rekeying来确保加密密钥遵循标准化的生命周期。密钥管理对用户完全透明,不需要配置、管理或下线。它是全面的安全策略的一部分,该策略支持完全的端到端加密和安全性。
5 相关工作
基于云的并行数据库系统。Amazon有许多DBaaS产品,其中amazon redshift是数仓产品。从并行数据库系统ParAccel演变而来,Redshift可以说是第一个真正的数据仓库系统,作为一种服务提供。Redshift使用了一个经典的 shared-nothing架构。因此,在可伸缩的同时,添加或删除计算资源需要重新分配数据。相比之下,Snowflake的多集群共享数据体系结构允许用户在不移动数据的情况下,立即从存储中独立地放大、缩小甚至暂停计算,包括跨孤立计算资源集成数据的能力。另外,遵循纯服务原则,Snowflake不需要物理调优、数据整理、手动收集表统计信息,也不需要用户进行表清理。尽管Redshift可以将JSON之类的半结构化数据作为VARCHAR来接收,但Snowflake对半结构化数据具有本地支持,包括列式存储这样重要的优化。
Google的云平台提供了一个完全托管的查询服务BigQuery,这是Dremel的实现。BigQuery服务允许用户快速在数TB的数据上运行查询,并在数千个节点上并行化。Snowflake的灵感之一是BigQuery对JSON和嵌套数据的支持,我们发现这是现代分析平台所必需的。但是,虽然BigQuery提供了一种类似SQL的语言,但它与ansi sql语法和语义有一些基本的偏差,这使得它很难与基于SQL的产品一起使用。此外,BigQuery表只能追加数据,需要schemas。相比之下,Snowflake提供了完整的DML(insert、update、delete、merge)、ACID事务,并且不需要对半结构化数据进行schema定义。
Microsoft SQL数据仓库(Azure SQL DW)是Azure云平台和基于SQL Server及其分析平台系统(APS)最新添加的服务应用。类似于Snowflake,它将存储和计算分开。计算资源可以通过数据仓库单元(DWU)进行扩展。但是并发的程度是有限制的。对于任何数据仓库,并发执行的查询的最大数量是32。相比之下,Snowflake通过虚拟仓库可以完全独立地扩展并发工作。Snowflake用户不需要分发密钥和管理其他任务。尽管Azure SQL DW确实支持通过PolyBase对非关系数据进行查询,但它不支持类似Snowflake对半结构化数据的VARIANT类型和相关优化。
文档存储和大数据。MongoDB、Couchbase Server和Apache Cassandra等文档存储近年来越来越受到应用程序开发人员的欢迎,因为它们提供了可伸缩性、简单性和灵活的schema。然而,这些系统的简单key value和CRUD(create、read、update和delete)的API带来的一个挑战是难以表达更复杂的查询。我们看到了一些类似SQL的查询语言的出现,比如用于Couchbase的N1QL或用于apache cassandra的CQL。此外,许多“大数据”引擎现在支持了对嵌套数据的查询,例如Apache Hive、Apache Spark、Apache Drill、Cloudera Impala和Facebook Presto。我们相信,这显示了对schema-less和半结构化数据的复杂分析的真正需求,而我们的半结构化数据支持正是受到许多此类系统的启发。通过使用schema推测、乐观转换和列存储,Snowflake将这些系统的灵活性与面向列的关系数据库的存储效率和执行速度结合了起来。
6 经验和展望
当Snowflake在2012年成立时,数据库方面完全专注于Hadoop上的SQL,在短时间内出现了十几个系统。当时,决定朝着一个完全不同的方向努力,为云构建一个“经典”的数据仓库系统,似乎是一个冒险的举动。经过三年的发展,我们相信这是一个正确的。Hadoop并没有取代关系型数据库,而是对它们进行了补充。人们仍然想要一个关系数据库,它需要更高效、更灵活,更适合于云计算。
Snowflake实现了我们的希望,即为云构建的系统可以为其用户提供一些功能。弹性的多集群共享数据体系结构改变了用户处理数据任务的方式。SaaS模式不仅让用户很容易试用和采用该系统,而且极大地帮助了我们的开发和测试。通过单一的生产版本和在线升级,我们能够发布新功能、提供改进和修复问题,比传统开发模式下的速度要快得多。
虽然我们希望半结构化扩展被证明是有用的,但我们对采用的速度感到惊讶。我们发现了一个非常流行的模型,在该模型中,组织将使用Hadoop实现两个功能:存储JSON,以及将其转换为可以加载到RDBMS中的格式。通过提供一个能够高效存储和处理半结构化数据的系统,我们发现Snowflake不仅取代了传统的数据库系统,而且还可以取代Hadoop集群。
当然,这不是一次无痛的旅行。虽然我们的团队拥有超过100年的数据库开发经验,但我们在开发过程中确实犯了一些完全可以避免的错误,包括一些关系运算符的早期实现过于简单化,没有在引擎的早期集成所有数据类型,对资源管理的关注不够早,全面的日期和时间函数功能的延迟推出。同时,我们对避免调优的持续关注引发了一系列工程挑战,最终带来了许多令人兴奋的技术解决方案。因此,如今,Snowflake只有一个调优参数:用户想要多少性能(并愿意为此付费)。
虽然Snowflake的性能已经非常有竞争力,特别是考虑到没有调优方面,但是我们知道有很多优化我们还没有时间去做。但有些出乎意料的是,对我们的用户来说,核心性能几乎从来都不是问题。原因是通过虚拟仓库进行弹性计算可以提供偶尔需要的性能提升。这使我们把发展方向集中在系统的其他方面。
我们面临的最大技术挑战与SaaS和系统的多租户方面有关。构建一个能够同时支持数百个用户的元数据层是一项非常具有挑战性和复杂的任务。处理各种类型的节点故障、网络故障和服务支持是一场永无止境的战斗。安全性一直是并将继续是一个大话题:保护系统和用户的数据免受外部攻击。维护一个每天运行数百万条查询的数百个节点的实时系统,会很有成就感,同时也需要一种高度集成的开发、操作和支持的方法。
Snowflake用户继续向系统抛出越来越大、越来越复杂的问题,会决定系统的发展。我们目前正致力于通过提供额外的元数据结构和数据重新组织来提高数据访问性能,重点是最小化或无用户交互。我们继续改进和扩展核心查询处理功能,包括标准SQL和半关系化数据结构的扩展。我们计划进一步改进倾斜处理和负载平衡策略,其重要性随着用户工作的规模而增加。我们致力于简化用户的工作管理,使系统更具弹性。我们致力于与外部系统的集成,包括数据高频加载等问题。
Snowflake未来面临的最大挑战是向全自助模式的过渡,用户可以在任何阶段注册并与系统交互,而无需我们的参与。它将带来许多安全性、性能和支持方面的挑战。我们期待着这种功能的实现。
7 致谢
Snowflake是大家的共同的产出,不能将人员一一在这里列出。我们要感谢整个Snowflake工程团队为产品所做的贡献,以及他们为产品所付出的辛勤工作、努力和自豪。我们还要感谢所有其他的“Snowflake”们,感谢他们为用户带来这款产品,共同打造一个伟大的公司所做的出色工作。与这样一支优秀的团队合作,我们一直深受感动并感到谦卑。