Trino集群优化:Trino的磁盘溢写配置

Trino 在执行数据量比较大的查询经常会遇到 OOM 的问题。为了解决这个问题,Trino 支持将计算的中间结果写到磁盘上,这个机制设计的目标是:当查询所需要的内存超过了单个查询设置的最大内存或者单个节点的最大内存时,可以继续执行,而不会因为内存不足导致查询失败。

默认情况下,当查询请求的内存超过了query_max_memory 或者 query_max_memory_per_node 设置的值后,Trino 会 kill 掉查询请求。Trino 的这种机制在处理大量小查询时可以提高效率;但对于大型查询,可能导致在超出内存限制的时候被 kill 掉。

开启 spill-to-disk

为了解决内存使用上的低效率问题,引入了一种称为"可回收内存"的概念, 即:开启spill-to-disk功能。当内存被回收时,查询执行器会将中间数据从内存中溢出到磁盘上,并在稍后继续处理这些数据。

当集群空闲,并且所有内存都可用时,一个内存密集型的查询可能会使用集群中的全部可用内存。另一方面,当集群中没有足够的空闲内存时,同样的内存密集型查询可能会强制使用磁盘作为中间存储。如果查询溢出到磁盘,那么它的执行时间将会比完全在内存中运行长很多。

?注意:

尽管启用了spill-to-disk功能,但是并不能保证所有内存密集型查询都能成功执行。

查询执行器在处理过程中,可能无法将中间数据分割成足够小的块,以至于每个数据块都能被装入内存中,导致从磁盘加载数据时也会遇到 OOM 的错误。

所以,磁盘溢出(spill-to-disk)是一种缓解内存压力的机制,但它并不能完全解决所有内存密集型查询的内存问题。

磁盘配置

将中间结果溢出到磁盘上,然后再次取回,这种I/O操作是相当昂贵的。因此,使用磁盘溢出(spill-to-disk)的查询很可能受限于磁盘性能。为了提高查询性能,建议在配置spiller-spill-path时配置多个磁盘路径。

不能使用系统盘作为溢出存储,否则会导致集群不稳定。此外,建议监控这些磁盘的情况,避免出现磁盘空间不足。

Trino将溢出路径视为独立的存储单元,因此不需要使用Raid技术。

配置压缩

当配置了spill-compression-codec属性,数据在溢出磁盘之前会被压缩。启用这个特性可以在一定程度上减少磁盘的I/O操作,但是代价是需要更多的CPU资源来执行压缩和解压缩。

配置加密

当配置了spill-encryption-enabled属性,溢出到磁盘的数据会被随机生成的密钥加密,这个密钥是针对每个溢出文件单独生成的。启用加密功能会增加 CPU 的负载,并降低数据写入磁盘的吞吐量,但可以防止溢出的数据被从溢出文件中恢复出来。建议降低memory-revoking-threshold的值,以适应由于加密带来的延迟增加。

哪些操作支持 spill-to-disk

并非所有操作都支持磁盘溢出特性(spill-to-disk),而且每个操作在处理数据溢出时的方式也各不相同。以下这些操作支持磁盘溢出:

1. join

执行 join 操作时,其中的一个表会存储在内存中,被称为build table,其他表会和build table进行匹配,最耗内存的部分就是这个build table

当任务的并行度大于1时,build table会被分为多个分区。分区的个数取决于任务的并行度配置(task.concurrency)。

build table被分区时,"溢写到磁盘"(spill-to-disk)机制可以减少 join 操作所需的峰值内存使用量。当查询达到内存限制时,build table的一部分分区会被溢写到磁盘上。同时,其他表中属于这些被溢写分区的行也会被写入磁盘。如果有更多的分区需要溢写,那么就需要更多的磁盘空间来存储这些数据。

最后,那些因为内存不足而临时存储到磁盘上的数据分区将被逐个重新读取回内存,以便完成整个join操作。

通过将build table分区并可能将部分数据溢出到磁盘,可以有效地控制内存使用量,使得连接操作的内存需求不超过单个最大分区的大小。这样可以在处理大量数据时,避免内存不足的问题,提高查询的效率和稳定性。

2. Aggregation

聚合函数对一组值执行操作,并返回一个值。当聚合操作涉及的分组数据很大时,可能需要大量的内存,如果开启了磁盘溢写功能,当内存不足时,会将中间的聚合结果写入磁盘以释放内存。最后,这些写入磁盘的数据会被重新加载回内存,并与其他数据合并,这个过程称为"merge"。

3. Order by

当尝试对大量数据进行排序时,可能会需要相当大的内存空间。如果启用了针对排序操作的磁盘溢出功能,当内存不足以容纳所有中间排序结果时,这些中间结果就会被写入到磁盘上。一旦内存空间变得可用,这些存储在磁盘上的数据会被重新加载回内存,并以占用更少内存的方式进行合并处理。

4. Window functions

窗口函数对窗口中的数据行进行操作,并为每行数据返回一个值。如果窗口数据很大,就需要大量内存。如果开启了磁盘溢写功能,当内存不足时,这些中间结果就会被写入到磁盘上。当内存再次可用时,这些写入磁盘的中间结果会被重新加载并合并,以继续处理。当单个窗口数据很大时,磁盘溢写功能并不会生效。

写在最后

磁盘溢出功能是 Trino 的遗留功能,不建议使用磁盘溢出功能,建议使用 Trino 的容错执行,配置相应的重试策略,并配置 exchange-manager 来增强 Trino 集群的稳定性。下一篇继续分享 Trino 的容错执行,磁盘溢出功能了解即可,毕竟官方也不太推荐这种方式。


往期推荐



Trino 动态Catalog 体验

如何在 Ipv6 环境中使用 Trino 的 Hive Catalog

如何正确使用 Trino 的资源组


请使用浏览器的分享功能分享到微信等