paint-brush
Uber Presto 本地缓存的设计与实现by@bin-fan
686
686

Uber Presto 本地缓存的设计与实现

Bin Fan2022/06/03
Read on Terminal Reader
Read this story w/o Javascript

在上一篇博客中,我们介绍了 Uber 的 Presto 用例以及我们如何协作实现 Alluxio 本地缓存以克服加速 Presto 查询的不同挑战。第二部分讨论对本地缓存元数据的改进。

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Uber Presto 本地缓存的设计与实现
Bin Fan HackerNoon profile picture


上一篇博客中,我们介绍了 Uber 的 Presto 用例以及我们如何合作实现 Alluxio 本地缓存以克服加速 Presto 查询的不同挑战。第二部分讨论对本地缓存元数据的改进。

本地缓存的文件级元数据

动机

首先,我们要防止过时的缓存。底层数据文件可能会被第三方框架更改。请注意,这种情况在 Hive 表中可能很少见,但在 Hudi 表中很常见。


其次,每天从 HDFS 读取的不重复数据可能很大,但我们没有足够的缓存空间来缓存所有数据。因此,我们可以通过为每个表设置一个配额来引入范围配额管理。


第三,元数据应该在服务器重启后可以恢复。我们将元数据存储在内存而不是磁盘中的本地缓存中,这使得当服务器关闭并重新启动时无法恢复元数据。

高级方法

因此,我们提出了文件级元数据,它保存并保存了我们缓存的每个数据文件的最后修改时间和范围。文件级元数据存储应持久保存在磁盘上,以便重启后数据不会消失。


随着文件级元数据的引入,数据将有多个版本。数据更新时会产生一个新的时间戳,对应一个新的版本。对应于这个新时间戳创建一个存储新页面的新文件夹。同时,我们会尝试移除旧的时间戳。

缓存数据和元数据结构

如上图,我们有两个文件夹对应两个时间戳:timestamp1和timestamp2。通常,系统运行时,不会同时有两个时间戳,因为我们会删除旧的时间戳1,只保留时间戳2。但是,在服务器繁忙或高并发的情况下,我们可能无法按时移除时间戳,这种情况下我们可能同时有两个时间戳。此外,我们维护一个元数据文件,该文件保存 protobuf 格式的文件信息和最新的时间戳。这确保了 Alluxio 的本地缓存只从最新的时间戳中读取数据。当服务器重启时,会从元数据文件中读取时间戳信息,以便正确管理配额和上次修改时间。


元数据意识

缓存上下文

由于 Alluxio 是一个通用的缓存解决方案,它仍然需要像 Presto 这样的计算引擎将元数据传递给 Alluxio。因此,在 Presto 站点上,我们使用 HiveFileContext。对于 Hive 表或 Hudi 表中的每个数据文件,Presto 都会创建一个 HiveFileContext。 Alluxio 在打开 Presto 文件时会使用这些信息。


在调用 openFile 时,Alluxio 会创建一个新的 PrestoCacheContext 实例,该实例保存 HiveFileContext 并具有范围(四个级别:数据库、模式、表、分区)、配额、缓存标识符(即文件路径的 md5 值)和其他信息。我们将把这个缓存上下文传递给本地文件系统。因此,Alluxio 可以管理元数据并收集指标。


Presto 端的每个查询指标聚合

除了将数据从 Presto 传递到 Alluxio 之外,我们还可以回调 Presto。在执行查询操作时,我们会知道一些内部指标,例如读取的数据有多少字节命中缓存以及从外部 HDFS 存储读取了多少字节的数据。

如下图,我们将包含PrestoCacheContext的HiveFileContext传递给本地缓存文件系统(LocalCacheFileSystem),之后本地缓存文件系统回调(IncremetCounter)给CacheContext。然后,这个回调链将继续到 HiveFileContext,然后到 RuntimeStats。


在 Presto 中,RuntimeStats 用于在执行查询时收集指标信息,以便我们进行聚合操作。之后,我们可以在 Presto 的 UI 或者 JSON 文件中看到本地缓存文件系统的信息。我们可以让 Alluxio 和 Presto 与上述流程紧密协作。在 Presto 方面,我们有更好的统计数据;在 Alluxio 方面,我们对元数据有更清晰的了解。

未来的工作

性能调优

由于上述回调过程使 CacheContext 的生命周期显着增长,我们遇到了一些 GC 延迟上升的问题,我们正在努力解决。

采用语义缓存 (SC)

我们将根据我们建议的文件级元数据来实现语义缓存(SC)。例如,我们可以将数据结构保存在 Parquet 或 ORC 文件中,例如页脚、索引等。

更高效的反序列化

为了实现更高效的反序列化,我们将使用 flatbuf 代替 protobuf。虽然在 ORC 工厂中使用了 protobuf 来存储元数据,但我们发现在 Alluxio 与 Facebook 的合作中,ORC 的元数据带来了超过 20-30% 的总 CPU 使用率。因此,我们计划用 flatbuf 替换现有的 protobuf 来存储缓存和元数据,这有望显着提高反序列化的性能。


总而言之,与上一篇博客一起,这个由两部分组成的博客系列分享了我们如何根据 Uber 的 Presto 和 Alluxio 社区之间最近的开源合作,为我们的 Presto 车队所需的热数据创建一个新的缓存层。这种架构上简单而干净的方法可以通过托管 SSD 和一致的基于散列的软关联调度显着减少 HDFS 延迟。加入我们社区Slack 频道的 9000 多名成员,了解更多信息。

关于作者

Chen Liang是 Uber 交互式分析团队的高级软件工程师,专注于 Presto。在加入优步之前,Chen 是 LinkedIn 大数据平台的一名软件工程师。 Chen 还是 Apache Hadoop 的提交者和 PMC 成员。陈先生拥有杜克大学和布朗大学两个硕士学位


王贝南博士是来自 Alluxio 的软件工程师,是 PrestoDB 的提交者。在加入 Alluxio 之前,他是 Twitter Presto 团队的 Tech Lead,他为 Twitter 的数据平台构建了大规模的分布式 SQL 系统。他在性能优化、分布式缓存和大容量数据处理方面拥有 12 年的经验。他获得了博士学位。雪城大学计算机工程专业,研究分布式系统的符号模型检查和运行时验证。


也在这里发布。