Raptor 是用来支持Meta(以前的Facebook)中的一些关键交互式查询工作负载的Presto连接器(presto-raptor)。尽管ICDE 2019的论文 Presto:SQL on Everything 中提到过这一特性,但它对于许多 Presto 用户来说仍然有些神秘,因为目前还没有关于此特性的可用文档。本文将介绍 Raptor 的历史,以及为什么 Meta 最终替换了它,转而采用基于本地缓存的新架构RaptorX。
![](https://101.200.239.157/wp-content/uploads/2022/05/image-7.png)
Raptor简介
一般来说,Presto 作为一个查询引擎并不具备存储空间,因此开发了连接器来查询不同的外部数据源。这个框架非常灵活,但在存算分离的架构中,很难提供低延迟保证。网络和存储延迟导致很难确保数据访问的稳定性。为了解决这个问题,Raptor被设计成 Presto 的独享存储引擎(shared-nothing storage engine)。
动机—AB 测试框架中的一个初始用例
在 Meta 公司,新的产品特性通常要经过 AB 测试,然后才能大范围发布。AB 测试框架允许工程师配置实验,在实验组启用新特性,然后通过监控一些关键指标与对照组进行比较。该框架为工程师提供了一个 UI(用户界面)来分析他们的实验统计数据,从而将配置转换为 Presto 查询,查询语句是已知且有限的。查询通常连接多个大型数据集,其中包括用户、设备、测试、事件属性等。这个用例的基本需求是:
准确性:数据必须完整、准确,不能有偏差;
灵活性:用户应该能够根据分析需求随意划分其运行结果;
实时性:测试结果应在数小时内获得;
交互延迟短:查询需要在几秒钟内返回结果;
高可用:作为产品开发的关键服务,服务的宕机时间必须很短。
Presto 在典型的仓库设置中(比如使用 Hive 连接器直接查询仓库数据)可以轻松满足前两个要求,但无法满足其他的要求。仓库数据大多是 T+1 导入,没有近实时的数据导入,因此不能满足实时性的要求。此外,Meta 的数据中心已经转用存算分离的架构,当以高 QPS (查询吞吐率)扫描大型表时,无法保证低延迟。同时,典型的 Presto 部署会停止整个集群,因此也不能满足高可用需求。
为了支持这一关键用例,我们开始了 Raptor 的产品化进程。
Raptor 架构
下面是使用 Raptor 连接器的 Presto 集群的高层次架构:
![](https://101.200.239.157/wp-content/uploads/2022/05/image-8.png)
Raptor连接器使用MySQL作为metastore来存储表和文件元数据。表数据存储在每个worker 节点的本地磁盘上,并定期备份到外部存储系统,以便在 worker节点崩溃时能够进行数据恢复。数据以足够小的批量方式导入Raptor集群中,从而确保分钟级别的延迟,满足实时性要求。此外,还创建了备用集群,提供高可用性。
想要了解更多Raptor存储引擎的相关信息,请查看附录—Raptor架构信息或观看附录—Raptor讲座。
局限
通过存算耦合,Raptor 集群可以支持低延迟、高吞吐量的查询工作负载。但是,这种架构带来了以下几个问题:
集群利用率低
Raptor集群的大小通常取决于需要存储多少数据。由于存算耦合,随着表的增多,将需要更多的worker提供足够的存储空间,即使在集群空闲时段,重新将机器分配给其他业务使用的难度也变得非常大。
尾部性能较差
由于数据是对应分配给 worker 节点的,如果一个 worker 节点宕机或变慢,必然会影响查询性能,难以提供稳定的尾部性能。
工程开销较大
Raptor 需要很多存储引擎特有的特性和处理功能的支持,比如数据导入/释放、数据压缩、数据备份/恢复、数据安全等。对于直接查询 Meta 数据仓库的 Presto 集群而言,所有这些服务都由专门的团队管理,所有用例都能从中受益。而对于 Raptor 来说,情况就不同了,这导致了工程开销。
运维开销较高
由于Raptor集群需要部署额外的存储系统,因此也就带来额外的运维开销。不同的集群配置和行为意味着需要单独建立oncall的处理流程。
潜在的安全和隐私漏洞
随着安全和隐私需求的增加,安全与隐私策略的统一实现变得更加重要。使用单独的存储引擎使得这些策略执行起来非常困难且脆弱。
RaptorX 的启用
Raptor有着很多的痛点,因此从2019年开始,Meta的工程师们就在重新思考 Raptor的未来,是否有可能既从本地闪存中受益,又无需承担存算紧耦合架构带来的代价?最终确定的方向是在原生数据仓库之上添加一个新的本地缓存层。这个项目作为 Presto Raptor 连接器用例的替代品被命名为 RaptorX。
从技术层面来讲,RaptorX项目与Raptor无关。直观来说,同样的闪存设备在RaptorX里被当作数据缓存使用来存储Ratpor表,因此将热数据存放在计算节点上。将本地闪存作为缓存使用而不作为存储引擎使用的优点如下:
① Presto无需管理数据生命周期;
② 单个 worker 故障导致的数据丢失对查询性能的影响较小;
③ 缓存作为文件系统层的一个特性,是 presto-hive 连接器的一部分,因此 RaptorX 集群的架构类似于其他 presto 集群,减少了运维开销。
RaptorX 架构
下图为RaptorX 的架构:
![](https://101.200.239.157/wp-content/uploads/2022/05/image-9.png)
Raptor和 RaptorX的根本区别是如何使用 worker 上的本地固态硬盘(SSD)。在 RaptorX 中,Presto Worker 使用 Alluxio 在本地缓存文件数据。不同表列的访问模式可能差异很大,像 ORC 和 Parquet 这样的列式文件格式通常用于数据存储,增加文件中的数据本地性。通过在列式文件上以较小的页面大小缓存文件片段,只有频繁访问的数据才会被保存在接近计算的地方。Presto coordinator 会尝试将处理相同数据的计算任务调度到相同的worker节点上,以提高缓存效率。RaptorX 还实现了文件footer和元数据缓存,以及其他能进一步提高性能的智能缓存策略。
要了解更多有关 RaptorX 的信息,参见 《RaptorX: 将 Presto 性能提升十倍》。
RaptorX 和 Raptor 性能基准测试
我们对 RaptorX 和 Raptor 进行了基准性能对比测试。基准测试运行在一个有大约 1000 个 Worker 节点和一个 coordinator 的集群上。Raptor和 RaptorX 使用相同的硬件,整个数据集都能够缓存到 RaptorX 的本地固态硬盘中,因此缓存命中率接近100%。
![](https://101.200.239.157/wp-content/uploads/2022/05/image-10.png)
从基准测试结果中可以看到,RaptorX的P90延迟与Raptor相比降低了一半。RaptorX 中的平均查询延迟和 P90 查询延迟之间的差异要比 Raptor 小得多。这是因为在 Raptor 中,数据被物理绑定到计算它的 worker 点上,因此运行慢的节点将不可避免地影响查询延迟。而在RaptorX中,我们采用软亲和(soft affinity) 调度。软亲和调度将选择两个 worker 节点作为处理分片(split)的候选节点。如果首选的worker节点运行正常,则选择该节点,否则将选择辅助(secondary) worker 节点。数据很有可能在多个节点上缓存,因此对整体工作负载的调度策略可以进一步优化,从而达到更好的 CPU负载均衡。
从 Raptor 迁移到 RaptorX
Meta 公司所有以前的 Raptor 用例都迁移到了 RaptorX上, RaptorX 提供了更好的用户体验,并且易于扩展。
A/B 测试框架
在前一节中,我们提到了 A/B 测试框架的要求是:准确性、灵活性、实时性、低交互延迟和高可用性。因为 RaptorX 是 Hive 原始数据的缓存层,所以 Hive 保证了数据的准确性。它享受所有来自核心Presto引擎的查询优化,以及 Hive 连接器中的许多特定优化。基准测试结果表明,RaptorX的平均查询和 P90 查询延迟都优于 Raptor。对于实时性要求,我们能够从 Meta 的近实时仓库数据导入框架优化中受益,它提高了所有 Hive 数据的实时性。与 Raptor 一样,备用集群保证了高可用性。
在迁移过程中,由于用户体验良好,测试框架的使用量增长了2倍。RaptorX 集群能够按照与迁移前的 Raptor 集群相同的容量支持额外的用量。集群的 CPU 资源得到充分利用,无需担心存储限制。
仪表板
在Meta 中 Raptor 的另一个典型用例是优化仪表板体验。Presto 用于支持 Meta 中的许多仪表板用例,一些数据工程团队通过预聚合一些数据表,并且手动导入指定的Raptor集群来获得更好的查询性能。在迁移到 RaptorX之后,数据工程师便可以省去数据导入操作,也不再需要担心基础表(base tables)和预聚合表之间的数据一致性问题,同时,P50 以上的大多数分位的查询延迟的降幅都达到了30%左右。
Raptor 范围之外
由于 RaptorX 在正常的 Hive 连接器工作负载下作为booster使用起来很容易,我们也在 Meta 的数仓交互式工作负载中启用了 RaptorX。这些是多租户集群,通过 Presto 处理几乎所有Hive 数据的非 ETL 查询,包括 Tableau、内部仪表板、各种自动生成的 UI 分析查询、各种内部工具生成的工作负载、工作流原型(pipeline prototyping)、调试、数据探索等。RaptorX 为这些集群提供了支持,提高了相同数据集的查询性能。
附录
Raptor架构信息
数据组织
![](https://101.200.239.157/wp-content/uploads/2022/05/image-11.png)
Raptor表是根据哈希函数进行桶(bucket)划分的。来自同一个bucket的数据被存储在同一个worker节点上。在同一列上的多个表被称为一个distribution。一个表桶可以包含多个分片(shard), 而分片是Raptor数据的基本不可变单位, 以ORC格式的文件存储。表也可以有排序属性,可以更好地优化查询。
执行优化
Raptor作为Presto的本地存储引擎,允许Presto将计算安排在数据节点上,从而提供低延迟、高吞吐量的数据处理能力。除了通用的SQL优化外,Raptor的数据组织方式还能实现更多的执行优化。
① 本地关联:当在桶列上关联同一distribution的表时,Raptor将进行本地关联(Collocated Join),因为具有相同连接键的数据在同一个worker上,避免了重新分配。
② 数据裁剪: Raptor可以进行分片粒度和ORC读取器粒度的裁剪
(1)分片粒度的裁剪:分片的列范围存储在元数据中,可以根据查询谓词跳过分片。如果表有排序属性,分片将在该worker内被排序,这也可用于分片裁剪。
(2)ORC读取器粒度的裁剪:ORC读取器基于谓词,通过利用Stripe(一组行数据)元数据针对Stripe和行组进行裁剪。如果数据是有序的,排序属性也有助于数据裁剪。
其他特性
时间列:一个时间或日期类型的列可以被指定为时间列。如果指定了一个时间列,Raptor会在分片上严格按天进行限制(即一个shard里的记录都是属于某一天的)。鉴于数据保留策略,这将能够提高大表的数据留存性能。
① 后台压缩:为了保证实时性,数据通常是以小的时间粒度导入Raptor的,这可能导致产生很多小文件,对查询性能不利。Raptor worker定期运行后台作业,将多个小分片压缩成大分片,并进行外部排序,保证排序属性。
② 数据恢复:如果某个worker发生故障,coordinator将在集群的其他节点上重新分配故障worker的数据。所有worker将从备份存储中下载必要的数据。在恢复过程中,如果某个查询需要访问缺失数据,该操作将被阻止,直到数据下载/恢复完毕。
③ 数据清理:每个worker都有一个后台进程,将其分配的数据与本地数据进行比较,从而恢复缺失的数据,更新陈旧的数据。
④ 数据再平衡:如果coordinator检测到数据不平衡(例如,增加了新的worker节点),它会修复不平衡的数据分布。
Raptor讲座
如需了解更多有关Raptor的信息, 可点击此链接:Presto Raptor: MPP Shared-Nothing Database on Flash,查看2016年Data@Scale会议上关于Raptor的公开讲座。