大型电子商务网站开发做尽调需要用到的网站

当前位置: 首页 > news >正文

大型电子商务网站开发,做尽调需要用到的网站,响应式网页模版,网站经常修改好不好本文是对于Snowflake论文的一个完整版解读#xff0c;对于从事大数据数据仓库开发#xff0c;数据湖开发的读者来说#xff0c;这是一篇必须要详细了解和阅读的内容#xff0c;通过全文你会发现整个数据湖设计的起初原因以及从各个维度#xff08;架构设计、存算分离、弹性…本文是对于Snowflake论文的一个完整版解读对于从事大数据数据仓库开发数据湖开发的读者来说这是一篇必须要详细了解和阅读的内容通过全文你会发现整个数据湖设计的起初原因以及从各个维度架构设计、存算分离、弹性伸缩、查询优化、故障恢复、性能优化等等展开而来的设计思路。 可能内容本身站在当下并不显得新颖和具备创意但是从2012年那个时候云计算和大数据也才刚刚普及不久在以结构化数据分析为主的行业里出现了以非结构化和非模式数据的概念并且是基于云计算为底座来做的。不得不说很有一定的挑战性。 下面内容是我对于各个不同段落加了一些自己的认知和解读也是基于大数据经验和云计算从业者的一些认知进行了补充和完善。希望对于每个读者都能有不同程度的收获。 我们生活在分布式计算的黄金时代。公有云平台现在可以根据需要提供几乎无限的计算和存储资源。与此同时软件即服务 (SaaS) 模型为那些由于成本和复杂性而无法负担此类系统的用户带来了企业级系统。遗憾的是传统的数据仓库正在努力适应这种新环境。一方面它们是为固定资源设计的因此无法利用云的弹性。另一方面它们对复杂的提取、转换和加载管道以及物理调优的依赖与云的新类型半结构化数据和快速发展的工作负载的灵活性和新鲜度要求相矛盾。 我们决定进行一次彻底的重新设计我们的任务是为云计算构建一个企业级的数据仓库解决方案。 结果便是“ snowflake 虚拟数据仓库” 简称 snowflake。snowflake 是一个多租户、 事务性的、 安全的、 高可扩展性和弹性的系统 全面支持 SQL 和半结构化和非结构化数据的内建扩展。 这个系统以亚马逊云服务的形式提供 按使用付费。 用户可以将他们的数据上传到云端并且能够利用常见的 工具和接口立刻管理及查询数据。 项目于 2012 年底启动 snowflake 从 2015 年 6 月开始成为通用可用版本。 如今 snowflake 被越来越多的大小组织用于生产环境中。 这个系统每天处理数百万条查询并管理着多个 PB 的数据。 解读 开头就重点输出了两点并且整个论文开篇重点和SaaS化的数据仓库技术也是基于这两点问题展开的。 在当下云计算的时代大数据还是以固有的资源体系架构进行设计无法满足灵活的弹性伸缩能力。 在整个计算处理过程中对于半结构化和非结构化数据的处理不够友好。
所以snowflake的目标是解决这种在云资源之上实现极致弹性伸缩能够全面支持SQL处理的半结构化和非结构化数据的能力从snowflake的设计概念上体现为是一个多租户、 事务性的、 安全的、 高可扩展性和弹性的系统 在本文中我们描述了 Snowflake 的设计以及其新颖的多集群、共享数据架构。文章强调了 Snowflake 的一些关键特性极端弹性和可用性、半结构化且无模式的数据、时间旅行和端到端安全。最后以经验教训和正在进行的工作展望作为结尾。 一、简介 云计算的出现标志着从在本地服务器上交付和执行软件转向共享数据中心和基于云的软件即服务 (SaaS) 解决方案。 云共享基础架构承诺实现规模经济、极端可扩展性和可用性并采用按使用量付费的成本模型来适应不可预测的使用需求。 但是只有当软件本身能够弹性地扩展到云资源池时才能利用这些优势。 传统数据仓库解决方案早于云计算。 它们旨在运行在小型静态群集上这使它们成为较差的体系结构选择。 解读 从大数据技术和云计算技术的诞生来说都是解决的当下那个时代所面临的问题大数据是在2008年前后发展起来解决的是互联网时代数据量爆发引申出的大数据量数据分析和处理的问题云计算的本质还是在于硬件发展速度受限摩尔定律失效如何提升整个资源利用率的问题。在大数据诞生的时期计算机硬件的发展还是非常迅速的。 但不仅平台变了。数据也变了。过去数据仓库中的大部分数据都来自组织内部事务系统、企业资源计划ERP应用、客户关系管理CRM应用等。结构、容量和速度都是可预测且已知的。但是云计算使得相当大且快速增长的数据量来自于不太可控或外部来源应用程序日志、网络应用、移动设备、社交媒体、传感器数据物联网。除了不断增长的数量之外这些数据经常以无模式的、半结构化格式出现。传统数据仓库解决方案正在努力解决这种新数据。这些解决方案依赖于深入的ETL管道和物理调优从根本上假定来自主要内部来源的可预测、缓慢变化且易于分类的数据。 针对这些不足数据仓库社区的一部分转向了“大数据”平台如Hadoop或Spark。  虽然这些对于数据中心规模的数据处理任务来说是不可或缺的工具而且开源社区仍在不断取得重大进展例如Stinger倡议 但它们仍然缺乏成熟的数据库技术所具有的许多效率和功能集。但是最重要的是它们需要大量的工程努力才能推出和使用。 我们相信有一大批用例和工作负载可以从云计算的经济性、弹性和服务方面受益但这些用例和工作负载并不适合传统的数据仓库技术。 解读 这一段讲了大数据的产生的背景从过去单体架构服务所产生的事务型数据到后面大数据量的产生而出现的大数据相关技术比如Hadoop和Spark主要是通过分布式架构的技术来做这种多节点资源的分配和调度但是从弹性和应用上来讲不是当时的核心问题。 通过大数据平台。所以我们决定为云环境构建一个全新的数据仓库系统。该系统被称为 Snowflake弹性数据仓库或“Snowflake”。与许多其他基于云计算的数据管理系统的不同之处在于Snowflake 并不是建立在Hadoop、PostgreSQL 或其他类似技术之上。其处理引擎和其他大部分组件都是从头开始开发的。Snowflake 的关键特性如下 纯软件即服务(SaaS)体验 用户无需购买机器、聘请数据库管理员或安装软件。用户的数据要么已经在云端要么他们上传或邮寄[14]。然后他们可以立即使用Snowflake的图形界面或标准化接口(如ODBC)来操作和查询数据。与其他基于云的关系型数据库服务(DBaas)不同Snowflake的服务范围涵盖整个用户体验。用户没有调整旋钮没有物理设计也没有存储整理任务。 关系型 Snowflake 具有对 ANSI SQL 和 ACID 事务的全面支持。大多数用户能够通过很少或没有更改来迁移现有的工作负载。 半结构化Snowflake提供内置函数和SQL扩展用于遍历、扁平化和嵌套半结构化数据并支持流行的格式如JSON和Avro。自动元数据发现和列存储使对无模式、半结构化数据的操作几乎与普通关系型数据一样快无需用户付出任何努力。 存算分离、平滑地进行扩展不会影响数据可用性或并发查询性能。 高可用Snowflake可以容忍节点、集群甚至整个数据中心的故障。在软件或硬件升级期间不会发生停机。 持久化为防止意外数据丢失而设计的具有额外的安全保护措施克隆、撤销删除以及跨区域备份。 低成本 Snowflake 非常高效且计算资源丰富所有表数据都经过压缩。 用户只需为其实际使用的存储和计算资源付费。 数据可靠性包括临时文件和网络流量都得到了端到端加密。没有用户数据会被暴露给云平台。此外基于角色的访问控制使用户能够在 SQL 层级上对访问进行细粒度的控制。 解读 这一段可以说是snowflake整个设计思想的核心点这里从云数据仓库提供服务的模式、对于标准SQL兼容性、存算分离架构、基于云所带来的容错能力跨可用区、数据安全措施、成本效益这几个方面考虑设计其实从技术角度来看都没有问题唯一的在于成本效益这块在这个段落里是说表被压缩并且存储和计算资源付费但是在后面的内容中整个成本计算方式是按照处理性能的登记来划分的。 Snowflake 目前运行在亚马逊云Amazon Web ServicesAWS上但未来我们可能会将其移植到其他云计算平台上。截至本文撰写时Snowflake 每天处理数百万条查询并为来自不同领域的众多大型和小型组织提供服务。 本文的结构如下。 第 2 节解释了 Snowflake 的关键设计选择存储与计算分离。 第 3 节介绍了由此产生的多集群共享数据架构。 第 4 节突出了不同的特点连续可用性、半结构化和无模式数据、时间旅行和克隆以及端到端的安全性。 第 5 节讨论了相关工作。 第 6 节总结了本文的工作成果并展望了正在进行中的研究。 二、存储与计算 Shared-nothing 架构已经成为高性能数据仓库系统的主要体系结构主要原因有两个可扩展性和商用硬件。在Shared-nothing 架构中每个查询处理节点都有自己的本地磁盘。表是跨节点水平分区的每个节点只负责本地磁盘上的数据行。这种设计非常适合星型模式查询因为只需要很少的带宽就可以将小广播维度表与大分区事实表连接起来。由于对共享数据结构或硬件资源的竞争很小因此不需要昂贵的定制硬件 在Shared-nothing 架构中每个节点都有相同的职责并且运行在相同的硬件上。这种方法导致了优雅的软件易于理解。然而Shared-nothing架构有一个重要的缺点它紧密地耦合计算资源和存储资源在某些情况下会导致问题。 解读 Shared-nothing架构是一种分布式系统中常用的架构模式它将每个节点上的资源都视为独立的不会共享任何资源。这种架构的优点是可以提高系统的可扩展性和容错性但是也会增加通信成本和数据复制的工作量。 Hadoop等大数据相关服务通常是基于Shared-nothing架构设计的。这种架构中每个节点都有自己的本地存储器和计算资源不同的节点之间不会共享数据和硬件资源。这样可以提高系统的可扩展性和容错性并且能够更好地适应大规模分布式环境下的数据处理需求。 而Shared-everything架构则是将所有节点上的资源都共享在一起包括硬件资源和软件资源。这种架构的优点是可以减少通信成本和数据复制的工作量但是会降低系统的可扩展性和容错性。 异构工作负载 硬件配置是一致的但工作负载通常不是。 一个对批量加载高I/O带宽、轻计算最理想的系统配置 对于复杂的查询低IO带宽、重计算来说却并不适用反之亦然。 因此硬件配置需要以较低的平均利用率作为代价。 成员变更 如果节点集合发生变化无论是由于节点故障还是用户选择调整系统大小都需要重新洗牌大量数据。 由于相同的节点负责数据洗牌和查询处理因此可以观察到显着的性能影响限制了可扩展性和可用性。 在线升级 尽管使用复制可以降低小规模成员更改的影响但软件和硬件升级最终会影响系统中的每个节点。在理论上一个接一个地升级节点而不让系统中断是可能的但由于所有东西都紧密结合且期望一致这变得非常困难。 在本地环境这些问题通常是可以容忍的。工作量可能异构但当只有一个很小的、固定的节点池可以运行时人们几乎无能为力。很少对节点进行升级也很少发生节点故障或系统调整大小的情况。 云计算的情况则完全不同。像亚马逊EC2这样的平台有很多不同类型的节点[4]。利用它们只需要把数据带到正确的节点类型即可。与此同时节点故障更加频繁性能差异也会很大即使是在相同类型的节点之间也是如此[45]。因此成员资格的变化并不是例外而是常态。最后实现在线升级和弹性扩展有很强的动力。在线升级可以大大缩短软件开发周期提高可用性。 弹性伸缩进一步提高了可用性并允许用户匹配其当前需求与资源消耗。 出于这些原因和其他原因Snowflake 将存储与计算分离。这两个方面由两个松散耦合、独立可扩展的服务处理。计算通过 Snowflake 的专有共享无关引擎提供。存储通过 Amazon S3 提供但原则上任何类型的 blob 存储库都足够了。为了减少计算节点和存储节点之间的网络流量每个计算节点都在本地磁盘上缓存一些表数据。 这种解决方案的另一个好处是本地磁盘空间没有用于复制整个基础数据集这可能非常大并且大多是冷很少访问。相反本地磁盘专门用于临时数据和缓存两者都是热的建议使用SSD等高性能存储设备。因此一旦缓存变暖性能就会接近甚至超过纯共享无关系统。我们称这种新颖的体系结构为多集群、共享数据架构。 解读 在大数据技术中存储和计算是耦合在一起的并且在节点扩容时要求硬件配置相同管控平台可以设置节点组那这时候就会造成要么存储资源浪费、要么计算资源浪费使得服务器资源使用不均衡。其次在数据节点缩容的时候数据会进行副本之间的同步和迁移对于整个系统稳定性来说是有一定风险的。 对于云上集群来说当节点故障的时候大数据场景下也会出发数据迁移和恢复无论是节点故障、磁盘故障还是网络故障所以对于大数据场景存算一体下的极致的弹性伸缩能力是基本无法做到的。 所以Snowflake通过将存储和计算分离这种松耦合的架构来实现更高效率的弹性和资源利用问题。 三、架构设计 Snowflake 是为大型企业而设计的服务。除了提供高可用性和互操作性外企业就绪意味着高可用性。为此Snowflake 是一个由高度容错且可独立扩展的服务组成的面向服务的架构。这些服务通过 RESTful 接口进行通信并分为三个架构层 解读 Snowflake 是为大型企业而设计的服务从定位上就是为大企业而服务小企业或者小数据量的公司可能都不足以开通资源的费用呢。 数据存储层 使用 Amazon S3 存储表数据和查询结果。 虚拟仓库 系统的“肌肉”。这一层负责在被称为虚拟仓库的弹性虚拟机集群中执行查询。 云服务 系统的大脑。这一层是一组服务用于管理虚拟仓库、查询、交易以及与此相关的所有元数据数据库模式、访问控制信息、加密密钥、使用统计数据等。 解读 从整个架构上分为三层架构分别为数据存储、数据仓库、云服务存储层使用对象存储S3来存储数据在数据仓库层主要做查询解析、资源管控、集群管理等等云服务主要用来做一些元数据相关的维护。 图 1 描述了snowflake架构的三个分层以及它们的主要组件。 3.1数据存储 选择 Amazon Web Services (AWS) 作为 Snowflake 的初始平台原因有二。首先AWS 是云平台市场上最成熟的产品。其次也是与第一点相关AWS 提供了最大的潜在用户群。 接下来的选择是在使用S3还是基于HDFS或类似的东西开发自己的存储服务之间进行选择。 我们花了一些时间来尝试S3发现尽管它的性能可能会有所不同但其可用性、高可用性和强大的持久性保证很难被打破。因此我们决定不再开发自己的存储服务而是将精力投入到虚拟仓库层的本地缓存和倾斜恢复技术中。 解读 从当下时期来说貌似使用对象存储来做这种存算分离架构的技术基本成熟但是回望2012年那时候基于HDFS分布式文件存储技术是如日中天对象存储想对还没有那么领先而且从性能、操作上来说不如文件系统所以说这个选择应该也是经历多了长时间的讨论和抉择的毕竟基于对象存储的选型来说对于K/V这种存储类型是不适用于大数据场景的事实也证明在大数据计算场景下的LIST和RENAME是有极大的瓶颈问题的。所以说如何做和计算和存储之间的数据存储层是整个存算分离技术的核心关键点之一。 与本地存储相比S3 的访问延迟自然要高得多每个 I/O 请求都会产生更高的 CPU 负担尤其是如果使用了 HTTPS 连接。但更重要的是S3 是一个 blob 存储库一个相对简单的基于HTTP(S) 的PUT/GET/DELETE 接口。对象即文件只能被完全重新写入。甚至不能向文件末尾追加数据。实际上在PUT 请求中必须提前声明文件的确切大小。但是S3 支持针对文件的部分ranger的GET 请求。 这些特性对 Snowflake 的表文件格式和并发控制方案产生了很大影响参见第 3.3.2 节。表被水平拆分为大而不可变的文件相当于传统数据库系统中的块或页。在每个文件中每个属性或列的值都被分组并进行高度压缩这是文献[2]中称为 Pax 或混合列存储的一种众所周知的方法。每个表文件都有一个标题除了其他元数据外它还包含文件中每列的偏移量。由于 S3 允许对文件的部分进行 GET 请求查询只需要下载文件头以及它们需要的那些列。 Snowflake 不仅使用 S3 存储表数据还使用 S3 存储查询运算符例如大规模连接生成的临时数据。当本地磁盘空间不足时它会将临时数据写入 S3 以存储大量查询结果。 将临时数据写入 S3 可让系统计算任意大小的查询而不会出现内存或磁盘不足错误。 将查询结果存储在 S3 中可以启用新的客户端交互形式并简化查询处理因为它消除了传统数据库系统中需要的服务端游标。 元数据如目录项、包含哪些S3文件的表、统计信息、锁、事务日志等都存储在可扩展的事务性键值存储中它是云服务层的一部分。 3.2虚拟仓库 虚拟仓库层由 EC2 实例组成。每个这样的集群都通过一个称为虚拟仓库 (VW) 的抽象呈现给单个用户。构成 VW 的单个 EC2 实例称为工作节点。 用户永远不会直接与工作节点交互。实际上用户不知道也不关心哪些工作节点构成了 VW 或者有多少个工作节点。取而代之的是VW 是以抽象的“T 恤尺码”形式提供的从 X 小到 XX 大不等。这种抽象使我们能够独立于底层云平台来发展服务和定价。 解读 虚拟数据仓库可以理解为是一种逻辑上的数据仓库集合在当年2012年的时候容器技术还没有发展起来所以当时设计还是以虚拟机节点来做为计算层这里还有一个关键的两点其实在上面也简单提到了就是成本效益问题。 使用者用户是不知道底层到底有多少个VM节点的用户只是感知到数据库连接地址然后进行读写数据即可。 关于计费计量方面一般Pass平台是按照CPU/Memory有的按照CU来计量单位1CU大概表示1C4G的空间但是在这里是通过更加抽象的逻辑单位来表示的比如X、XL、XXL、XXXL等等不同的XX能够处理的数据量、计算量也不同通常来说是逐步扩大的。
最后一句话也提到了这种定价模式是方便于云数据仓库这种SaaS产品独立于云平台来发展和定价。一般云厂商定价的规则是包年包月、按量付费的逻辑计量的单位是以节点规格来收费的另外加上一些服务费用相对更加透明一些。 但是Snowflake的收费模式就没有那么透明很难解释清楚定价逻辑和规则所以从成本效益上可能会有减少也可能会有增多这要具体看使用者的业务处理方式。 3.2.1弹性和隔离 虚拟机VM是一种纯粹的计算资源。它们可以根据需要在任何时间创建、销毁或调整大小。创建或销毁 VM 不会影响数据库的状态。用户在没有查询时关闭所有 VM 是完全合法的并且受到鼓励。这种灵活性使用户能够根据使用需求动态匹配计算资源而无需考虑数据量。 解读 这段其实是很有料的不知道读者朋友是否对于云计算有所了解一般云上主机虚拟机是有弹性策略的但是对于数据仓库、大数据这种场景主机资源通常是724小时开机状态因为从付费模式上就决定了关机或者不关机没有成本上的缩减。 所以除非是走退订的逻辑将主机进行释放当需要的时候在重新购买然后开机部署使用这种模式需要使用者具备一定的技术能力和门槛国内云厂商注意是国内通常并没有针对大数据场景做这种标准化的处理模式。而且这种模式对与IASS的弹出性能有一定的要求不过幸运的一点在于当下基于Kubernetes的容器化技术的弹性伸缩性能要更快一些如果使用一些高性能的容器管控服务的话秒级别可以弹出几十甚至几百个Pod都是可能的当然这里要依赖很多容器化内核的技术比如镜像预拉取缓存、调度服务、容器运行时、配置管理等等。 每个单独的查询只运行在一个VW上。工作节点不会在多个VW之间共享从而为查询提供了强大的性能隔离。(话虽如此我们认为工作节点共享是未来工作的一个重要领域因为它将为性能隔离不是大问题的用例提供更高的利用率和更低的成本。) 解读 我理解这里的隔离技术指的就是当下Kubernetes的worker和Pod之间的关系显然当下的容器化技术就是提升了资源利用率并且提供了强大的资源隔离策略成本也相比虚拟机有了一定程度的降低。 注意这篇论文是2012年提出的容器化技术大概是在2014年才开始。 当提交一个新查询时每个 VW 工作节点如果优化器检测到小查询则为子集都会产生一个新的工作进程。 每个工作进程只存在一个查询的时间长度内。 即使作为更新语句的一部分单独的工作进程也永远不会对外部可见的影响由于表文件是不可变的参见第3.3.2节。因此工作节点的故障很容易被控制并通过重试来解决。Snowflake目前不支持部分重试因此非常大的、长时间运行的查询是一个需要关注和未来工作的重点。 解读 分布式计算引擎大多是MPP并行计算架构对于单个Task的失败、重试会直接影响整个作业的最终结果成功失败、运行效率的核心因素先从两个方面来说吧。 不可变文件天然优势如果使用Scala写Spark作业的话会发现里面很多算子和函数都是不可变的不可变的好处就在于不用担心数据的变化而重新刷新所有已经计算完成的数据集所以重试、重跑的效率更高一些。 大任务大数据量很容易出现数据热点问题这是所有MPP架构都会遇到的问题例如Shuffle数据、数据倾斜都会导致这种问题的出现所以各种计算引擎都在做数据倾斜方面的优化但是倾斜并不是一个技术上能够完全避免的问题从使用角度业务上来说也需要一定的设计和优化。 每个用户可以同时运行多个虚拟机而每个虚拟机又可以并发执行多个查询。每台虚拟机都可以访问相同的共享表无需实际复制数据。 共享、无限存储意味着用户可以分享和整合他们所有的数据这是数据仓库的核心原则之一。同时用户还可以从私有的计算资源中受益避免不同工作负载和组织单位之间的干扰——这也是数据集市的原因之一。这种弹性和隔离使得一些新的用例策略成为可能。Snowflake用户通常会为来自不同组织单位的查询拥有多个虚拟仓库VW这些查询通常会持续运行并会定期启动按需VW例如用于批量加载。 解读 先说从模式上来讲上面提到对于使用者来说就是购买了XXL的资源对于存储来说是基于对象存储来存储的对象存储的好处就是不需要关心实际存储用量大小可以说一种无限大的存储资源池想要写多少数据都可以并且支持不同等级的冷热分层策略。 其次是说计算资源隔离问题我理解当时的隔离技术可能并不是很成熟更多的可能是未来的一种对于计算资源隔离的“设想”但是从目前的实际来看这种是能够实现的 资源隔离首先要有强大的资源调度引擎可以进行内核级别的资源管控同时对于碎片化的资源例如内存能够充分的利用上。 与弹性相关的另一个重要观察是通常可以以大致相同的价格实现更好的性能。例如在一个具有四个节点的系统上需要 15 小时的数据加载任务可能只需要在拥有32个节点的系统上花费两小时 , 由于每小时计算成本总体成本非常相似——然而用户体验却大不相同。因此我们相信 VW 的伸缩性是 Snow-Flake 架构的最大优势之一并且它表明需要一种新的设计来利用云的独特功能。 解读 这其实就是多角度看待问题的一种方式是选择多节点快速跑完还是选择少节点多时间来跑完并没有好坏之分这里突出的重点在于Snowflake的极致弹性伸缩能力就是说你可以选择快速把资源打满然后快速跑完任务。这是产品本身能够达到的效果换句话说给了用户更多选择的空间体验度上更好一些。毕竟一些紧急的作业是非常需要这种特性支持的。 3.2.2本地缓存与文件窃取 解读 这一节重点解决的应该就是数据存储处理问题上面有提到对象存储是有大数据量计算瓶颈问题的 所以在大数据场景下必然会有很强大的缓存能力才能够做到既高效又经济的作业执行。 每个工作节点都维护本地磁盘上的表数据缓存。缓存是一组表文件即过去由该节点访问过的 S3 对象。具体来说缓存包含文件头和文件中的每一列因为查询只会下载所需的列。 解读 对象存储的优化方案就是尽量减少大批量的访问这样对于访问过的信息元数据可以记录在本地缓存中这样当下次再进行访问时就可以通过本地缓存的元数据信息比如Key的位置直接到GET请求到对应的KEY信息。就不用单独的LIST的方式挨个扫描一遍了这是对于S3等对象的其中一种处理方式。 当下来说很多开源的系统也支持直接链接对象存储元数据缓存和数据缓存例如JuiceFS、Alluxio都可以支持挂载/链接对象存储来实现高效的数据读写。 缓存在工作节点期间存在并在并发和后续工作进程(即查询)之间共享。它只看到一个文件和列请求流并遵循一个简单的最近最少使用(least-recently-used, LRU)替换策略忽略单个查询。这个简单的方案工作得非常好但我们可能会在将来对其进行改进以更好地匹配不同的工作负载。 为了提高命中率并避免在VW的工作节点上对单个表文件进行冗余缓存查询优化器使用表文件名上的一致散列将输入文件集分配给工作节点。因此访问同一表文件的后续或并发查询将在同一工作节点上执行此操作。 解读 在大多数的存算分离架构下的系统来说基本上都会有一致性Hash算法的应用例如Apache Pulsar的Bundle概念这种算法本质上来说就是提供了存算分离场景下的任务均衡调度能力能够充分的将任务进行打散并且根据节点数量的大小可以平滑的进行Hash重调度。 一致散列算法是一种用于分布式系统中的负载均衡算法数据集映射到一个环上每个节点被分配到环上的某个位置然后根据数据集中的元素所对应的环上的位置来确定哪个节点负责处理该元素。这种算法的优点是可以实现平滑的扩容和缩容因为只需要添加或删除少量节点即可重新平衡负载而不需要重新分配整个数据集。此外一致散列还可以减少网络流量和数据复制的数量提高系统的可靠性和可用性。 Snowflake中的一致性哈希是惰性的。当工作节点集合发生变化时由于节点故障或VW调整不会立即进行数据洗牌。相反snowflake依赖LRU缓存淘汰策略最近最少使用策略来最终重新放置缓存内容。这种解决方案将替换缓存内容的成本分摊到多个查询中从而比急切的缓存或纯shared-nothing系统具有更好的可用性后者需要立即在节点之间shuffle大量表数据。它还简化了系统因为没有“降级”模式。 解读 通常来说缓存不是无限大的能够提供缓存的大小是有限的所以基于本地缓存的策略一般是通过时间周期TTL或者LRU算法最近最少使用来实现。 除了缓存之外数据倾斜在云数据仓库中尤为重要。由于虚拟化问题或网络争用某些节点的执行速度可能比其他节点慢得多。在其他地方Snowflake在扫描级别处理这个问题。每当一个工作进程扫描完它的输入文件集它就会从它的对等进程请求额外的文件我们称之为文件窃取技术。如果对等节点发现当这样的请求到达时它的输入文件集中还有许多文件它通过在当前查询的持续时间和范围内转移剩余一个文件的所有权来应答请求。然后请求者直接从S3下载文件而不是从对等节点。这种设计确保了文件窃取不会因为在离散节点上增加额外的负载而使事情变得更糟。 解读 这里说到的数据倾斜就是在上面提到MPP架构里面的痛点本段落里给出的可能是因为节点故障或者网络通信问题其实还有很多很多因素那在对于数据倾斜问题上snowflake的处理方式是 A和B两个进程处理的可能是同一个Stage的数据集A先处理完成了 但是B卡顿了一只没有处理完成那么A会通过RPC请求到B中B会把一部分数据的信息给到A然后A根据这些元数据信息拉取相关数据进行处理那么B就不需要处理这部分数据里了。 3.2.3执行引擎 如果另一个系统可以使用10个这样的节点在相同的时间内执行查询那么能够对超过1000个节点进行查询几乎没有价值。因此虽然可扩展性很重要但每个节点的效率同样重要。我们希望为用户提供市场上任何数据库即服务(Database-as-a-Service)产品中性能/价格比最佳的产品所以我们决定实现自己的最先进的SQL执行引擎。我们构建的引擎是基于列、向量化和push-based。 解读 基于向量化、列式存储的计算引擎是当下很多大数据存储/分析系统近几年才开始做的比如Doris、Starrocks、Spark、CK等向量化能力也是近几年开始实现的但是Snowflake在十几年前就开始通过向量化、列存储来构建自己的计算引擎了。 列存储和执行通常被认为比行存储和执行更适用于分析工作负载因为它更有效地利用了CPU缓存和SIMD指令并提供了更多轻量级压缩的能力 向量化执行意味着与 MapReduce 等方法相比Snowflake 避免了中间结果的物化。相反数据以pipeline方式处理在列存储格式中按数千行一组进行批量处理。这种由 Vectorwise最初为 MonetDB/X100[15]开创的方法节省了 I/O 并极大地提高了缓存效率。 基于Push-based的执行是指关系运算符将它们的结果推送给下游运算符而不是等待这些运算符拉取数据经典的火山模型。 基于推送的执行提高了缓存效率因为它从紧密循环中删除了控制流逻辑。它还使Snowflake能够有效地处理DAG形状的计划而不仅仅是树形结构从而为共享和pipeline中间结果创造了额外的机会。 解读 基于Push-based的执行逻辑在很多计算引擎运算中都有用到如果对于spark shuffle处理机制比较熟悉的话对push-based会更容易理解。在Spark shuffle中通过将数据集划分为多个分区并对每个分区进行排序然后在不同的节点之间交换这些分区的数据最后对所有分区的数据进行合并以生成最终的结果。具体来说就是当一个TaskA需要访问另一个TaskB的输出时该TaskA会向另一个TaskB发送一个请求并且TaskB会在接收到请求后立即将其输出发送回请求方而不是等到下一个轮询周期才发送。这样做的好处是可以减少网络通信的开销并提高任务之间的协作效率。 同时传统查询处理中的许多开销在Snowflake中不存在的。特别是在执行过程中不需要事务管理。就引擎而言查询是针对一组固定的不可变文件执行的。此外没有缓冲池。大多数查询会扫描大量数据。将内存用于表缓冲而不是操作是一个不好的权衡。然而Snowflake允许所有主要操作符join、group by、sort溢出到磁盘并在主内存耗尽时递归。我们发现纯主内存引擎虽然更精简、更快但过于严格无法处理所有有趣的工作负载。分析工作负载可能具有非常大的连接或聚合。 解读 简单可以理解为中间shuffle数据结果落盘内存的容量比磁盘要少很多所以大多数的计算引擎在计算时会将shuffle数据进行落盘处理这个在当下大多数分布式计算引擎中都有相关实现。 3.3云服务 虚拟仓库是短暂的、特定于用户的资源。相比之下云服务层是高度多租户的。该层的每个服务——访问控制、查询优化器、事务管理器等——都是长期存在的并且在许多用户之间共享。多租户改善了利用率减少了管理开销比传统架构中每个用户都拥有完全私有系统实例的情况下实现更好的规模经济。 解读 对于云数据仓库而言是立于云的基础设施之上的对于图一的架构图而言中间的VW数据仓库其实是一种无状态的计算资源是和用于进行绑定的但是在这些资源之上对于租户管理、查询器优化、事务管理是snowflake平台化的一种能力。 每个服务都有副本以实现高可用性和可扩展性。因此单个服务节点的故障不会导致数据丢失或可用性的丧失一些正在运行的查询可能会失败并被重新执行。 3.3.1查询管理与优化 用户发出的所有查询都通过云服务层。在这里处理所有查询生命周期的早期阶段解析、对象识别、访问控制和计划优化。 解读 这里的云服务层更多的是部署在云上的服务这些服务主要作用就是做查询解析的工作生成查询计划以及查询计划优化等等。 Snowflake 的查询优化器遵循典型的 Cascade 级联式风格方法[28]采用自顶向下的基于成本的优化。所有用于优化的统计信息都会在数据加载和更新时自动维护。由于 Snowflake 不使用索引参见第 3.3.3 节因此计划搜索空间比某些其他系统要小。通过将许多决策推迟到执行时间例如连接的数据分布类型可以进一步缩小计划空间。这种设计减少了优化器做出的糟糕决策数量在以微小的性能损失为代价的同时提高了鲁棒性。它还使系统更易于使用性能变得更加可预测这符合Snowflake对服务体验的整体关注度。 解读 这个是对于内部查询引擎所使用的技术相关。当作了解即可毕竟我们也不是做查询器的。 自顶向下的搜索过程中整个搜索空间会形成一个Operator Tree Cascades首先将整个Operator Tree按节点拷贝到一个Memo的数据结构中每个Operator放在一个Group。对于有子节点的Operator来说将原本对Operator的直接引用变成对Group的引用。 一旦优化器完成生成的执行计划就会分发给查询中参与的所有工作节点。随着查询的执行云服务会持续跟踪查询的状态以收集性能计数器并检测节点故障。所有查询信息和统计都用于审计和性能分析。用户可以通过Snowflake图形用户界面监视和分析过去的和正在进行的查询。 3.3.2并发控制 如前所述Snowflake 的并发控制完全由云服务层处理。Snowflake 是为分析工作负载而设计的这些工作负载往往是由大量读取、批量插入或点滴插入以及批量更新。与该工作负载空间中的大多数系统一样我们决定通过快照隔离实现ACID 事务。 在SI下事务读取的所有内容都看到了一个一致的数据库快照该快照是事务开始时的状态。通常情况下SI是建立在多版本并发控制MVCC之上的这意味着每个更改的数据库对象的副本都会被保留一段时间。 解读 这里的SI指的是Snapshot Isolation这里的快照隔离技术是数据库里面用于实现ACID事务的基本原则简单来讲就是通过在每个事务开始的时候创建一个视图这个视图包含了当前事务开始之间所有已经提交事务的信息并且在此之后所有未提交的事务不会影响当前的视图就避免了脏读Dirty Read、不可重复读Non-Repeatable Read和幻读Phantom Read等问题同时也满足了事务的隔离性和持久性要求当事务结束并提交时所有对数据的修改都会被永久保存下来保证了数据的一致性和可靠性 由于表文件是不可变的因此使用S3进行存储的直接结果是MVCC是一种自然的选择。文件的更改只能通过用包含更改的不同文件替换来完成。这意味着对表执行写操作插入、更新、删除、合并会产生一个新版本的表通过相对于先前的表版本添加或删除整个文件来实现。文件的添加和删除在元数据中进行跟踪在全局键值存储中以一种允许计算属于特定表版本的文件集的方式。 解读 S3做为对象存储是不支持文件变更的所以会发现在很多数据湖组件中iceberg、hudi都有版本变更的概念每次在修改一个文件操作时其实是基于一种Copy On Write的思想来重新生成了一个新的文件然后替换掉了之前文件。 这是数据湖组件选择使用对象存储作为数据存储方式所必然要做的选择也就是MVCC多版本控制 除了SI之外Snowflake还使用这些快照来实现时间旅行和数据库对象的高效克隆。有关详细信息请参阅第4.4节。 解读 时间旅行的概念如果现在有接触到数据湖技术的话这个应该是比较清楚的简单来讲就是Snowflake使用快照技术可以在保留一定时间内的历史版本的同时快速恢复到过去的某个时间点或者创建一个完整的备份副本一种跨越时间窗口的数据恢复能力。 3.3.3剪枝 解读 剪枝的实现在OLAP架构中非常的常用通俗来讲就是对查询条件进行过滤避免不必要的计算和扫描从而提高查询性能的一种技术。 其原理是利用多维数据的特点在查询时根据当前维度和度量值的状态预测出下一步需要计算的数据并且只计算必要的部分而不是全部计算。这样可以大大减少计算时间和内存消耗提高查询速度和效率。具体实现方法包括前缀剪枝、后缀剪枝、中间状态剪枝等多种策略。 将访问权限限制在与给定查询相关的数据上是查询处理中最重要的方面之一。通常来讲通过使用B树或类似的数据结构来限制数据库中的数据访问。虽然这种方法对于事务处理非常有效但对于像Snowflake这样的系统它会引发多个问题。首先它严重依赖于随机访问这是由于存储介质S3和数据格式压缩文件的问题。其次维护索引会显著增加数据量和数据加载时间。最后用户需要明确地创建索引这将与Snowflake的纯服务方法非常不符。即使在调优的帮助下维护索引也可能是一个复杂、昂贵和风险高的过程。 最近一种新的技术在大规模数据处理中变得流行基于最小最大值的剪枝也称为小量聚合、区域映射和跳读。在这种情况下系统维护给定数据块记录集、文件、块等的数据分布信息特别是该块中的最小值和最大值。根据查询谓词这些值可以用来确定给定查询是否需要给定的数据块。例如假设文件f1和f2包含列x的值分别为3..5和4..6。那么如果查询有一个谓词WHERE x 6则我们知道只需要访问f2。与传统索引不同这种元数据通常比实际数据小几个数量级导致存储开销小并且访问速度快。 剪枝很好地符合snowflake设计原则它不依赖于用户输入它能够扩展并且易于维护。此外对于大量数据的顺序访问它的效果很好并且在加载、查询优化和执行时间方面几乎没有开销。 Snowflake 会为每个实例保留与剪枝相关的元数据。单个表文件。元数据不仅包括普通的关联列还包括半结构化数据中自动检测到的一些列如第 4.3.2 节所述。在优化过程中会使用查询谓词来检查元数据以减少或剪枝输入文件集以执行查询。优化程序不仅针对简单的基值谓词进行剪枝还针对更复杂的表达式进行剪枝例如WEEKDAYorderdateIN6、7。 除了静态剪枝之外Snowflake 还在执行过程中进行动态剪枝。例如在作为哈希连接处理的一部分时Snowflake 会收集构建侧记录中连接键分布的统计信息。然后这些信息会被推送到探查侧并用于过滤以及可能跳过探查侧上的整个文件。除此之外还有其他众所周知的技术如 Bloom Join [40]。 四、特色功能和亮点 Snowflake 提供了许多预期从关系型数据仓库获得的功能全面的 SQL 支持、ACID 事务、标准接口、稳定性与安全性、客户支持以及、当然、强大的性能和可扩展性。此外它还引入了一些其他功能这些功能在相关系统中很少见到或者从未见过。本节介绍一些我们认为是技术差异化的功能。 解读 目前这些功能和特性基本上像hudi、iceberg的数据湖组件都支持的而且基于SaaS化的商业化企业也有很多。 所以本节从当下来看并没有什么特别的地方主要就是Web的可视化访问支持Ad-hoc功能可视化的数据库表管理、用户权限控制基于数据库的、监控、查询用量等等。 4.1纯SaaS化体验 Snowflake 支持标准数据库接口JDBC、ODBC、Python PEP-0249并与诸如Tableau、Informatica或Looker等第三方工具和服务集成。然而它还提供了仅使用网络浏览器与系统交互的可能性。web 界面似乎是一件小事但它很快证明了它是关键差异因素。Web 界面使从任何位置和环境访问 Snowflake 非常容易并大大减少了启动和使用系统的复杂性。由于大量数据已经存储在云中它使得许多用户可以指向他们的数据并查询而无需下载任何软件。 不出所料UI 不仅支持 SQL 操作还提供了数据库目录、用户和系统管理、监控、使用信息等。我们不断扩展 UI 功能专注于在线协作、用户反馈和支持等方面的工作。 但我们在易用性和用户体验上的关注并不局限于用户界面它延伸到系统架构的方方面面。没有失败模式也没有调优旋钮、物理设计或存储优化任务。这一切都是关于数据和查询。 4.2持续可用性 过去数据仓库解决方案是深藏不露的后端系统与世隔绝。在这样的环境中计划内软件升级或管理任务和非计划内故障停机时间通常不会对运营产生重大影响。但随着数据分析越来越多地成为业务任务的关键部分任何数据仓库都必须保持持续可用性。这一趋势反映了现代SaaS系统的期望它们大多都是始终运行、面向客户的应用程序并且没有计划内的停机时间。 “Snowflake提供符合这些期望的持续可用性。在这方面的两个主要技术特点是故障容错和在线升级。 4.2.1故障恢复 图 2 展示了 Snowflake 架构中各层对节点故障的容忍程度。目前Snowflake 的数据存储层使用的是 Amazon S3S3 在多个数据中心称为“可用区”或 AZ之间进行复制。在 AZ 之间的复制允许 S3 承受整个 AZ 故障并保证 99.99%的数据可访问性和 99.999999999% 的持久性。与 S3 架构相匹配Snowflake 的元数据存储也是分布式且在多个 AZ 之间进行复制。如果一个节点出现故障其他节点可以继续处理工作而不会给终端用户带来很大影响。云服务层的剩余服务由多个 AZ 中的无状态节点组成负载均衡器在它们之间分配用户请求。因此单个节点故障甚至整个 AZ 故障都不会对系统产生整体影响只是可能会导致当前连接到故障节点上的用户查询失败。这些用户将在下一个查询时被重定向到不同的节点。 解读 这块可以稍加的解释一下如果使用云计算比较熟悉的话会了解云是区分不同Region和不同AZ的availability zonesRegion往往指的是地域比如北京地域就是北京region、杭州一般就是杭州region、上海就是上海region然后在不同的region下面区分不同的可用区简称为AZ可用区也可以理解为是在不同的region下的不同机房如果北京可能有万国机房、UCloud机房、亦庄电信机房等等那么这些就是不同region下的不同可用区的分区。 容错性为什么一定要考虑使用不同的AZ呢不同AZ也就是要多机房部署的概念这样当某个机房出现问题的时候另外一个机房所部署的服务就可以来承接业务不至于业务出现中断。 一般而言云上的服务都是多AZ来部署的比如RDS、Redis等等都是支持跨AZ来部署所以从段落里重点标记的内容也说明了这一点。 相比之下虚拟仓库VW不分布在多个区域。出于性能考虑而做出此选择。分布式查询执行需要高网络吞吐量而同一区域内的网络吞吐量显著更高。如果在查询执行过程中其中一个工作节点出现故障查询会失败但会自动重新运行要么立即替换节点要么暂时减少节点数量。为了加快节点替换速度Snowflake 维护了一个备用节点的小池子。这些节点也用于快速提供 VW。 解读 上面提到数据存储和元数据是跨AZ存储的但是VW是部署在单AZ的为什么文中给出的是出于性能考虑分布式查询需要高网络吞吐而跨AZ之间并不是同一个机房内网通信需要通过专线进行链接。所以网络延迟相对会比较高具体要看不同AZ之间距离。 那么VW容错怎么来保证呢首先VW的功能是什么上面有提到负责查询计划解析、执行等它是一种纯粹的计算资源计算资源是一种无状态的即便是失败了重试之后也可以在另外一个AZ中进行重新执行。 所以从整个架构上来看SQL作业首先会进入到云服务中云服务会根据元数据信息将作业调度到就近的机房中。 如果整个AZ不可用那么在该AZ中运行的所有查询都会失败用户需要主动在另一个AZ中重新配置vw。由于全AZ故障确实是真正灾难性的、非常罕见的事件我们今天接受这种部分系统不可用的情况但希望在未来解决这个问题。 4.2.2在线升级 Snowflake 不仅在故障发生时提供持续可用性而且在软件升级期间也是如此。系统设计允许多个版本的各种服务并存部署包括云服务组件和虚拟仓库。所有服务都是无状态的这使得这一点成为可能。所有的硬状态都保存在一个事务性的键值存储中并且可以通过一个映射层来处理元数据版本控制和模式演变。每当我们更改元数据模式时我们都会确保与旧版本兼容。 解读 下面对于在线升级讲的比较清楚了而且常用的在线升级方式就是多版本共存新旧感知和业务逐步切换的方式 为了执行软件升级Snowflake 首先并行部署新版本的服务与旧版本。然后逐步切换用户帐户到新版本在此期间每个用户的任何新查询都会被重定向到新版本。所有针对旧版本正在运行的查询都可以完成。一旦所有的查询和用户都完成了对旧版本的使用该版本的所有服务都将终止和退役。 图3显示了正在进行升级过程的快照。有两个版本的Snowflake并排运行分别是版本1浅色和版本2深色。Cloud Services 的一个实例有两个版本每个版本控制两个虚拟仓库 (VW)每个版本也有两个版本。负载均衡器将传入呼叫路由到适当版本的Cloud Services。单个版本的Cloud Services 只与匹配版本的VW通信。 如前所述云服务的两个版本共享相同的元数据存储库。此外不同版本的虚拟机可以共享相同的 worker 节点及其各自的缓存。因此在升级后无需重新填充缓存。整个过程对用户来说是透明的不会发生停机或性能下降的情况。 在线升级对我们的发展速度产生了巨大的影响也影响了我们如何处理 Snowflake 中的关键错误。截至撰写本文时我们每周都会对所有服务进行一次升级。这意味着我们每周都会发布新功能并改进现有功能。为了确保升级过程顺利升级和降级都在 Snowflake 的特殊预生产版本中持续进行测试。在这些罕见的情况下如果我们在生产版中发现了关键错误不一定是在升级期间我们可以快速降级到之前的版本或者实施修复并通过计划外升级来完成。这个过程并不像听起来那么可怕因为我们一直在测试和锻炼升级/降级机制。它现在已经高度自动化并且经过强化。 4.3半结构化数据和无模式数据 解读 半结构化数据是指具有部分结构的数据通常包含标签或字段名但不完全符合传统关系型数据库中的表格式结构。而无模式数据则是指没有预定义的数据结构可以是任意形式的数据如文本、图像、音频等。在 Snowflake 中半结构化数据可以通过 VARIANT 类型进行存储和处理而无模式数据则需要通过外部工具或程序进行导入和转换。 很多NoSQL 数据库有个共同点那就是它们都没有模式。若要在关系型数据库中存储数据首先必须定义“模式”也就是用一种预定义结构向数据库说明要有哪些表格表中有哪些列每一列都存放何种类型的数据。必须先定义好模式然后才能存放数据。 相比之下NoSQL 数据库的数据存储就比较随意了。“键值数据库”可以把任何数据存放在一个“键”的名下。“文档数据库”实际上也如此因为它对所存储的文档结构没有限制。在列族数据库中任意列里面都可以随意存放数据。你可以在图数据库中新增边也可以随意向节点和边中添加属性。 Snowflake 在标准 SQL 类型系统的基础上增加了三种半结构化数据类型VARIANT、ARRAY 和 OBJECT。VARIANT 类型的值可以存储任何原生 SQL 类型如 DATE、VARCHAR 等的值以及可变长度的 ARRAY 数组以及类似 JavaScript 的 OBJECT 对象它是从字符串到 VARIANT 值的映射。后者在文献中也被称为文档从而产生了文档存储的概念 数组和对象只是变体类型的限制。内部表示法是一样的自我描述、紧凑的二进制序列化支持快速的键值对查找以及高效的类型测试、比较和哈希。因此可以像使用其他列一样将变体列用作连接键、分组键和排序键。 VARIANT 类型允许 Snowflake 以一种与传统 ETL提取 - 转换 - 加载相反的方式进行操作即 ELT提取 - 加载 - 转换。不需要指定文档模式或对加载数据进行转换。用户可以直接将输入数据从 JSON、Avro 或 XML 格式加载到 VARIANT 列中Snowflake 处理解析和类型推断参见第 4.3.3 节。这种方法在文献中被恰当地称为“延迟模式”它通过解耦信息生产者和信息消费者以及任何中介来实现模式演变。相比之下在传统的 ETL 管道中如果数据模式有任何更改则需要组织内的多个部门协调这可能需要数月才能完成。 ELT 和 Snowflake 的另一个优势是如果需要进行转换可以使用并行 SQL 数据库的全部功能来实现包括连接、排序、聚合、复杂谓词等操作这些在传统的 ETL 工具链中通常缺失或效率低下。在这方面Snowflake 还支持具有完整 JavaScript 语法和变体数据类型集成的用户定义过程UDF。对过程 UDF 的支持进一步增加了可以推入 Snowflake 的 ETL 任务数量。 4.3.1后关系操作Post-relational Operations 文档上最重要的操作是从数据元素中提取通过字段名对于 对象或偏移量对于 数组。Snowflake 提供了在功能 SQL 表示法 和 JavaScript 风格路径语法 中执行提取的操作。内部编码使得提取非常高效。子元素只是父元素中的一个指针不需要复制。通常会将提取结果转换为标准 SQL 类型的 VARIANT 值。再次强调这种编码方式使这些转换变得非常高效。 第二种常见的操作是扁平化即把嵌套文档转换为多行。Snowflake 使用 SQL 侧视图来表示扁平化操作。这种扁平化可以递归进行从而完全将文档的层次结构转换为一个适合 SQL 处理的关系表。与扁平化相反的操作是聚合。为了实现这一点Snowflake 引入了一些新的聚合和分析函数如 ARRAY_AGG 和 OBJECT_AGG。 解读 Post-relational Operations 是一种针对半结构化数据的操作方法它比传统的基于关系模型的数据库操作更为灵活和适应性强。具体来说Post-relational Operations 包括以下几个方面 提取数据元素通过路径表达式或者 JavaScript 类似的语法来提取半结构化数据中的特定字段或者子元素。 扁平化将嵌套的数据结构转化为平面表使得数据更容易被查询和分析。 聚合对半结构化数据进行聚合操作例如 ARRAY_AGG 和 OBJECT_AGG 等函数以便更好地进行数据分析和统计。 4.3.2列存储与处理 将半结构化数据使用序列化二进制表示整合到关系型数据库中是一种常规的设计选择。不幸的是行式表示法使得存储和处理此类数据的效率低于列式关系数据这也是将半结构化数据转换为普通关系数据的原因。 Cloudera Impala 21 和Google Dremel 34 已经证明了半结构化数据的列式存储是可能且有益的。然而Impala 和 Dremel以及其外部化的 BigQuery 44要求用户为列式存储提供完整的表模式。为了实现无模式序列化表示的灵活性和列式关系数据库的性能Snowflake 提出了一种用于类型推断和列式存储的新自动化方法。 如第 3.1 节所述Snowflake 将数据存储为混合列式格式。当存储半结构化数据时系统会自动对单个表文件中的文档集合进行统计分析以自动推断类型并确定哪些带类型的路径经常出现。然后从文档中删除相应的列并使用与原生关系型数据相同的压缩列式格式单独存储。对于这些列Snowflake 还计算了用于剪枝的显式聚合值参见第 3.3.3 节就像普通的关系型数据一样。 在扫描过程中可以将各种列重新组装为单个VARIANT列。然而大多数查询只对原始文档中的一组列感兴趣。在这种情况下Snowflake 将投影和转换表达式推入到扫描操作符中以便仅访问必要的列并直接转换为目标 SQL 类型。 上述优化在每个表文件中独立执行即使在架构演变期间也能实现高效的存储和提取。然而这确实带来了查询优化方面的挑战特别是剪枝。假设一个查询有一个基于路径表达式的谓词并且我们想使用剪枝来限制要扫描的文件集。路径及其对应的列可能出现在大多数文件中但只有足够的频繁出现才需要元数据出现在一些文件中。保守的做法是对所有没有适当元数据的文件进行扫描。Snowflake 通过计算文档中存在的所有路径不是值上的布隆过滤器来改进此解决方案。这些布隆过滤器与其它文件元数据一起保存并在剪枝过程中由查询优化器探测。不需要给定查询所需的路径的表文件可以安全地跳过。 4.3.3乐观转换 由于一些原生的 SQL 类型尤其是日期/时间值在常见的外部格式如 JSON 或 XML中表示为字符串因此这些值需要在写入时插入或更新期间或读取时查询期间从字符串转换为其实际类型。如果没有类型化的模式或等效的提示这些字符串转换需要在读取时进行这比写入时一次转换效率低在读取主导的工作负载中。无类型的另一个问题是缺乏适当的元数据来进行剪枝这对于日期尤其重要。分析工作负载经常对日期列具有范围谓词。 但是如果在写入时应用则自动转换可能会丢失信息。例如一个字段可能包含数字产品标识符但实际上它可能不是一个数字而是一个带有显著前导零的字符串。类似地看起来像日期的内容实际上可能是短信的内容。Snowflake 通过执行乐观的数据转换来解决这个问题并将转换结果与原始字符串除非存在完全可逆的转换分开存储在不同的列中。如果稍后查询需要原始字符串则可以轻松检索或重建。由于未使用的列不会加载和访问因此对查询性能的影响很小。 4.3.4性能 为了评估列存储、乐观转换和修剪对半结构化数据查询性能的影响我们使用类似于TPC-H4的数据和查询进行了一组实验。 我们创建了两种类型的数据库模式。第一种是传统的关系型TPC-H模式。第二种是“无模式”数据库模式其中每个表都由一个类型为VARIANT的单列组成。然后我们生成了聚集排序的SF100和SF1000数据集分别为100 GB和1 TB将数据集以纯JSON格式存储即日期变为字符串并使用关系和无模式数据库模式将数据加载到Snowflake中。没有给系统任何关于无模式数据的字段、类型和聚类的提示并且没有进行任何其他调整。然后我们在无模式数据库上定义了一些视图以便能够对所有四个数据库运行完全相同的TPC-H查询。在撰写本文时Snowflake不使用视图进行类型推断或其他优化因此这纯粹是一种语法上的便利。 最后我们在使用中等规模的标准仓库5上对这四个数据库中的所有22个TPC-H查询进行了测试。图4显示了结果。通过三次热缓存运行获得的结果数字不显著因此从结果中省略。 如上所述除了两个查询在SF1000上的Q9和Q17之外无模式存储和处理查询的开销约为所有查询的10。对于这两个查询我们确定了导致性能下降的原因是不理想的数据估计中的唯一值估计已知错误。我们继续改进半结构化数据的元数据收集和查询优化。 简而言之对于具有相对稳定且简单的模式即在实践中发现的大多数机器生成的数据的半结构化数据的查询性能几乎与传统关系型数据的性能相当同时享受列存储、列式执行和剪枝的所有好处——而无需用户付出努力。 4.4时间旅行与克隆 在第 3.3.2 节中我们讨论了如何在多版本并发控制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-605);– 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 的分层密钥模型。[12] 加密密钥会自动进行旋转并重新加密“重置密钥”以确保密钥完成完整的 NIST 800-57 密码密钥管理生命周期。[13] 加密和密钥管理对用户来说完全透明无需配置或管理。 snowflake密钥层次结构如图 5 所示包含四级根密钥、账户密钥、表密钥和文件密钥。每一层父密钥加密封装其下一层子密钥。每个账户密钥对应一个用户帐户每个表密钥对应一个数据库表每个文件密钥对应一个表文件。 分层密钥模型是一种很好的安全做法因为它限制了每个密钥保护的数据量。如图 5 中的方框所示每一层都减少了其下方密钥的范围。Snowflake 的分层密钥模型在多租户架构中确保用户数据的隔离因为每个用户帐户都有一个单独的帐户密钥。 4.5.2 关键生命周期 除了限制每个密钥保护的数据量外Snowflake 还会限制密钥的有效时间。密钥有四个有效阶段 阶段: (1) 一个预操作创建阶段(2) 一个操作阶段在这个阶段中使用密钥进行加密发起者使用期和解密接收者使用期(3) 一个后操作阶段在这个阶段中密钥不再被使用以及(4) 一个销毁阶段。第1、3和4个阶段很容易实现。第2步需要限制发起者使用期和接收者使用期。只有当密钥不再对任何必要的数据进行加密时才能进入第3和第4阶段。Snowflake 使用密钥轮换来限制发起者使用期并使用重新配钥来限制接收者使用期。 密钥轮换会在固定间隔例如一个月内创建密钥的新版本。每次这样的间隔之后都会生成一个新版本的密钥并且“退役”前一版本的密钥。退役版本仍然可以使用但只能用来解密数据。在加密层次结构中的新子密钥或写入表时仅会使用最新、活动的密钥版本来加密数据。 重新加密 是使用新密钥对旧数据进行重新加密的过程。在特定的时间间隔例如一年之后用过时密钥加密的数据会使用活动密钥重新加密。这种 重新加密 和 密钥轮换 正好相反。当密钥轮换确保密钥从活动状态源使用过渡到退役状态接收者使用时重新加密确保密钥可以从退役状态过渡到销毁。 图6显示了一个单表键的生命周。假设密钥每个月旋转一次每年重新加盐一次。表文件1和2于2014年4月使用k1v1创建。在2014年5月k1被升级到k1v2并且使用k1v2创建了表文件3。在2014年6月k1再次升级为k1v3并且创建了另外两个表文件。自2014年6月以来不再向表中插入或更新任何数据。在2015年4月k1v1过期一年并需要销毁。一个新的密钥k2v1被创建并且所有与k1v1相关的文件都使用k2v1重新加密。在2015年5月相同的过程发生在k1v2上表文件3使用k2v2重新加密。在2015年6月表文件4和5使用k2v3重新加密。 实现了账户密钥和表密钥之间以及根密钥和账户密钥之间的类比方案。密钥层次结构的每个级别都要进行密钥轮换和重新加密包括根密钥。账户密钥和根密钥的密钥轮换和重新加密不需要重新加密文件。只需要重新加密下一级别的密钥。 然而表键和文件键之间的关系是不同的。文件键并不是由表键包装的。相反文件键是从表键和唯一的文件名中派生出来的。因此每当表键发生变化时所有相关的文件键都会发生变化所以受影响的表文件需要重新加密。然而派生密钥的主要好处是消除了创建、管理和传递单个文件密钥的需求。否则像 Snowflake 这样的系统必须处理数十亿个文件的数吉字节的文件密钥。 我们之所以选择这种设计是因为 Snowflake 的存储与计算分离允许它在不影响用户工作负载的情况下进行重新加密。重置密钥的工作是在后台进行的使用不同于查询的不同的工作者节点。在文件重置密钥后Snowflake 会原子更新数据库表的元数据以指向新加密的文件。一旦所有正在进行的查询完成旧文件就会被删除。 4.5.3 完整性保护 Snowflake 使用 AWS CloudHSM 作为防篡改、高安全的方法来生成、存储和使用密钥层次结构中的根密钥。AWS CloudHSM 是一套连接到 AWS 虚拟私有集群 (VPC) 的硬件安全模块 (HSM)。根密钥从未离开过 HSM 设备。所有使用根密钥进行的加密操作都在 HSM 内部执行。因此如果没有获得对 HSM 设备的授权访问则无法解密较低级别的密钥。HSM 还用于在帐户和表级别生成密钥包括在密钥轮换和重新键入期间。我们配置了 AWS CloudHSM 高可用性配置以降低服务中断的可能性。 除了数据加密之外Snowflake 还通过以下方式保护用户的数据 通过S3访问策略隔离存储。 在用户帐户中使用基于角色的访问控制以对数据库对象进行细粒度访问控制。 从云端提供商亚马逊处导入和导出加密数据而云端提供商永远不会看到明文。 为安全访问控制提供双因素认证和联邦身份验证。
简而言之Snowflake 提供了基于 AWS CloudHSM 的分层密钥模型并使用密钥轮换和重新键入来确保加密密钥遵循标准化生命周期。密钥管理完全透明于用户无需配置、管理和停机时间。它是全面安全策略的一部分可实现端到端加密和安全性。 五、 相关工作 基于云的并行数据库系统。亚马逊拥有多个DBaaS产品其中Amazon Redshift是这些产品中的数据仓库产品。Redshift起源于并行数据库系统ParAccel可以说是第一个真正的作为服务提供的数据仓库系统。Redshift使用经典的shared-nothing 架构。因此虽然可扩展但添加或删除计算资源需要进行数据重新分配。相比之下Snowflake的多集群、共享数据架构允许用户独立于存储即时扩展、缩小或暂停计算而无需进行数据移动包括跨隔离计算资源集成数据的能力此外Snowflake遵循纯服务原则无需用户进行物理调整、数据整理、手动收集表统计信息或表格清理。虽然Redshift可以将半结构化数据如JSON作为VARCHAR导入但Snowflake具有半结构化数据的本地支持包括重要的优化如列存储。 谷歌云平台提供了一个称为 BigQuery[44] 的全托管查询服务它是 Dremel[34] 的公共实现。BigQuery 服务允许用户以惊人的速度在数千个节点上并行处理数TB的数据。Snowflake 受到启发的原因之一是 BigQuery 对 JSON 和嵌套数据的支持我们发现这对于现代分析平台至关重要。但是虽然 BigQuery 提供了一种类似 SQL 的语言但它与 ANSI SQL 语法和语义存在一些基本差异这使得它难以与其他基于 SQL 的产品一起使用。此外BigQuery 表只读写需要模式定义。相比之下Snowflake 提供了完整的 DML插入、更新、删除、合并操作ACID 事务并且不需要模式定义即可处理半结构化数据。 Azure SQL 数据仓库 (Azure SQL DW) 是基于 SQL Server 和其分析平台系统 (APS) 设备的 Azure 云平台及服务的最新加入[35][37]。与 Snowflake 相似它分离了存储和计算。通过数据仓库单位 (DWU) 可以扩展计算资源。然而并发度有限制。对于任何数据仓库同时执行查询的最大数量为32[47]。相比之下Snowflake 允许通过虚拟仓库对并发工作负载进行完全独立的扩展。Snowflake 用户也不必再为选择合适的分布键和其他管理任务而烦恼。虽然 Azure SQL DW 支持通过 PolyBase[24] 对非关系型数据执行查询但它没有像 Snowflake 的 VARIANT 类型及其相关优化那样内置支持半结构化数据的功能。 文档存储与大数据。近年来MongoDB[39]、Couchbase Server[23] 和 Apache Cassandra[6] 等文档存储在应用程序开发人员中变得越来越受欢迎因为它们提供了可扩展性、简单性和模式灵活性。然而由于这些系统简单的键值对和 CRUD创建、读取、更新和删除API表达更复杂的查询是一项挑战。为此我们看到了诸如 Couchbase 的 N1QL[22] 或 Apache Cassandra 的 CQL[19] 等多个类似 SQL 的查询语言的出现。此外Apache Hive[9]、Apache Spark[11]、Apache Drill[7]、Cloudera Impala[21] 和 Facebook Presto[43] 等许多“大数据”引擎现在支持嵌套数据上的查询。我们认为这表明了对针对无模式或半结构化数据进行复杂分析的实际需求而我们的半结构化数据支持受到了其中许多系统的启发。通过使用模式推断、乐观转换和列式存储Snowflake 将这些系统的灵活性与关系型数据库的存储效率和执行速度结合了起来。 六、 学到的经验和展望 当Snowflake于2012年成立时数据库世界完全专注于Hadoop上的SQL短短时间内出现了十几个系统。当时在一个完全不同的方向上工作构建一个“经典”的云数据仓库系统的决定似乎是反潮流和冒险的举动。经过三年的发展我们相信这是正确的选择。Hadoop并没有取代关系型数据库管理系统它只是补充了它们。人们仍然想要一个关系型数据库但更高效、灵活并且更适合云计算。 解读 不得不说大数据技术的发展是应用了分布式技术支持大批量数据的计算和存储工作并不是完全颠覆式的存在而snowflake这种云数据仓库的思路是依赖于云计算的崛起在云能力之上补充了数据结构的不足以及成本效益的考虑下所作出的创新式技术。 Snowflake 满足了我们对云原生系统为用户和开发者提供的期望。多集群共享数据架构的弹性能改变用户处理数据任务的方式。SaaS 模式不仅使用户能够轻松试用和采用该系统而且极大地帮助了我们的开发和测试工作。通过一个单一的生产版本和在线升级我们可以更快地发布新功能、提供改进并修复问题这比传统的开发模式要快得多。 虽然我们希望半结构化扩展会有所帮助但我们对采用的速度感到惊讶。我们发现了一个非常流行的模型组织使用Hadoop来完成两件事一是存储JSON二是将其转换为可以加载到RDBMS中的格式。通过提供一个系统该系统能够高效地存储和处理非结构化数据——并且具有强大的SQL界面——我们发现Snowflake 不仅取代了传统的数据库系统还取代了Hadoop集群。 解读 目前来看近几年数据湖技术开始流行也正是验证了snowflake当初的设想某种意义上是能够替代Hadoop集群的。无论是从成本还是组件兼容性都可以做到Hadoop集群更好的实现。 当然这并不是一帆风顺的旅程。虽然我们的团队拥有超过100年的数据库开发经验但我们在路上还是犯了一些可以避免的错误包括对一些关系运算符过于简单的早期实现、没有在引擎一开始就包含所有数据类型、没有及早关注资源管理、推迟了全面日期/时间功能等。此外我们持续专注于避免调整旋钮也带来了一系列工程挑战最终带来了许多令人兴奋的技术解决方案。因此今天Snowflake 只有一个调优参数用户想要多少性能并愿意为之付费。 虽然Snowflake的性能已经非常有竞争力尤其是考虑到不需要调优方面但我们知道还有很多优化工作我们还没有时间去做。然而有点出乎意料的是核心性能几乎从未成为我们的用户的问题。这是因为虚拟仓库提供的弹性计算可以偶尔提供所需的性能提升。这让我们把开发重点放在了系统其他方面。 我们面临的最大技术挑战与该系统的 SaaS 和多租户方面有关。构建一个可以支持数百个用户并发访问的元数据层是一项非常具有挑战性和复杂性的任务。处理各种类型的节点故障、网络故障和支持服务是一场永无止境的战斗。安全一直是个大问题而且还会继续存在保护系统和用户的数据免受外部攻击、用户本身以及内部用户的侵害。维护一个由数百个节点组成的在线系统每天运行数百万次查询虽然会带来很多满足感但需要高度集成的方法来开发、运维和支持。 Snowflake用户继续向系统提出越来越大的、越来越复杂的问题影响着它的演变。我们目前正在通过提供额外的元数据结构和数据重组任务来改善对数据的访问性能重点是最小化或无用户交互。我们继续改进和扩展核心查询处理功能包括标准 SQL 和半关系型扩展。我们计划进一步提高倾斜处理和负载平衡策略随着我们的用户工作量的增加它们的重要性也在增加。我们致力于简化工作负载管理使系统更具弹性。我们还致力于与外部系统集成包括高频数据加载等问题。 Snowflake 面临的最大未来挑战是向完全自助模式过渡用户可以在任何阶段注册并与系统交互而无需我们的参与。这将带来许多安全、性能和支持方面的挑战。我们期待着这些挑战。 七、 致谢 Snowflake是太多人的作品无法在此列出。我们要感谢整个Snowflake工程团队对产品的贡献以及他们为此付出的辛勤工作、努力和自豪。我们还要感谢所有其他“Snowflakes”感谢他们出色的完成了这项工作将这款产品带给用户并一起打造一家伟大的公司。与这样优秀的团队共事我们感到无比荣幸和谦卑。