在私有云时代,私有云平台简直可能按需提供有限的计算和存储资源。同时,SaaS 模型将企业级零碎带给了无奈累赘老本和相干零碎复杂性的用户。传统的数仓零碎正在致力的适应新的环境,然而传统数仓毫无疑问还存在一些设计上的局限性,传统数仓往往都是为固定资源而设计,因此没方法利用云的弹性能力。另外,传统的数仓依赖简单的 ETL 流水线和物理调优,这个是和云的半构造数据和疾速解决工作问题的新模式所须要的弹性和疾速不统一的。
基于此,咱们决定进行根本性的从新设计,建设云上的企业级数据仓库的解决方案。这便是 Snowflake 的设计初衷。本文将会次要介绍 Snowflake 的设计、多集群共享数据的构造和 Snowflake 的要害个性:极致的弹性和可用性、半结构化和 schema-less 的数据反对、工夫旅行、端到端的安全性。
1.Snowflake 介绍
云技术的呈现标记着软件的倒退将从本地服务器上的交付和运行转移到由亚马逊、谷歌或微软等平台提供商提供的共享数据中心和软件即服务的解决方案。云的共享基础设施保障了规模经济,极高的可扩展性和可用性,现收现付老本模式,以便适应不可预测的应用需要。然而,只有当软件自身可能在商品资源池(云)上弹性伸缩时,能力取得这些劣势。传统的数据仓库解决方案先于云,被设计成在小型动态集群上运行,这些集群由性能良好的机器组成,这使得传统的数仓在体系结构上不适宜云。
随着平台的变动,数据也跟着产生了变动。过来的状况是,数据仓库中的大多数数据都来自组织外部的数据源事务化:事务零碎、企业资源布局(ERP)应用程序、客户关系治理(CRM)应用程序等。数据的构造、数量和速率都是可预测和可把握的。但随着云技术的倒退,大量且快速增长的数据来源于不那么可控或内部的起源:应用程序日志、web 应用程序、挪动设施、社交媒体、传感器数据(物联网)。除了一直增长的数据量,这些数据常常以 schema-less、半结构化的格局存储。传统的数据仓库解决方案正在致力解决于这种新的数据。这些解决方案十分依赖于 ETL 管道和物理调优,但管道和物理调优是假设来自外部的可预测、不易挪动且易于分类的数据。
为了应答这些毛病,局部数仓社区曾经转向 Hadoop 或 Spark 等大数据平台。只管这些工具对于数据中心规模的解决工作来说是不可或缺的,开源社区也在一直地进行重大改良,如 Stinger Initiative(号称让 Hive 提速 100 倍),但它们依然不足现有数仓的效率和性能。但最重要的是,他们须要大量的致力来推广和应用。
咱们设计 Snowflake 的初衷就是基于当下传统的数据仓库技术或大数据平台并不能很好的与云进行联动,为此咱们专门为云构建了一个全新的数据仓库零碎,这便是 Snowflake 弹性数据仓库。与云数据管理畛域的许多其余零碎不同,Snowflake 并不是基于 Hadoop、PostgreSQL 之类的,解决引擎和其余大部分组件都是从新开发的。
Snowflake 的要害特点如下:
Saas 级服务体验。用户无需购买机器、雇佣数据库管理员或装置软件。用户基于本身零碎在云上的数据,借助于 Snowflake 的图形界面或 ODBC 等标准化接口就能够立刻操作和查问数据。
关系型。Snowflake 反对 ANSI 的 SQL 和 ACID 的事务。大部分的用户简直无需改变或者很小的改变就能迁徙曾经存在的工作内容。
半结构化。Snowflake 提供了用于遍历、展平和嵌套半结构化数据的内置函数和 SQL 扩大,并反对 JSON 和 Avro 等风行格局。主动模式发现和列式存储使得对 schema 较少的半结构化数据的操作简直与对一般关系数据的操作一样快,而无需用户额定的操作。
弹性。存储和计算资源能够独立无缝地扩大,而不影响数据可用性或并发查问的性能。
高可用。Snowflake 可能容忍节点,集群,甚至全副的数据中心失败。在软件和硬件更新的时候不会下线。
持续性。Snowflake 的设计具备极高的持续性,可避免意外数据失落:克隆、下线和跨区域备份。
经济节约。Snowflake 具备很高的计算效率,所有的表数据都被压缩。用户只为他们理论应用的存储和计算资源付费。
平安。所有数据包含临时文件和网络流量都是端到端加密的。没有用户数据裸露在云平台上。此外,用户可能基于角色在 SQL 级别执行级别细粒度的访问控制。
Snowflake 当初运行在亚马逊云下面(截止目前曾经扩大在亚马逊、微软、谷歌三家次要云厂商),然而将来咱们也会反对其余云平台。在写这篇文档的同时,Snowflake 被大大小小的组织用于生产。每天运行几百万次查问在几 PB 的数据上。
2. 存储与计算
Shared-nothing 构造曾经成为高性能数据仓库的支流体系结构,次要起因有两个:可扩展性和商用硬件。在 Shared-nothing 构造中,每个查问处理器节点都有本人的本地磁盘。表是跨节点程度分区的,每个节点只负责其本地磁盘上的行。这种设计能够很好地扩大星型模式查问,因为将一个小的(播送的)维度表与一个大的(分区的)事实表连接起来只须要很少的带宽。而且,因为共享数据结构或硬件资源简直没有争用,因而不须要低廉的定制硬件。
在纯正的 Shared-nothing 构造中,每个节点都有雷同的性能并在雷同的硬件上运行。这种结构设计无疑是良好的。不过,纯正的 Shared-nothing 构造有一个重要的毛病:它将计算资源和存储资源严密耦合,这在某些场景中会导致问题。
异构工作负载。因为对于工作负载的要求不同,在同一硬件配置下,对于大容量加载(高 I / O 带宽,轻计算)来说,平衡的系统配置不适宜简单查问(低 I / O 带宽,重计算),反之亦然。这使得硬件的总体资源使用率较低。
节点关系变动。如果产生节点更改、节点故障,或是用户被动进行了零碎调整,则大量数据须要从新 shuffle。因为雷同的节点同时负责数据 shuffle 和查问,因而会对性能有显著的影响,从而限度了灵活性和可用性。
在线降级。尽管通过正本机制能够在肯定水平上加重节点关系变动更改的影响,但软件和硬件降级最终会影响零碎中的每个节点。尽管原则上还是能够进行在线降级。然而因为所有节点都是严密耦合的,并且都是同质的,这使得实现在线降级变得十分艰难。
在外部部署环境中,这些问题通常不会产生太过微小的影响因为节点的降级、故障和零碎扩容产生的频率并不高。
而在云中状况则不大雷同。像亚马逊 EC2 这样的平台具备许多不同的节点类型。它们只需简略将数据挪动到正确类型的节点,同时,节点故障更为频繁,性能可能会产生巨大变化,甚至在雷同类型的节点之间也是如此。因而,节点关系的扭转不是偶尔,而是常态。最初,在线降级和弹性扩大逐步成为了当下客户的一个重大痛点。在线降级可能大幅缩短软件开发周期,晋升零碎的可用性。
基于此,Snowflake 实现了存储和计算拆散。存储和计算由两个松耦合、独立可扩大的服务来解决。计算是通过 Snowflake 的(专有的)shared-nothing 引擎提供。存储是通过亚马逊 S3 提供的,反对多类型的对象存储(Azure 对象存储,Google 云存储)。同时,为了缩小计算节点和存储节点之间的网络流量,每个计算节点在本地磁盘上缓存了一些表的数据。
存储和计算拆散的另一个益处是实现了数据的冷热拆散,本地磁盘空间不必存储整个数据,这些数据可能十分大,而且大部分是冷数据(很少拜访)。本地磁盘专门用于长期数据和缓存,两者都是热数据(倡议应用高性能存储设备,如 ssd)。因而,缓存了热数据,性能就靠近甚至超过纯 shared-nothing 构造的性能。咱们称这种新的体系结构为 multi-cluster、shared-data 构造。
3. 构造
Snowflake 是 Saas 服务商。除了提供高可用性和操作性之外,还须要兼顾高可用。为此,Snowflake 是一个面向服务的体系结构,由高度容错和独立可扩大的服务组成。这些服务通过 RESTful 接口进行通信,分为三个体系结构层:
数据存储。该层应用 amazon s3 存储表数据和查问后果。
虚构仓库。零碎的“肌肉”。该层通过弹性的虚构集群(称为虚构仓库),执行查问。
云服务。零碎的“大脑”。这一层是治理虚构仓库、查问、事务和围绕虚构仓库的所有元数据的服务的汇合,蕴含数据库元信息、访问控制信息、加密密钥、应用状况统计等。
图 1 展现了 Snowflake 三个架构层及其次要组件。
图 1:multi-cluster、shared-data 架构
3.1 数据存储
AWS 被选为 Snowflake 的初始平台次要有两个起因。首先,AWS 是云平台市场上最成熟的产品。其次(与第一点相干),AWS 提供了最大的潜在用户资源。
接下来的抉择是应用 S3 还是基于 HDFS 或相似的技术开发咱们本人的存储服务。咱们花了一些工夫对 S3 进行了测试,发现尽管它的性能可能有些不同,但它的可用性、高可用性和弱小的持续性有牢靠的保障。因而,咱们没有开发本人的存储服务,而是决定将精力投入到虚构仓库层的本地缓存和数据歪斜解决技术上。
相比于本地存储,S3 尽管具备更高的拜访提早。然而,S3 是一个对象存储,具备一个绝对简略的基于 HTTP 的 PUT/GET/DELETE 接口。对象(即文件)只能齐全写入。甚至不可能将数据附加到文件的开端。文件的确切大小须要在 PUT 申请中前就确定。并且,S3 反对对局部(范畴)文件的 GET 申请。
这些属性对 Snowflake 的表文件格式和并发管制计划有很大的影响(参见第 3.3.2 节)。表被程度地划分成大的、不可变的文件,这些文件相当于传统数据库系统中的块或页。在每个文件中,每个属性或列的值都被分组在一起并进行了大量压缩,这是一种广泛采取的计划,在文献 [2] 中称为 PAX 或 hybrid columnar。每个表文件都有一个表头,其中蕴含文件中每列的偏移量,以及其余元数据。因为 S3 容许对局部文件执行 GET 申请,所以查问只须要下载文件头和它们须要的列。
Snowflake 不仅在表数据上应用 S3。当本地磁盘空间耗尽时,它还应用 S3 存储由查问(例如,大量连贯)生成的长期数据,以及大型查问后果。将 temp 数据溢出到 S3,零碎能够计算任意大的查问,而不会呈现内存不足或磁盘有余的谬误。将查问后果存储在 S3 中,实现了客户端交互新形式并简化查询处理,因为它打消了对传统数据库系统中的服务端游标的须要。
元数据,例如 catalog 信息,由 S3 文件、统计信息、锁、事务日志等组成,存储在可伸缩的事务 KV 存储中,这也是云服务的一部分。
3.2 虚构仓库
虚构仓库层由 EC2 实例集群组成。每个这样的集群通过一个称为虚构仓库(VW)的形象出现给用户。形成虚构仓库的单个 EC2 实例称为工作节点。用户不间接与工作节点交互。事实上,用户不须要关怀哪个或者多少个工作节点组成了一个虚构仓库。虚构仓库依照大家所相熟的“T 恤尺寸”从 X -Small 到 XX-Large 不等来标识规模大小。这样的形象展现容许咱们独立于底层云平台来倒退服务和定价。
3.2.1 弹性与隔离
VM 层是纯计算资源,能够依照需要创立、销毁并且能够随时扭转大小。创立或者销毁一个 VM 对数据库状态没有任何影响。当没有查问时候,用户能够敞开所有的 VM 资源。这种弹性答应用户独立于数据层,依照需要动静的伸缩他们的计算资源。
每个查问只在一个 VW 上运行。工作节点不会在 VW 之间共享,从而使查问具备弱小性能隔离。(也就是说,咱们将工作节点共享视为将来工作的一个重要畛域,因为对于性能隔离不太重要的用例,它将实现更高的利用率和更低的老本。)
提交新查问时,相应 VW 中的每个 worker 节点(或者如果优化器检测到一个小查问,则为节点的子集)生成一个新的 worker 过程。每个工作过程只在其查问工夫内工作。worker 过程自身,即便有 update 语句,不会对外部可见造成影响,因为表文件是不可变的,参见第 3.3.2 节。因而,worker 故障很容易被管制,并且通过重试来解决。不过,Snowflake 目前不反对局部重试,因而十分大的、长时间运行的查问是一个值得关注的畛域和将来的工作。
每个用户能够在任何给定的工夫运行多个 VW,而每个 VW 又能够运行多个并发查问。每个 VW 都能够拜访雷同的共享表,而无需物理复制数据。
共享的有限存储意味着用户能够共享和集成所有数据,这是数据仓库的外围准则之一。同时,用户受害于公有计算资源,防止了不同工作和组织的烦扰,这也是数据集市的起因之一。这种弹性和隔离使得一些新的应用策略成为可能。对于 Snowflake 用户来说,通常有几个 VM 用于来自不同组织的查问,通常是间断运行的,并按需定期启动 VM,例如批量加载。
另一个与弹性无关的重要后果是,通常能够用大致相同的价格取得更好的性能体现。例如,在具备 4 个节点的零碎上,数据加载须要 15 小时,而在具备 32 个节点的零碎上,数据加载可能只须要 2 小时。因为计算工夫是付费的,所以总体老本十分类似,但用户体验却截然不同。因而,咱们置信弹性是 Snowflake 架构最大的长处和区别之一,因为须要一种新鲜的设计来利用云的独特性能。
3.2.2 本地缓存和文件窃取
每一个 worker 节点在本地磁盘上缓存了一些表数据。缓存的文件是一些表文件,即节点过来拜访过的 S3 对象。精确地说,缓存保留文件头和文件的各个列,因为查问只下载它们须要的列。
缓存在工作节点的工作工夫内无效,并在并发和后续工作过程(即查问)之间共享。它只是一个文件流和列申请,并遵循一个简略的最近起码应用(LRU)替换策略,而疏忽了单个查问。这个简略的计划成果比拟好,然而咱们未来可能会改良它,以便更好地匹配不同的工作。
为了进步命中率并防止 VW 的工作节点之间对单个表文件进行冗余缓存,查问优化器应用表文件名上的统一哈希将输出文件集调配给工作节点。因而,拜访同一表文件的后续查问或并发查问将在同一工作节点上执行。
Snowflake 中统一的 hash 是 lazy 的。当工作节点因为节点故障或 VW 调整大小而更改时,不会立刻对数据进行 shuffle。相同,Snowflake 依赖 LRU 替换策略最终替换缓存内容。此解决方案将替换缓存内容的老本摊派到多个查问上,从而取得比立刻缓存或纯 shared-nothing 零碎更好的可用性,后者须要立刻在节点之间 shuffle 大量表数据。它简化了零碎,因为没有“降级”模式。
除了缓存,歪斜解决在云数据仓库中尤为重要。因为虚拟化问题或网络争用,某些节点的执行速度可能比其余节点慢得多。在这点上,Snowflake 在扫描文件的时候就解决了这个问题。每当工作过程实现对其输出文件集的扫描时,它就会从其对等过程申请其余文件,咱们称之为文件窃取。当申请达到时,如果一个 worker 发现它的输出文件汇合中还有许多文件要解决,这个时候又有其余 worker 申请帮忙,这个 worker 将这个申请中他须要的查问的范畴内的一个残余文件的解决势力转移给其余 worker。而后其余 worker 间接从 S3 下载文件,而不是从这个 worker 下载。这种设计确保了文件窃取不会给以后 worker 减少额定的解决累赘。
3.2.3 执行引擎
如果一个 1000 个节点的零碎执行一个查问,而另一个零碎能够应用 10 个这样的节点就能够用同样工夫实现这个查问,那么这个零碎就没有什么价值了。因而,尽管可伸缩性是首要的,但每个节点的效率同样重要。咱们心愿给用户提供市场上任何数据库服务产品中最好的性价比,因而咱们决定实现咱们本人的 SQL 执行引擎。咱们构建的引擎是列式的、向量化的和基于 push 的。
列式存储和执行通常被认为优于行式存储和执行,因为它更无效地应用了 CPU 缓存和 SIMD 指令,并且更有可能进行(轻量级)压缩。
向量化执行,与 MapReduce 相比,Snowflake 防止了两头后果的物化。相同,数据是以 pipeline 形式解决的,每次以列成批处理几千行。这种办法由 VectorWise(最后是 MonetDB/X100)独创,这能节俭了 I / O 并大大提高了缓存效率。
基于 push 的执行是指,关系运算符将后果推送到其上游运算符,而不是期待这些运算符拉取数据(经典的火山式模型)。Push-based 进步了缓存效率,因为他打消了循环中的管制逻辑。它还使 Snowflake 可能高效地解决 DAG 模式的打算,而不仅仅是树的构造,从而可能更好的采纳共享和管道化的形式利用两头后果。
同时,传统查询处理中的许多开销在 Snowflake 中并不存在。须要留神的点,在执行时候不须要事务管理。就引擎而言,查问是针对一组固定的不可变文件执行的。此外,没有缓冲池。大多数查问扫描大量数据。这里没有应用内存进行表缓冲和操作。不过,Snowflake,在内存耗尽时,容许所有次要操作(join、group by、sort)溢写到磁盘。纯内存引擎尽管更精简,兴许更快,但它的限制性太强,无奈解决所有的查问状况。剖析型工作有的时候会有大量的 join 或 aggregation。
3.3 云服务
虚构仓库是长期的、特定于用户的资源。相比,云服务层在很大水平上是多租户的。这一层的每个服务访问控制、查问优化器、事务管理器和其余服务都是长期存在的,并在许多用户之间共享。多租户进步了利用率并缩小了治理开销,这比传统体系结构中每个用户都有一个齐全公有的零碎在体系结构上具备更好的规模经济。
每个服务都被复制以实现高可用性和可扩展性。因而,单个服务节点的故障,可能导致某些正在运行的查问可能会失败(并通明地从新执行),然而不会导致数据失落或可用性降落。
3.3.1 查问治理和优化
用户所有查问都通过云服务层。云服务层解决查问生命周期的所有晚期阶段:解析、对象解析、访问控制和打算优化。
Snowflake 的查问优化器遵循典型的层叠式办法,采纳自顶向下的基于老本的优化。所有用于优化的统计信息都会在数据加载和更新时主动保护。因为 Snowflake 不应用索引(参见第 3.3.3 节),因而执行打算搜寻的空间会比其余一些零碎更小。通过将许多决策下推到执行时候(例如连贯的数据分布类型),执行打算搜寻的空间进一步缩小。这种设计缩小了优化器做出的谬误优化,以峰值性能的小损失为代价减少了健壮性。它还使零碎更易于应用(性能变得更可预测),这与 Snowflake 对服务体验的整体关注是统一的。
优化器实现后,生成的执行打算将分发给局部查问节点。当查问执行时,云服务会一直跟踪查问的状态,收集性能指标并检测节点故障。所有查问信息和统计信息都存储起来,进行审计和性能剖析。用户能够通过 Snowflake 图形界面监督和剖析之前和正在进行的查问。
3.3.2 并发管制
如前所述,并发管制齐全由云服务层解决。Snowflake 是为剖析工作而设计的,这些工作往往会有大量读取、批量或随机插入以及批量更新。与大多数零碎一样,咱们决定通过快照隔离(Snapshot Isolation,SI)实现 ACID 事务。
在 SI 下,事务的所有读取都会看到事务启动时数据库的统一快照。通常,SI 是在多版本并发管制(MVCC)之上实现的,这意味着每个更改的数据库对象的一个正本都会保留一段时间。
MVCC 是一个天然的抉择,因为表文件是不可变的,这是应用 S3 存储的后果。只有将文件替换为蕴含更改的其余文件,能力对文件进行更改。因而,表上的写操作(insert、update、delete、merge)通过增加和删除绝对于上一个表版本的整个文件来生成新版本的表。在元数据(在全局键值存储中)中跟踪文件的增加和删除,这种模式对属于特定表版本的文件集计算十分高效。
除了 SI 之外,Snowflake 还应用这些快照来实现工夫旅行和数据库对象的高效复制,详细信息请参见第 4.4 节。
3.3.3 剪枝优化
限度对给定查问数据的拜访是查询处理最重要的方面之一。从历史上看,数据库中的数据拜访是通过应用 B + 树或相似数据结构模式的索引来限度的。尽管这种办法被证实对事务处理十分无效,但对于像 Snowflake 这样的零碎,它会引发多个问题。首先,它重大依赖随机拜访,因为存储介质(S3)和数据格式(压缩文件),这将是一个问题。其次,保护索引显著减少了数据量和数据加载工夫。最初,用户须要显式地创立索引,这与 Snowflake 的纯服务办法不一样。即便在调优人员的帮忙下,保护方面也可能是一个简单、低廉有危险的过程。
另一种技术最近在大规模数据处理中失去了广泛应用:基于最小 - 最大值的修剪,也称为小物化聚合、区域映射和数据跳跃。这里,系统维护给定数据块(记录集、文件、块等)的数据分布信息,特地是块内的最小值和最大值。依据查问谓词的不同,这些值可用于确定给定查问可能不须要给定的数据块。例如,假如文件 f1 和 f2 在某个列 x 中别离蕴含值 3..5 和 4..6。而后,如果查问有一个谓词,其中 x >=6,咱们就晓得只须要拜访 f2。与传统索引不同,这种元数据通常比理论数据小几个数量级,因而存储开销小,访问速度快。
剪枝优化很好地合乎 Snowflake 的设计准则:它不依赖于用户输出;它能够很好地扩大;并且易于保护。更重要的是,它能够很好地对大数据块进行程序拜访,并且在加载、查问优化和查问执行工夫方面减少的开销很小。
Snowflake 一直地为每个独自的表文件做相干元数据的剪枝优化。元数据不仅包含一般的关系列,还包含半结构化数据中自动检测的列的抉择,参见第 4.3.2 节。在优化过程中,依据查问谓词查看元数据,以缩小(“删减”)查问执行的输出文件集。优化器不仅对简略的基值谓词执行修剪,还对更简单的表达式(如 WEEKDAY(orderdate) IN (6, 7))执行剪枝优化。
除了动态剪枝,Snowflake 还在执行过程中执行动静剪枝。例如,作为 hash join 解决的一部分,Snowflake 收集无关 build-side 记录中 join key 散布的统计信息。而后将此信息推送到 probe-side,并用于过滤 probe side 的整个文件,甚至可能跳过这些文件。除此之外,还应用其余技术,如 bloom joins。
4. 亮点性能
Snowflake 提供了关系型数仓所冀望的许多个性:全面的 SQL 反对、ACID 事务、标准接口、稳定性和安全性、用户反对,当然还有弱小的性能和可扩展性。此外,它还引入了一些在相干零碎中很少或没有的其余有价值的个性。本节介绍了其中一些咱们认为有技术区别的个性。
4.1 Saas 服务体验
正如大部分 Saas 服务一样,Snowflake 能够通过浏览器间接与零碎交互。一个 WebUI 是一个要害的区别。WebUI 使得从任何地位和环境拜访 Snowflake 都非常容易,同时因为云中已有大量数据,用户只需将 Snowflake 指向本人的数据并进行查问,而无需下载任何软件。
Snowflake 的 UI 界面能够 SQL 操作,还能够拜访数据库目录、用户和系统管理、监督、应用信息等。
4.2 继续可用性
在过来,数仓的解决方案个别是局域网内的暗藏较好的后端系统,与世界上大部分的网络隔离的。在这种环境中,打算内(软件降级或治理工作)和计划外(故障)的停机工夫通常不会对操作产生很大影响。然而,随着数据分析对越来越多的业务工作变得至关重要,继续可用性成为数仓的一个重要需要。
Snowflake 提供了满足这些冀望的间断可用性。这方面的两个次要技术是故障恢复能力和在线降级能力。
4.2.1 故障恢复能力
Snowflake 在体系结构的所有级别上都能容忍单个和相干的节点故障,如图 2 所示。现在,Snowflake 的数据存储层是 S3,它跨多个数据中心进行复制,在 Amazon 术语中称为“可用性区域”(availability zones)或 AZs。跨 AZs 的复制容许 S3 解决残缺的 AZ 故障,并保障 99.99% 的数据可用性和 99.999999999% 的持久性。与 S3 的体系结构相匹配,Snowflake 的元数据存储也在多个 AZ 之间散布和复制。如果一个节点产生故障,其余节点能够在不影响最终用户的状况下接管工作。云服务层的其余服务由多个 AZ 中的无状态节点组成,负载均衡器负责散发用户申请。因而,单个节点故障甚至是齐全的 AZ 故障都不会对系统范畴造成影响,可能是对以后连贯到故障节点的用户的一些失败查问。这些用户将被重定向到另一个节点进行下一次查问。
相比之下,虚构仓库(VM)并不散布在 AZs 中。这个抉择是出于性能思考。高吞吐是分布式查问执行的要害,而在同一个 AZ 中,网络吞吐量要高得多。如果其中一个工作节点在查问执行期间失败,则查问会失败,但会通明地从新执行,要么立刻替换该节点,要么临时缩小节点数。为了减速节点更换,Snowflake 保护了一个小的备用节点池。(这些节点还用于疾速 VW 配置。)
如果全副的 AZ 变得不可用,那么在该 AZ 的给定 VW 上运行的所有查问都将失败,并且用户须要在不同的 AZ 中被动重新配置 VW。因为全副的 AZ 故障是真正的灾难性和极为常见的事件,咱们明天承受这种局部零碎不可用的状况,但心愿在未来解决它。
图 2:Snowflake 的多数据中心实例
4.2.2 在线降级能力
Snowflake 不仅在产生故障时提供间断可用性,而且在软件降级期间也提供间断可用性。零碎的设计容许同时部署服务的多个版本,包含云服务组件和虚构仓库。这是因为所有服务实际上都是无状态的。所有的状态都保留在事务性 KV 存储服务中,并通过映射层进行拜访,映射层负责元数据版本控制和模式演变。每当咱们更改元数据模式时,咱们都会确保与以前的版本向后兼容。
为了执行软件降级,Snowflake 首先将新版本的服务与以前的版本一起部署。而后,用户帐户逐步切换到新版本,这个时候,相应用户收回的所有新查问都被定向到新版本。同时,保障以前版本的所有查问都实现。一旦所有查问和用户在以前的版本没有查问后,以前版本的所有服务都将被终止和停用。
图 3 显示了正在进行的降级过程的快照。有两个版本的 Snowflake 运行并排,版本 1(亮)和版本 2(暗)。云服务有两个版本,管制两个虚构仓库(vw),每个都有两个版本。负载平衡器将传入的申请定向到云服务的适当版本。一个版本的云服务只与一个匹配版本的通信。
如前所述,两个版本的云服务共享雷同的元数据存储。此外,不同版本的 vw 可能共享雷同的工作节点及其各自的缓存。因而,降级后不须要从新填充缓存。整个过程对用户是通明的,没有停机或性能降落。
在线降级也对咱们的开发速度,以及如何解决 Snowflake 的要害 bug 产生了微小的影响。在撰写本文时,咱们每周降级一次所有服务。这意味着咱们每周都会公布性能和改良。为了确保降级过程顺利进行,降级和降级都在一个非凡的预生产的 Snowflake 正本一直测试。在极少数状况下,如果咱们在产品中发现了一个重大的 bug(不肯定是在降级过程中),咱们能够很快地将其降级到以前的版本,或者施行一个修复程序并执行一个超出原打算的降级。这个过程并不像听起来那么可怕,因为咱们一直地测试和应用降级 / 降级机制。这是高度自动化的和并且严格的。
图 3:在线降级
4.3 半结构化和 Schema-Less 的数据
Snowflake 将规范 SQL 类型零碎扩大为三种半结构化数据类型:VARIANT、ARRAY 和 OBJECT。VARIANT 类型的值能够存储本地 SQL 类型的任何值(DATE、VARCHAR 等),也能够存储可变长度的数组,以及相似 JavaScript 的对象,字符串到 VARIANT 值的映射。后者在文献中也被称为 documents,由此产生了文档存储的概念(MongoDB,Couchbase)。
数组和对象只是类型 VARIANT 的严格模式。外部示意是雷同的:一个自描述的紧凑二进制序列化类型,它反对疾速的键值查找,以及高效的类型测试、比拟和 hash。因而,VARIANT 列能够像其余列一样用作 join keys、gourping keys 和 ordering keys。
VARIANT 类型容许 Snowflake 以 ELT(Extract-Load-Transform)形式应用,而不是以传统的 ETL(Extract-Transform-Load)形式应用。不须要指定数据的 schema 或在加载时进行转换。用户能够将 JSON、Avro 或 XML 格局的输出数据间接加载到变量列中;Snowflake 解决解析和类型推断(参见第 4.3.3 节)。这种办法在文献中被失当地称为“schema later”,它容许通过将信息生产者与信息消费者和任何中介拆散来解决 schema 问题。相同,传统 ETL 管道中数据 schema 的任何更改都须要组织中多个部门之间的协调,这可能须要数月的工夫来执行。
ELT 和 Snowflake 的另一个长处是,当前如果须要转换,能够应用并行 SQL 数据库查问性能来执行转换,包含连贯、排序、聚合、简单谓词等操作,这些操作在传统 ETL 工具链中通常缺失或效率低下。在这一点上,Snowflake 还具备自定义函数(udf),反对残缺的 JavaScript 语法,并与 VARIANT 数据类型集成。对 udf 的反对进一步减少了能够在 Snowflake 中执行的 ETL 工作的数量。
4.3.1 后关系执行
对数据最重要的操作是提取数据元素,能够按字段名(对于对象)提取,也能够按偏移量(对于数组)提取。Snowflake 提供了函数式 SQL 和类 JavaScript 的门路标识来反对。外部编码也使得提取十分高效。子元素只是父元素中的指针;不须要复制。提取之后通常会将后果变量值转换为规范 SQL 类型。同样,编码也使强制转换十分无效。
第二种常见操作是展平数据,行将嵌套构造旋转到多行中。Snowflake 应用 SQL 横向视图来示意开展操作。这种扁平化能够是递归的,容许将文档的层次结构齐全转换为一个适宜 SQL 解决的关系表。与展平相同的操作是聚合。Snowflake 为此引入了一些新的聚合和剖析函数,如 ARRAY_ AGG 和 OBJECT_AGG。
4.3.2 列存及解决
将半结构化数据序列化(二进制)是将半结构化数据集成到关系数据库中的惯例抉择。不好的方面是,行存储的解决效率个别低于列存储,所以列式关系数据个别会将半结构化数据转换为关系数据。
Cloudera Impala[21](应用 Parquet[10])和 Google Dremel[34]曾经证实,半结构化数据的列式存储是可能的,也是无益的。然而,Impala 和 Dremel(及其内部化 BigQuery[44])要求用户为列式存储提供残缺的 table schema。为了实现 schema-less 序列化依然放弃灵活性和列式关系数据库的性能,Snowflake 引入了一种新的主动类型推断和列式存储办法。
如第 3.1 节所述,Snowflake 以混合列格局存储数据。在存储半结构化数据时,零碎会主动对单个表文件中的文档汇合执行统计分析,以执行主动类型推断,并确定哪些(类型化的)类型是常见的。而后从文档中移除相应的列独自存储,独自存储的列应用与本地关系数据雷同的列压缩形式。对于这些列,Snowflake 甚至会计算物化聚合,以便通过修剪(参见第 3.3.3 节)应用,就像一般关系数据一样。
在扫描过程中,不同的列能够重新组合成一个 VARIANT 的列。然而,大多数查问只对原始文档的一部分列感兴趣。在这些状况下,Snowflake 会将映射和强制转换表达式下推到 scan 中,只拜访必要的列并将其间接强制转换到指标 SQL 类型中。
下面形容的优化对于每个表文件都是独立执行的,这使得即便在 schema 变动的状况下也能够无效地存储和提取。然而,它的确给查问优化带来了挑战,特地是剪枝。假如一个查问在门路表达式上有一个谓词,咱们心愿应用修剪来限度要扫描的文件集。门路和相应的列可能呈现在大多数文件中,但频率仅足以保障某些文件中的元数据。激进的解决方案是简略地扫描没有适合元数据的所有文件。Snowflake 通过计算所有门路上的 Bloom 过滤器(而不是值)来改良此解决方案存在于文件中。这些 Bloom 过滤器与其余文件元数据一起保留,并在修剪期间由查问优化器进行探测。能够平安地跳过不蕴含给定查问所需门路的表文件。
4.3.3 乐观转换
因为一些本地 SQL 类型(尤其是日期 / 工夫值),比方罕用的格局(如 JSON 或 XML)中是字符串,因而须要在写入时(插入或更新期间)或读取时(查问期间)将这些值从字符串转换为其理论类型。如果没有 schema 的提醒,这些字符串转换须要在读取时执行,而在以读取为主的查问中,这比在写入期间执行一次转换效率要低。没有类型的数据的另一个问题是短少适合的元数据进行优化,比方对于日期比拟重要。(剖析工作通常在日期列上有范畴查问。)
但在写入时,主动转换可能会失落信息。例如,一些字段定义成数字实际上可能不是数字,比方后面填充 0 的字符串。又比方,看起来像是日期实际上可能是文本内容。Snowflake 通过执行乐观数据转换来解决这个问题,并在独自的列中保留转换后果和原始字符串(除非是齐全可逆的不保留原始字符串)。如果查问之后须要原始的字符串,则能够轻松地检索或重构。因为有不加载和不拜访未应用的列,所以双存储对查问性能的影响是最小的。
4.3.4 性能体现
为了评估列式存储、乐观转换和半结构化数据剪枝对查问性能的综合影响,咱们应用 TPC-H-like 数据集和查问进行了测试。
咱们创立了两种类型的数据库模式。首先,一个传统的关系型 TPC- H 模式。第二种是“schema-less”数据库模式,其中每个表都由一列 VARIANT 类型组成。而后,咱们生成汇集(排序)的 SF100 和 SF1000 数据集(别离为 100GB 和 1TB),以纯 JSON 格局存储数据集(即日期变成字符串),并应用关系数据库模式和 schema-less 数据库模式将数据加载到 Snowflake 中。咱们没有将 schema-less 数据的字段、类型提供给零碎,也没有进行调优。而后,咱们在 schema-less 数据库定义了一些视图,以便可能对所有四个数据库运行完全相同的 TPC- H 查问集。(在撰写本文时,Snowflake 不应用视图进行类型推断或其余优化。)
最初,咱们对这四个数据库运行了所有 22 个 TPC- H 查问,应用了一个中等规范的仓库。图 4 显示了后果。测试后果是通过三次热缓存运行的后果。标准误差是很少,因而省略了。
能够看出,除了两个查问(SF1000 上的 Q9 和 Q17)之外,其余所有查问的 schema-less 存储和查询处理的开销都在 10% 左右。对于这两个查问,咱们确定了慢的起因是 join 程序,这是由 distinct 的已知谬误造成的。咱们持续改良半结构化数据的元数据收集和查问优化。
总之,对于具备绝对稳固和简略模式的半结构化数据(即在实践中发现的大多数机器生成的数据),其查问性能简直与传统关系数据查问的性能相当,能够间接应用列存储、列执行和修剪的劣势,而无需用户优化。
图 4: TPC-H SF100 and SF1000 测试问题: Relational vs. Schema-less 的构造比照
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 关键字来疾速复原意外删除的表、schemas 或整个数据库。
DROP DATABASE important_db;--whoops!
UNDROP DATABASE important_db;
Snowflake 还实现了一个咱们称之为 CLONE 的性能,通过新的关键字 CLONE 来示意。CLONE 表能够疾速创立具备雷同定义和内容的新表,而无需对表文件进行物理复制。CLONE 操作只是复制源表的元数据。克隆实现后,两个表援用同一组文件,但尔后能够独立批改这两个表。CLONE 个性还反对整个 schemas 或数据库,这是十分高效的快照。在进行大量更新之前,或者在执行较为简单的探索性数据分析时,快照是一种很好的做法。CLONE 关键字甚至能够与 AT 和 BEFORE 组合应用,这样就能够在预先创立快照。
CREATE DATABASE recovered_db CLONE important_db BEFORE(STATEMENT =>’8e5d0ca9-005e-44e6-b858-a8f5b37c5726’);
4.5 安全性
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 还通过以下形式爱护用户数据:
通过拜访 S3 时使用隔离存储策略。
用户帐户中基于角色的访问控制,用于对数据库对象进行细粒度的访问控制。
加密的数据导入和导出,云提供商(Amazon)也不晓得数据的具体内容。
用于平安访问控制的双因素和联结身份验证。
总之,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 将这些零碎的灵活性与面向列的关系数据库的存储效率和执行速度联合了起来。
END
更多干货内容请关注微信公众号“录信数软”~