Presto:Facebook的分布式SQL查询引擎
英文原文: Martin Traverso (Facebook)
背景
Facebook 是一家数据驱动的公司。 数据处理和分析是 Facebook 为 10 亿多活跃用户开发和交付产品的核心所在。 我门拥有世界上最大的数据仓库之一,存储了大约 300PB 以上的数据。 这些数据被一系列不同种类的程序所使用, 包括传统的数据批处理程序、基于图论的数据分析[1]、机器学习、和实时性的数据分析。
分析人员、数据科学家和工程师需要处理数据、分析数据、不断地改善我们的产品, 对于这些人来说, 提高数据仓库的查询性能是非常重要的。在一定时间内能够运行更多的查询并且能够更快地获得查询结果能够提高他们的工作效率。
Facebook 数据仓库中的数据存储在几个大型的 Hadoop HDFS 的集群上。 Hadoop MapReduce[2]和 Hive 被设计为用于进行大规模、高可靠性的计算,而且这些技术都被优化为用来提高整体系统的吞吐量。但是当我们的数据仓库增长到 PB 级别,并且我们的需求进一步提升的时候, 我们就非常需要一个在数据仓库上工作的,能够提供低延迟的交互式查询系统。
在 2012 年秋天,Facebook 数据基础设施(Data Infrastructure)部门的一支团队开始为我们的数据仓库的用户解决这个问题。我们评估了一些外部项目, 发现这些项目或者是太不成熟,或者就是不能满足我们在灵活性和规模性上的要求。 所以我们决定开始搭建 Presto,一个崭新的能够在 PB 级别的数据上进行交互式查询的系统。
在这篇文章中,我们将简单地介绍 Presto 的架构、现状和前景。
架构
Presto 是一个分布式 SQL 查询引擎, 它被设计为用来专门进行高速、实时的数据分析。它支持标准的 ANSI SQL,包括复杂查询、聚合(aggregation)、连接(join)和窗口函数(window functions)。
下面的架构图中展现了简化的 Presto 系统架构。客户端(client)将 SQL 查询发送到 Presto 的协调员(coordinator)。协调员会进行语法检查、分析和规划查询计划。计划员(scheduler)将执行的管道组合在一起, 将任务分配给那些里数据最近的节点,然后监控执行过程。 客户端从输出段中将数据取出, 这些数据是从更底层的处理段中依次取出的。
Presto 的运行模型和 Hive 或 MapReduce 有着本质的区别。Hive 将查询翻译成多阶段的 MapReduce 任务, 一个接着一个地运行。 每一个任务从磁盘上读取输入数据并且将中间结果输出到磁盘上。 然而 Presto 引擎没有使用 MapReduce。它使用了一个定制的查询和执行引擎和响应的操作符来支持 SQL 的语法。除了改进的调度算法之外, 所有的数据处理都是在内存中进行的。 不同的处理端通过网络组成处理的流水线。 这样会避免不必要的磁盘读写和额外的延迟。 这种流水线式的执行模型会在同一时间运行多个数据处理段, 一旦数据可用的时候就会将数据从一个处理段传入到下一个处理段。 这样的方式会大大的减少各种查询的端到端响应时间。
Presto 系统是用 Java 来实现的, 主要原因是 Java 的开发效率高,且拥有非常好的生态环境, 并且很容易同 Facebook 数据基础设施的其他 Java 应用进行集成。Presto 会将查询计划中的一部分动态地编译成 JVM 字节代码,并让 JVM 优化和生成原生的机器代码。 通过谨慎地使用内存和数据结构,Presto 避免了通常 Java 程序会碰到的内存分配和垃圾收集(Java garbage collection)的问题。(在后一篇文章中, 我们会分享一些在开发高性能 Java 系统的时候的一些提示和技巧,以及我们在搭建 Presto 系统时的一些经验教训。)
扩展性是在设计 Presto 时的另一个要点。在项目的早期阶段, 我们就意识到出了 HDFS 之外,大量数据会被存储在很多其他类型的系统中。 其中一些是像 HBase 一类的为人熟知的系统,另一类则是象 Facebook New Feed 一样的定制的后台。Presto 设计了一个简单的数据存储的抽象层, 来满足在不同数据存储系统之上都可以使用 SQL 进行查询。存储插件(连接器,connector)只需要提供实现以下操作的接口, 包括对元数据(metadata)的提取,获得数据存储的位置,获取数据本身的操作等。除了我们主要使用的 Hive/HDFS 后台系统之外, 我们也开发了一些连接其他系统的 Presto 连接器,包括 HBase,Scribe 和定制开发的系统。
(译者注:Scribe 是 Facebook 的开源项目,可以实时的将大量服务器产生的日志文件汇总到文件系统中, 详见: https://github.com/facebook/scribe)
(译者注: 从目前的信息来看,Presto 的架构在分布式处理数据的方式和基于 MapReduce 2.0 的 HorntonWorks 的 Stinger 有着很大的不同,可能会比较接近于 Google 的 Dremel 或者 Cloudera 的 Impala。 )
现状
正如上面所介绍的, Presto 的开发是从 2012 年的秋天开始的。 在 2013 年早期的时候我门的第一个生产系统开始运行。 在 2013 年春天的时候这个系统推广到了 Facebook 的整个公司。从那是起, Presto 成为了公司内在数据仓库上进行交互式分析的主要系统。 它被部署到了多个不同的地区,而且我们成功地将一个集群扩展到了 1000 个节点。 超过 1000 名以上的员工在日常工作中使用这个系统, 他们每天在一个 PB 的数据上会运行超过 30,000 个查询。
Presto 在 CPU 的性能和主要的查询性能上比 Hive/MapReduce 要好 10 倍以上。它目前支持 ANSI SQL 的大部分操作, 包括连接、 左/右外连接、 子查询、以及通用的聚合和标量函数, 同时也包含了一些近似的去重(使用了 HyperLogLog)和近似的百分数(基于 quantile digest 算法,)计算。目前阶段的主要限制是在表连接时候的大小限制以及唯一键值和群组的基数(cardinality of unique keys/groups)。目前系统没有能力将查询结果回写到特定的表中(目前查询结果会直接通过流输出的方式返回给客户端)。
(译者注:对大数据进行特定操作的时候会用到一些使用统计方法的近似算法。HyperLogLog 算法时用来估计大量数据中特定值出现次数的,具体可以看 这篇博文。Quantile Digest 算法及具体应用可以看 这篇博文。)
展望
我们在积极努力地扩展 Presto 的功能以及提供性能。 在接下来的几个月中,我们会去除查询中连接和聚合的大小限制,同时我们将提供将查询结果写入输出表的功能。 我们同时在开发一个查询加速器。主要是设计一种为查询处理优化的新的数据格式来避免不必要的数据转换。 这些新的特性会将后台数据仓库中经常使用的数据集合缓存起来, 系统会有效地使用这些缓存数据来加速查询的速度,而不需要让用户知道缓存机制的存在。 我们同时也在开发一个高性能的 HBase 连接器(HBase connector)。
开源
2013 年 6 月的 Analytics @ WebScale 大会上, 我们第一次介绍了 Presto。在那之后,它吸引了许多外界对它的关注。在最近的几个月中, 我们已经将 Presto 的源代码和可执行包发布给了一些外界的公司。他们已经在他们自己的环境中成功地进行了部署和测试的工作, 并且给了我们很好的反馈。
今天我们非常高兴宣布我们将 Presto 变成开源项目。 你可以在以下的网站上找到源代码和文档。 我将非常乐意从你这里了解到你的用例,以及 Presto 可以怎样帮到你的交互式分析。
Preston 官网: http://prestodb.io/
Preston Github 主页: https://github.com/facebook/presto
Facebook 数据基础设施的 Presto 团队由以下成员组成, Martin Traverso, Dain Sundstrom, David Phillips, Eric Hwang, Nileema Shingte 以及 Ravi Murthy.
链接
[1] Scaling Apache Giraph to a trillion edges. https://www.facebook.com/notes/facebook-engineering/scaling-apache-giraph-to-a-trillion-edges/10151617006153920
[2] Under the hood: Scheduling MapReduce jobs more efficiently with Corona https://www.facebook.com/notes/facebook-engineering/under-the-hood-scheduling-mapreduce-jobs-more-efficiently-with-corona/10151142560538920
[3] Video of Presto talk at Analytics@Webscale conference, June 2013 https://www.facebook.com/photo.php?v=10202463462128185