Presto 在知乎的缓存加速实践
Presto,作为一个典型的存储与计算分离的 OLAP 引擎已经在大数据领域取得了一系列的成果。存算分离的部署方式虽然在资源扩展性上拥有明显优势,但也不免带来了一系列技术挑战。其中,数据获取的速度与成本问题尤为突出。
存储与计算分离的挑战
在这样的架构中,Presto 虽然提供了丰富且灵活的 Connector,让查询异构数据源变得更为简单。但由于自身缺乏专门的存储系统,低延迟的数据查询往往难以保障。此外,因为必须频繁地与外部存储通信,这使得网络和存储的不稳定性变得更为显著,从而可能影响到数据访问的稳定性。
历程
知乎的 Presto 经历了 PrestoDB -> PrestoSQL -> Trino 几个阶段,现在需要重新审视和调整目前的 Presto 架构,来解决知乎日益增长的复杂分析需求,主要提升报表场景的查询性能,同样也包括但不限于即席查询,探索分析等场景。
Presto 是一种开源的分布式 OLAP SQL 查询引擎,它最初由 Facebook 开发,并于 2012 年开源。因为丰富的连接器特性 (Connector) 它不仅可以支持非关系数据源,例如 Hadoop 分布式文件系统 (HDFS,Hive)、S3、Cassandra,还可以支持关系型数据源,例如 MySQL、PostgreSQL、Oracle 等。对于这些异构数据域均支持标准 ANSI SQL 语义,同时还支持复杂查询、聚合、联接、左 / 右外联接、子查询、开窗函数等。
Presto 的架构与经典大规模并行处理 (MPP) 数据库管理系统相似,由一个协调器节点 (Coordinator) 与多个工作节点 (Worker) 组成。协调器节点负责接收来自客户端的查询请求并进行解析、优化、调度。然后将任务分配到多个工作节点中,所有处理都在内存中进行,并以流水线方式 (Pipeline) 在集群中流动,从而避免不必要的 I/O 开销。
在大数据 OLAP 领域中,衡量一个引擎的标准主要有数据量、灵活性、性能,并且只能侧重于一点。根据前面的 Presto 架构介绍,将它定位为成中小型数据量、高度灵活、性能适中的数据场景,能够发挥出最大的价值。
所以在面向实际业务场景中,Presto 特别适合交互式分析、报表查询、数据探索、等需要快速失败 (Fail-fast) 的场景。不太适合那种需要任务高容错的场景,比如大规模 ETL、数据同步、数据回溯、机器学习数据建模。同时,因为在知乎使用 Presto 的首要任务是为 Hive 查询提速,所以也不建议承接高并发查询场景。
最终,我们在知乎大数据中把 Presto 定位成了 “只读 OLAP 引擎”,部署在大数据的计算领域架构下。其他读写场景的需求会推荐使用 Hive 或者 Spark,或者根据业务需要选择其他引擎。
注: 下图只有计算领域 ,省略了其他环节。
Presto 在知乎的部署经历了两种方式的迭代:
资源物理隔离方式。
资源统一网关路由方式。
在早期的 PrestoDB 与 PrestoSQL 时代,由于缺乏高效的基础设施运维的便利性以及网关路由对资源的负载均衡机制,系统主要采用物理隔离的方式进行部署。
这种方式虽然满足了业务使用的便捷性,但也导致了一系列问题,如维护复杂性增加、资源分布不均、变更成本增高及资源浪费等。
为了优化资源管理和简化用户访问,我们在集群入口引入了 presto-gateway。
借助此项目,我们实现了将原先的 N 个集群的独立域名整合为一个统一域名,这既为后续的 AB 测试、灰度升级和特定用户路由提供了便利,同时也显著降低了资源的浪费。
在基础运维策略上,我们整合了 Terraform,将传统的手动运维工作转化为更为逻辑化的软件开发流程。
利用 Terraform 的幂等状态管理设计,所有的运维操作都可以经过代码审查后使用单一的命令来完成。虽然这种转变略微增加了初期的开发成本,但在长期看来,其为我们节省了大量的日常维护成本,降低了 99% 的维护心智复杂度。
需要强调的是,这里提到的 “单一命令” 并不仅仅是某种简化的一键操作,而是遵循基础设施即代码 Infrastructure as Code (IaC) 开发后得到的,意味着所有的部署和后续变更都可以通过这个命令来高效完成。
在不增加机器成本的前提下:
查询耗时需要呈下降的良性趋势。
报表类的中小型查询场景 (P50) 相较于之前,至少有 50% 的性能提升。
我们的目标,有一个硬性前提,不能增加机器成本,根据这个硬性前提,有如下两种部署模式:
独立 Alluxio 集群,可以实现 OLAP 引擎统一加速,不局限于 Presto 还可以为 Hive,Spark 进行加速,最终提供统一的数据编排服务。
RaptorX,此为 PrestoDB 中的一个专属缓存加速功能,打开配置后即可使用。
Allxuio:是什么
Alluxio 是一个开源的分布式超大规模数据编排系统,旨在加速分布式计算工作负载的数据访问速度。它可以在内存和存储之间提供一种高效的数据访问层,以便在不同的数据存储系统(如 HDFS、S3、Azure Blob 等)和计算框架(如 Presto、Apache Spark 等)之间进行快速数据共享。
PrestoDB RaptorX:缓存加速
RaptorX 前身是为 Raptor 它是一个 Presto Connector (presto-raptor),主要用于支持 Meta(以前的 Facebook)中的一些关键的交互式查询场景。PrestoDB 存算分离的架构,这种方式非常灵活,但很难提供低延迟保证,尤其是网络和存储延迟等问题会被放大。为了解决这些问题,Raptor 被设计成 PrestoDB 的独享存储引擎 (shared-nothing storage engine)。
注意,这里提到的 RaptorX 与 Raptor 是两个项目。Raptor 可以按照是一个独立的缓存集群理解,RaptorX 则是多级缓存功能,在比如元数据、文件列表、原始数据等等功能在使用时,赋予自动缓存的能力。
通过实现自有存储,Presto 也在往低延迟,高吞吐的 OLAP 引擎道路上迈出脚步。同时这种架构变更,也带来了如下问题:
资源利用率不可控:Raptor 集群的大小取决于需要存储多少数据,但是因为架构变更数据与计算耦合在一起了,这对资源使用率带来了新的挑战。
高工程和运营成本:虽然 Raptor 实现了自有存储,这对数仓工作等与数据相关的场景带来了好处,但是对于 Presto 来说需要多维护一套存储系统。
潜在的安全问题:随着安全性和隐私要求的增加,实现统一的安全性和隐私政策变得更加重要。使用单独的存储引擎使得执行此类政策变得极为困难和脆弱。
因此从 2019 年开始,Meta 的工程师们就在重新思考 Raptor 的未来,是否有可能既从本地存储中受益,又无需承担存算紧耦合架构带来的成本提升?最终确定的方向是在原生数据仓库之上添加一个新的本地缓存层。项目命名为 RaptorX (详情 https://prestodb.io/blog/2021/02/04/raptorx)。
从技术层面来讲,RaptorX 项目与 Raptor 无关。主要的区别是利用本地存储与单独的存储系统,带来的好处如下:
Presto 无需管理数据生命周期;
单个 Worker 故障导致的数据丢失对查询性能的影响较小;
缓存作为文件系统层的一个特性,是 presto-hive 连接器的一部分,运维方式与常规 Presto 集群一样,从而减少了运维成本。
PrestoDB RaptorX:功能介绍
原始数据缓存: 可以将查询需要的原始数据缓存下来,缓存模式有 2 种缓存类型 FILE_MERGE 与 ALLUXIO;
FILE_MERGE 是使用本地存储。
ALLUXIO 使用嵌入式的 ALLUXIO,一般称为 Alluxio Local Cache。
元数据缓存: 在 Coordinator 中缓存 Hive 表 / 分区等信息;
文件列表缓存: 缓存来自远程存储分区目录的文件列表;
分片结果缓存: 在 Worker 节点的本地存储上缓存部分计算结果,比如 COUNT DISTINCT;
Footer 缓存: 在 Worker 节点内存中缓存 ORC 和 Parquet 的 Footer 信息,这些数据大多在读取时会频繁使用;
亲和性调度器: 将查询与缓存赋予亲和性,根据哈希取模或者一致性哈希的方式将查询调度到缓存数据所处的节点,以此提升缓存命中率。
尽管独立部署的 Alluxio 集群拥有多项优势,然而考虑到我们当前使用的 Presto 在 Kubernetes(K8s)环境中运行,将独立 Alluxio 集群集成进现有环境中可能面临网络、磁盘和副本等方面的高成本运维挑战。鉴于初期的考量,为了避免过多投入资源在这些方面,我们选择了目前具有性价比的方案,使用 PrestoDB RaptorX。
独立维护一个完整的集群与简单地进行配置调整相比,短期内无疑后者更具性价比。然而,从长远来看,选择独立部署的 Alluxio 集群将在大数据的 OLAP 领域带来不可忽视的优势。
从先前对 RaptorX 项目的探讨及社区中相关的实践案例分析可知,利用 Alluxio (独立式或嵌入式) 可以优化和挖掘服务器中的闲置资源,从而提高查询速度是可行的。
知乎在调整 Presto 的集群部署策略之后,发现了若干未充分利用的资源。这些资源为我们提供了一个绝佳的机会,去解决一些早期服务的遗留问题。
得益于集群部署策略的优化,现在我们已经拥有了快速部署和在 PrestoDB 与 Trino 之间切换的能力,并且还能进行异构部署。
基于这样的背景,我们决定再次进行深入的对比测试,重新评估 PrestoDB 和 Trino 在 OLAP 性能上的表现,以便为我们的用户提供更优质的数据查询服务。
测试版本为 PrestoDB 0.280 vs Trino 416 (它们为 2023-05 月期间的最新版本)。
96C 192G 的云主机;
500GB TPC-DS 数据集,造数项目 spark-sql-perf 和 tpcds-kit;
数据模拟生产开启了 snappy 压缩,数据格式有 Parquet 和 ORC;
Trino 使用了 jdk17,PrestoDB 使用了 jdk11;
1Coordinator 3Worker 和 6Worker 两种部署方式 (独立部署),Worker 的堆内存为 64GB,其他参数尽量与生产一致;
测试使用了原生 PrestoDB 或 Trino 的 Java 客户端;
测试用例由源码中的 tpcds 所提供。
TPC-DS 数据集抽取了 20 个 SQL,对齐配置后,进行了多轮测试。
生产环境中,我们因为有了网关和多集群部署的便利性,摘了一个子集群的资源部署了 PrestoDB ,在闲时进行了对比测试。
k8s 容器化部署;
1Coordinator 64Worker,Worker 堆内存 64GB;
其他参数与 Trino 对齐。
测试用例随机从业务中抽取了 20 个 SQL,它们分别代表了不同的业务场景,有报表类、分析类、挖掘类等,几乎能反应真实业务场景。
还是同样的方式,生产环境开始了多轮 AB 测试,采取了 20%、40%、50% 的资源进行 AB 测试。
测试发现,在 P50 场景中平均有 1.5 ~ 2 倍的性能提升,在 P90 场景中只有少量的提升。
Trino 的社区发展接受了很多用户的意见,很多易用性等细节功能开发走在了前面,这次测试我们发现如下几点相对于 PrestoDB 更优。
5.5.1.1 动态过滤
Trino 会对 TPC-DS 中的一些场景,实现动态过滤的优化,如果命中了该场景优化效果特别明显。
虽然 PrestoDB 也有这功能,可以理解 Trino 加大了开发投入所以走在了前面。但是这种场景特别考验数仓的设计,在我们对实际业务测试中,很难命中这个场景。
详情见:https://trino.io/docs/current/admin/dynamic-filtering.html
5.5.1.2 享受 Spark 统计信息加成
Trino 可以享受 Spark ETL 产出时的统计信息加成。
这个统计信息是在数据产出后直接被 Spark ETL 写到了 Hive 表的 DDL 信息里面的,如下图:
因为 Trino 可以享受该加成,所以会比 PrestoDB 要快,我们测试将这些统计信息去掉后,查询耗时回到了持平状态。
详情见:https://github.com/trinodb/trino/pull/16120
5.5.1.3 参考 Trino 的优化参数
经过对比发现 Trino 的很多默认参数都比 PrestoDB 投入的开发更多,比如在 PrestoDB 还是实验性的参数,在 Trino 中已经迭代了几轮并正式上线了。所以我们在测试的时候,PrestoDB 的很多参数都是参考 Trino 在进行调优。
主要参数如下:
下推类 hive.pushdown_filter_enabled=false,hive.parquet_pushdown_filter_enabled=true
下推类 hive.enable-parquet-dereference-pushdown=true
下推类 hive.parquet.pushdown-filter-enabled=true
动态过滤 experimental.enable-dynamic-filtering=true
查询类 query.max-stage-count=150
分区类 hive.ignore-unreadable-partition=true
经过多轮测试 PrestoDB RaptorX 项目,我们最后开启了如下功能:
开启软亲和 hive.node-selection-strategy=SOFT_AFFINITY;
开启原始数据缓存 ALLUXIO 模式,关闭版本校验,关闭 cache.default-cache-quota 只开启 cache.alluxio.max-cache-size;
开启 Hive 元数据缓存 主要使用 hive.metastore-cache-ttl 时间进行缓存更新;
开启分片缓存;
因为原始数据缓存使用了 ALLUXIO 所以关闭了文件列表缓存和 Footer 缓存。
虽然 Trino 在多个细节上进行了精细优化,并且默认参数优于 PrestoDB。其基础对接代码极具人性化,如公司认证对接、资源队列管理以及客户端的兼容性等。但考虑到 Trino 当下尚未支持 Alluxio Local Cache 的功能(即嵌入式缓存),以及我们短期内的快速上线需求,显然修改配置相对于新建一套 Alluxio 集群更为经济高效。
基于上述原因,我们决定采用 PrestoDB 代替 Trino。得益于基础运维的便捷性,部署过程仅需更换相关镜像即可。
需要明确的是,这并不意味 Trino 不能配合 Alluxio 使用,只是目前 Alluxio 的 Local Cache 功能仅限于在 PrestoDB 中运行。
注:Trino 针对 Alluxio Local Cache 的支持,已经在进行中。
借助 PrestoDB RaptorX 的便利性,我们在很短的时间内完成了 Presto 集群的架构迭代与升级,同时也遇到了具有代表性的问题,如下:
虽然在 PrestoDB 中开启 RaptorX 可以显著提高查询速度,但在原始数据缓存配置方面的灵活性仍有待加强。目前,关于缓存的主要配置仅限于缓存类型、缓存大小和 Shadow Cache 的缓存命中检测,而并没有为用户提供更细粒度的控制能力。
贴心的是,Alluxio 社区提供了 CacheFilter 接口,允许用户自定义缓存过滤规则,进而实现对缓存的自定义控制。
比如在一些特定的业务场景中,如报表生成、即席查询、数据挖掘和多维分析等,如果未进行适当的缓存管理,可能会导致缓存资源的竞争和频繁的缓存冲刷。为解决此问题,我们参考 CacheFilter 接口开发了一套基于路径前缀匹配的自定义过滤规则。
尽管我们拥有了缓存自定义控制的能力,但查询的分区范围仍然是一个变数,而且缓存空间总是有限的,我们无法把所有要查询的数据都预加载到缓存中,那么面对这样的挑战,我们应该如何制定一个有效的缓存策略呢?
在这个集群中,一共有 43T 的空间可以用于缓存使用。
在尽可能的将缓存空间用满的前提下,缓存命中率要达到 60% 以上。
为了在有限的资源下确保缓存能够带来最大的收益,我们选定了基于 ROI(投资回报率)的策略来筛选库表。此策略旨在确保高性价比的库表优先得到缓存,同时结合实际的缓存命中情况,动态地调整缓存策略,更好地满足用户实际的查询需求。
我们深入分析了平台数据及相关统计信息,识别出以下几个高频的数据查询范围:
基于这些分析结果,我们决定将缓存策略的粒度细分为:1 天、30 天、60 天和 90 天内更新过的数据。进一步的数据探索,用户对于 30 天和 90 天内的数据更新情况查询得尤为频繁。考虑到缓存空间的实际限制,我们初步决定优先关注 30 天内更新的数据为主的缓存策略。
流程大致如下:
通过审计日志,分析得到库表的访问热度。
结合库表的日均数据增量,进一步计算出 ROI 值。
根据不同的缓存粒度,如 30 天或 90 天,进行窗口累加计算。
利用上述方法,我们以 ROI 的排序为库表选取缓存范围进行缓存规则配置。但在实践过程中,我们也意识到选择的范围并非完全依赖于数值,还需结合实际经验。同时,为确保持续的缓存优化,我们也倾向于引入实时的缓存效果校验的监控机制。
根据以上方式定义了自定义过滤规则后,可以参考 Alluxio 社区提供的默认监控,去调整规则动态选取缓存范围。
参考如下:
开启了缓存的功能后我们遇到了新的问题。因为 presto-gateway 路由策略只有随机路由这一种,会导致查询有可能会路由到没有缓存的集群,或者集群将数据缓存之后相关的查询又不会进入到该集群。最终造成查询的实际缓存命中率较低,缓存数据的换入换出量较大,加速效果不理想。
一个能实现缓存加速的 SQL 约需要触发 25 ~ 30 次的时候才能达到全子集群缓存覆盖,实现秒级返回。
同时,因为 Alluxio Local Cache 的监控指标统计口径问题,容易造成信息混淆从而对缓存命中率判断失真,会误以为缓存命中率高,但是实际的查询却很慢。
监控指标:目前的 Alluxio Local Cache 模式缓存命中率的指标是在 Worker 侧,且统计方式为累计值后的比值,对真实的缓存命中会造成信息混淆,缺乏实际次数,缺乏时间窗口粒度;
路由策略:presto-gateway 的查询路由策略暂时只有一种,随机路由;
缓存预热:PrestoDB 在接收到查询时,如果没有缓存,比 Trino 慢,并且大部分中小型查询在命中缓存后都能达到秒出;
由此可以初步判断,主要问题在于 presto-gateway + 多集群的模式,次要问题在于缓存能力对数据感知能力比较滞后,缺乏预热。另外缓存命中率的问题虽然对提速没有直接影响,但是会对维护造成错误判断,以及无法精确的判断当前的缓存命中情况。
缓存预热问题在开发成本较高,所以不在本次优化中进行。暂时只进行监控指标和路由策略的优化调整。
经过一段时间的维护,PrestoDB 多级缓存的监控指标理想状态如下:
SQL 级别的缓存命中率 (比如 1 个 SQL,某个算子只要命中缓存就参与统计,或者说 SQL 中有哪些算子使用了缓存加速在其中的占比);
原始数据缓存命中率;
分片结果缓存命中率;
元数据缓存命中率;
缓存的换入换出量。
进一步拆解,发现我们对原始数据缓存的真实命中率缺乏,参考 presto-cache 模块,我们可以自行新增监控指标的打点,来上报 hit 与 miss 次数,这样可以结合 metrics 的方式搭配时间窗口进行统计。
修改后,我们发现实际的缓存命中率应该是一个时间窗口波动值,而不是长期的趋势值。同时也发现,实际的命中率是要比之前的命中率要低。
早期使用 Allxuio Local Cache 中的指标,命中率平均能达到 60% ~ 70% 甚至更高。
但是按照重新统计的口径中发现,实际只有 30% 左右。
因为目前的网关路由策略简陋 (只有一个随机路由),所以我们需要对路由策略进行优化,最终的目的是将相近的库表查询分配到同样的集群中。
由此产生了以下新问题:
路由策略制定:根据什么规则策略,查询会固定的落到某个集群?
资源均衡:因为查询有大有小,如何分配才能均衡,避免出现热点集群的情况?当使用某个规则路由查询后,对应的集群资源满了该怎么办?
在此拆解中可以判断,我们应该根据某个条件进行 hash 然后再路由,这样可以保证每次同样的查询进来会固定落到某个集群中,再联想到可以结合集群的负载状态进行相关集群的资源压力判断,此时应该是将查询的路由路径进行固定计算并且与最初的路由形成环,这样才能保证如果最后所有集群都判断了一遍发现无法进行路由,可以落回最初的 hash 路由集群,不对其他的集群造成影响。
秉承着低成本快速验证的原则,我们最终选择如下:
路由策略制定:选择 对查询中所有相关表名排序,取第一个进行 hash 取模路由 方式进行实现。
资源均衡:选择 基于故障 (负载) 切换的负载 方式,暂定为轮询圈数最多就一圈。
上线后最直观的就是,分片缓存的命中率由原来的 5% 上升到 30%,由此可以证明大量的查询都路由到了有缓存的子集群。
上线一段时间后,我们频繁遇到以下错误,导致查询失败:
com.facebook.presto.spi.PrestoException: Error opening Hive split hdfs://hdfs01:8020/***/***/***/b7f59389-6237-44a1-995d-6ffbbd72bf51.parquet (offset=0, length=8859277): Unexpected error in parquet metadata reading after cache miss
at com.facebook.presto.hive.parquet.ParquetPageSourceFactory.createParquetPageSource(ParquetPageSourceFactory.java:355)
at com.facebook.presto.hive.parquet.ParquetPageSourceFactory.createPageSource(ParquetPageSourceFactory.java:555)
at com.facebook.presto.hive.HivePageSourceProvider.createHivePageSource(HivePageSourceProvider.java:431)
Query 20230720_054938_01149_ccwvt failed: Error reading from hdfs://hdfs01:8020/***/date=2023-03-15/hour=14/000316_0 at position 10929617.
我们发现开启 Alluxio Local Cache 的时候,这些元数据也会被一并缓存进来,因为它们也是原始数据的一部分。
所以那些更新比较频繁的库表,尤为容易出现这个问题。
最终关闭了此设置,问题得到解决。
这次从 Trino 迁移到 PrestoDB 我们发现了,在对接 OLAP 引擎时,有几个关键对接点特别重要:
注:这里只罗列了最关键的两个对接点。
账户安全认证集成。
审计日志集成。
在我们使用 Trino 时,集成这两个功能的开发成本相对较低。这是因为 Trino 社区已经预见到许多公司在内部网络中可能使用的不那么严格的安全认证方式(即,用户仅通过输入用户名和密码即可登录,而不需要提供额外的证书)。因此,Trino 内置了一个特定的内部网络认证模式,使得单纯的认证功能集成变得异常简单。而与此相反,PrestoDB 在这方面并没有提供类似的功能,这导致我们不得不参考 Trino 的代码,并进行了大量的代码移植来满足这个需求。
在审计日志方面,我们可以利用引擎自动解析出的库表信息、排队信息等,来进行血缘分析、库表行为评估、饱和度分析等深入的数据分析。然而,PrestoDB 在这方面也存在一些功能空白。为了解决这个问题,我们再次参考了 Trino 的相关功能,并进行了大量的代码移植。
总的来说,尽管 PrestoDB 在某些方面有其独特的优势,但在实际生产场景中,Trino 在基础易用性对接的功能上确实展现出了更为用户考虑的投入和付出。
测试发现在 PrestoDB 中无法使用中文进行字段的比较判断,只能使用 trim,like 等函数嵌套一层,才能查询。
这算是 PrestoDB 一个比较严重的 Bug,我们可以参考 Trino 进行修复。
详情见:https://github.com/trinodb/trino/issues/3517
相较于 Trino,PrestoDB 有如下 udf 函数没有对齐,可以自行参考移植:
parse_data_size;
concat_wc;
format;
format_number。
PrestoDB RaptorX 的分级缓存功能,相较于 Trino,会使用更多的内存。
以 Hive 元数据缓存举例,如果使用了内存模式,其中大量的使用了 com.google.common.cache.LoadingCache,所以需要配置更多的内存,不然容易 OOM。
知乎目前的 Hadoop 已经升级到了 3.X 阶段,并大规模开启了 Hadoop EC 功能。
因为 Trino 迭代的比较快,提早地跟进了所依赖的 Hadoop 版本,支持了 EC。
PrestoDB 比较滞后,所以在使用中会出现如下问题:
Error opening Hive split hdfs://hdfs01:8020/***/***/***/000019_0 (offset=100663296,length=33554432): Unexpected error in parquet metadata reading after cache miss :
at com.facebook.presto.hive.parquet.ParquetPageSourceFactory.createParquetPageSource(ParquetPageSourceFactory.java:355)
at com.facebook.presto.hive.parquet.ParquetPageSourceFactory.createPageSource(ParquetPageSourceFactory.java:555)
at com.facebook.presto.hive.HivePageSourceProvider.createHivePageSource(HivePageSourceProvider.java:431)
文件为 EC 的状态:
因为 PrestoDB 还是用的 hadoop2 的包,所以无法读取 EC 的文件。
这里同样也是在 https://github.com/prestodb/presto-hadoop-apache2 中参考里面的 3.2.x 分支,和 trino https://github.com/trinodb/trino-hadoop-apache 的代码进行修改,重新打包部署后即可完成查询。
注:工程中凡是需要使用 hadoop 的包,这个方式也通用,也可以按需替换。
报表类的中小型查询场景相较于之前,有至少 50% 的性能提升,日常 P50 场景,均为报表类的小 SQL 查询场景,大部分都能在 5 秒内完成。
数据平台视角,查询耗时均呈下降趋势:
P50 视角:
借助 Alluxio Local Cache,我们不仅改进了查询性能,还有效降低了对远端存储的带宽和 I/O 压力。通过智能地缓存热点数据到本地存储,远端数据读取的需求得到了大幅度减少,进一步降低了运营成本。
这次的成功实践也验证了在大数据查询优化方面,硬件资源的合理利用和配置对于整体性能的提升具有不可或缺的作用。只要正确识别并利用现有资源的潜能,即便不增加额外的硬件投入,也能够获得显著的性能提升。
更令人欣喜的是,这种性能提升在实际业务应用中带来的用户体验改善是非常明显的。对于日常报表查询、数据分析等业务场景,查询响应时间的缩短意味着用户可以更加高效地进行数据探索和决策,从而进一步提高整体的工作效率。
我们的这次经验分享,也希望给其他企业在大数据查询优化方面提供一些启示和参考。未来,我们还将继续深入探索和研究,努力在更多的场景和条件下进一步优化查询性能,为业务提供更加稳定和高效的支持。
最后,也是最重要的一点,我们所有的提速优化均在普通 SSD 上进行,就已经达到如此效果。市面上 NVME 的成本也在逐渐衰减,完全使用 NVME 做缓存是能够轻易做到的。届时 Alluxio Local Cache 将如性能猛兽一般,将 Presto 发挥更高的价值。
在现有环境中,深入理解查询行为做好缓存规则的调整和预热是现阶段的优化提速的前提。
单纯的一个 ROI 计算规则生成的缓存策略可能不够,未来我们将引入更多的缓存分析,同时也需要搭配更方便的缓存更新和应用,达到持续优化的目的。
着眼于 Presto 在大数据环境中面临的关键挑战,小文件。规划好小文件治理,有效的合并,合理的 ETL,不光在 Presto 中有帮助,对整个大数据平台都是利好的。
同样,配合数仓 Presto 需要持续提供查询治理功能确保系统资源的最优使用。通过实时的查询跟踪、智能的资源分配和高级的队列管理,为业务保驾护航。
向量化的引入,在 OLAP 引擎中起到了革命性应用,标志着查询处理速度的新纪元。
未来我们将考虑引入 velox 为 Presto 实现查询加速。
参考
Presto 中文 bug https://github.com/trinodb/trino/issues/3517
RaptorX https://prestodb.io/blog/2021/02/04/raptorx
RaptorX https://github.com/prestodb/presto/issues/13205
亲和度 hive https://github.com/prestodb/presto/pull/14095
亲和度 https://github.com/prestodb/presto/pull/13966
Presto 分片缓存实现 https://github.com/prestodb/presto/pull/15155
动态过滤相关 https://trino.io/blog/2020/06/14/dynamic-partition-pruning.html
Alluxio Local Cache https://github.com/Alluxio/alluxio/pull/10748
Alluxio 官方配置参考 https://docs.alluxio.io/os/user/stable/en/reference/Properties-List.html
Alluxio Shadow Cache https://zhuanlan.zhihu.com/p/441933685
Alluxio 监控指南 https://zhuanlan.zhihu.com/p/544775228
Alluxio 挖掘闲置性能 https://zhuanlan.zhihu.com/p/628091188
Alluxio 一致性哈希 https://www.alluxio.com.cn/consistent-hashing/
利用 Alluxio 数据缓存降低 Presto 延迟 https://zhuanlan.zhihu.com/p/526847158
Presto Fragment Result Cache 剖析 https://zhuanlan.zhihu.com/p/527057990
OLAP 场景的查询加速实践 https://mp.weixin.qq.com/s/cWIdal_Szh8fgZTN6gBpig
Presto 的缓存机制 https://zhuanlan.zhihu.com/p/196398077
Uber https://zhuanlan.zhihu.com/p/442876203
金山云 Presto 如何与 Alluxio 搭配 https://zhuanlan.zhihu.com/p/53
微信扫码关注该文公众号作者