共计 4793 个字符,预计需要花费 12 分钟才能阅读完成。
概要速览📕
Meta 公司(前“Facebook 公司”,下文统称“Meta”)的 Presto 团队始终在与 Alluxio 单干为 Presto 提供开源数据缓存计划。该计划被用于 Meta 的多个用例,来升高从诸如 HDFS 等远端数据源扫描数据产生的查问提早。试验证实,应用 Alluxio 数据缓存后,查问提早和 IO 扫描都失去了显著优化。
咱们发现,Meta 架构环境中的多个用例都得益于 Alluxio 数据缓存。以 Meta 的一个外部用例为例,其各分位的查问提早别离降落了 33%(P50)、54%(P75)和 48%(P95)。此外,远端数据源扫描数据的 IO 性能晋升了 57%。
Presto 架构📖
Presto 的架构容许存储和计算独立扩大,然而扫描远端存储中的数据可能会产生低廉的操作老本,也难以达到交互式查问的低提早要求。
Presto worker 只负责对从独立(通常是远端)数据源扫描的数据执行查问打算片段,而不会存储任何远端数据源的数据,因而计算能够进行弹性扩大。
上面的架构图清晰地展现了从远端 HDFS 读取数据的门路。每个 worker 都会独立地从远端数据源中读取数据,本文将只探讨对远端数据源读取操作的优化。
Presto + 数据缓存架构📖
为了解决用例的亚秒级提早问题,咱们决定进行多种优化,其中一个重要的优化就是实现数据缓存。数据缓存作为一种传统的优化形式,能让工作数据集更凑近计算节点,缩小对远端存储的拜访,从而升高提早并节约 IO 开销。
其中的艰难在于,如果从远端数据源拜访 PB 级别的数据时没有固定拜访模式的话,如何能实现无效的数据缓存,此外,无效数据缓存的另一个要求是在 Presto 等分布式环境中实现数据的亲和性。
增加数据缓存性能后,Presto 的架构如下所示:
对于数据缓存,前面会有更具体的阐明。
软亲和调度📖
Presto 目前的调度器在调配分片时曾经把 worker 的负载纳入考量,因而该调度策略使得工作负载在 worker 之间平均调配。但从数据本地性的角度来看,分片是随机调配的,不能保障任何亲和性,而亲和性恰好是实现无效数据缓存的必备条件。对 Coordinator 而言,每次把分片调配给同一个 worker 至关重要,因为该 worker 可能曾经缓存了分片所需的数据。
上图阐明了亲和性调度是如何给 worker 调配分片的。
执行软亲和调度策略时,会尽可能将同一个分片调配给同一个 worker。软亲和调度器应用分片的哈希值来为分片抉择一个首选 worker,软亲和调度器:
✓ 为分片计算其首选 worke。如果首选 worker 有短缺的可用资源,那么调度器会把该分片调配给首选 worker。
✓ 如果首选 worker 处于繁忙状态,那么调度器就会抉择一个备选 worker,如果该备选 worker 有短缺的可用资源,调度器就会把分片调配给它。
✓ 如果备选 worker 也处于繁忙状态,那么调度器就会把分片调配给以后最闲暇的 worker。
确定一个节点是否繁忙可通过两项配置来定义:
✓ 单节点最大分片数:node-scheduler.max-splits-per-node
✓ 单任务最大待定分片(pending split)数: node-scheduler.max-pending-splits-per-task
当某一节点上的分片数超过上述任一配置的限度时,该节点就被视为繁忙节点。能够看出,节点亲和性对于缓存的有效性至关重要。如果没有节点亲和性,同一分片可能会在不同的工夫被不同的 worker 解决,这会导致冗余的分片数据缓存。
出于这个起因,如果亲和性调度器没能把分片调配给首选 worker 或者备选 worker(因均处于繁忙状态),调度器就会向被调配的 worker 发出信号,让其不要缓存分片数据。这意味着只有分片的首选或备选 worker 才会缓存该分片的数据。
数据缓存📖
Alluxio 文件系统是一个常常用作 Presto 分布式缓存服务的开源数据编排零碎。为了在架构中实现亚秒级的查问提早,咱们心愿进一步升高 Presto 和 Alluxio 之间的通信开销。因而,Alluxio 和 Presto 的外围团队进行单干, 从 Alluxio 服务中倒退出一个单节点的嵌入式缓存库。
具体而言,Presto worker 通过规范的 HDFS 接口查问位于同一个 JVM 内的 Alluxio 本地缓存。当缓存命中时,Alluxio 本地缓存间接从本地磁盘读取数据,并将缓存数据返回给 Presto;否则,Alluxio 将拜访远端数据源,并将数据缓存在本地磁盘上,以便后续查问。该缓存对 Presto 来说是齐全通明的。一旦缓存呈现问题(如本地磁盘产生故障),Presto 还能够间接从远端数据源读取数据,该工作流程如下图所示:
本地缓存的外部形成和配置
Alluxio 数据缓存是位于 Presto worker 节点上的库,它提供了一种与 HDFS 兼容的接口“AlluxioCachingFileSystem”,作为 Presto worker 进行所有数据拜访操作的次要接口。Alluxio 数据缓存蕴含的设计选项有:
根本缓存单元
依据 Alluxio 的教训以及 Meta 团队晚期的试验,以固定的数据块大小来进行数据读写和清理是最无效的。为了缩小元数据服务的存储和服务压力,Alluxio 零碎中默认的缓存数据块大小为 64MB。因为咱们采纳的 Alluxio 数据缓存只须要在本地治理数据和元数据,所以咱们大大调低了缓存的粒度,把默认缓存粒度设置成大小为 1MB 的“page(页面)”。
缓存地位和层级
Alluxio 本地缓存默认将数据缓存到本地文件系统。每个缓存 page 作为独自的文件存储在目录下,目录构造如下:<BASE_DIR>/LOCAL/1048576/<BUCKET>/<PAGE>
✓ BASE_DIR 是缓存存储的根目录,能够通过 Presto 的配置项“cache.base-directory”来设置。
✓ LOCAL 示意缓存存储类型为 LOCAL(本地)。Alluxio 也反对 RocksDB 作为缓存存储。
✓ 1048576: 代表数据块的大小为 1MB。
✓ BUCKET 作为各种页面文件的 bucket 的目录。之所以创立 bucket 是为了确保繁多目录下不会有太多的文件,否则可能会导致性能很差。
✓ PAGE 代表以页面 ID 命名的文件。在 Presto 中,ID 是文件名的 md5 哈希值。
线程并发
每个 Presto worker 蕴含一组线程,每个线程执行不同的查问工作,但共享同一块数据缓存。因而,该 Alluxio 数据缓存须要具备跨线程的高并发度,以提供高吞吐量。也就是说,数据缓存须要容许多个线程并发地获取同一个 page,同时还能在革除缓存数据时确保线程平安。
缓存复原
当 worker 启动(或重启)时,Alluxio 本地缓存会尝试复用曾经存在于本地缓存目录中的缓存数据。如果缓存目录构造是兼容的,则会复用已缓存数据。
监控
Alluxio 在执行各种缓存相干操作时,会输入各种 JMX 指标。通过这些指标,系统管理员能够轻松地监控整个集群的缓存应用状况。
基准测试📖
咱们以运行在某个生产集群上的查问来进行基准测试,该集群被当作测试集群来应用。
查问数:17320
集群大小:600 个节点
单节点最大缓存容量:460GB
革除策略:LRU
缓存数据块大小:1MB, 意味着数据按 1MB 的大小读取、存储和革除。
查问执行工夫优化(单位:毫秒):
从表格中能够看出,查问提早有显著改善,其中 P50 的查问提早升高了 33%,P75 升高了 54%,P95 升高了 48%。
开销节俭
✓ Master 分支执行过程的总数据读取大小:582 TB
✓ 缓存分支执行过程的总数据读取大小:251 TB
节俭的扫描数据量:57%
缓存命中率
在试验过程中,缓存命中率根本稳固地放弃在较高的程度,少数工夫维持在 0.9 和 1 之间。两头可能是因为新查问扫描大量新数据的起因呈现了一些降落。咱们须要增加一些其余算法来防止出现拜访不太频繁的数据块相较于拜访频繁的数据块更容易被缓存的状况。
如何应用?📖
应用数据缓存前,咱们要做的第一件事就是启用软亲和调度策略,数据缓存不反对随机节点调度策略。
要启用软亲和调度策略,在 coordinator 中须要进行如下配置:
"hive.node-selection-strategy", "SOFT_AFFINITY”
要应用默认(随机)节点调度策略,则设置如下:
"hive.node-selection-strategy", "NO_PREFERENCE”
要启用 Alluxio 数据缓存,在 worker 节点采纳如下配置:
✓ 启用 worker 节点上的数据缓存 => “cache.enabled”, “true”
✓ 将数据缓存类型设置为 Alluxio=> “cache.type”, “ALLUXIO”
✓ 设置缓存数据存储的根本目录(base directory) => “cache.base-directory”, “file:///cache”
✓ 配置单个 worker 缓存所能应用的最大数据容量:”cache.alluxio.max-cache-size”, “500GB”
其余有用的配置如下
Coordinator 配置(可用来配置繁忙 worker 的定义):
✓ 设置单任务最大待定分片数:node-scheduler.max-pending-splits-per-task
✓ 设置单节点最大分片数:node-scheduler.max-splits-per-node
Worker 配置:
✓ 启用 Alluxio 缓存指标(默认:true): cache.alluxio.metrics-enabled
✓ Alluxio 缓存指标的 JMX 类名(默认: alluxio.metrics.sink.JmxSink): cache.alluxio.metrics-enabled
✓ Alluxio 缓存应用的指标域名:(默认: com.facebook.alluxio): cache.alluxio.metrics-domain
✓ Alluxio 缓存是否要异步写入缓存(默认: false): cache.alluxio.async-write-enabled
✓ Alluxio 缓存是否要验证已有的配置(默认: false): cache.alluxio.config-validation-enabled
Alluxio 数据缓存为其缓存操作输入各种 JMX 指标。点击查看指标名称的残缺列表。
下一步工作📖
✓ 实现通过限速器(rate limiter)管制缓存写入操作的速率,从而防止闪存耐久性问题;
✓ 实现语义感知缓存,进步缓存效率;
✓ 建设清理缓存目录的机制,用于保护或重新启动。
✓ 可执行“dry run”模式
✓ 可能施加各种容量应用限度,例如单表缓存配额限度,单分区缓存配额限度或单模式缓存配额限度。
✓ 构建更弱小的 worker 节点调度机制。
✓ 减少新的算法实现,防止出现拜访不太频繁的数据块相较于拜访频繁的数据块更容易被缓存的状况。
✓ 容错性:目前,当集群中的节点数量发生变化时,基于哈希的节点调度算法会呈现问题。咱们正在努力实现更鲁棒的算法,如一致性哈希。
✓ 更好的负载平衡:当咱们把其余因素如分片大小、节点资源等纳入考量后,咱们就能更好地定义“繁忙”节点,继而在实现负载平衡方面做出更理智的决策。
✓ 亲和性规范:目前,Presto 集群内的亲和性粒度是文件级的。如果不能在该粒度规范下达到最佳性能,则须要调整咱们的亲和性规范,使其更加细粒度,并在负载平衡和良好的缓存命中率之间找到平衡点,从而实现更好的整体性能。
✓ 进步 Alluxio 缓存库的资源利用率。
文章贡献者:🧔
Meta:Rohit Jain, James Sun, Ke Wang, Shixuan Fan, Biswapesh Chattopadhyay, Baldeep Hira
Alluxio: Bin Fan, Calvin Jia, Haoyuan Li
原文内容公布于:2020/6/16