概况
为了预防内存紧张的operator,presto允许将中间操作的结果转存到磁盘上。这个机制的目的是为了让那些需要的内存超过一台机器一个query内存限制的query能够执行。
这个机制类似于操作系统级的页交换。但是,它是被应用在应用程序级去满足presto的特殊需求。
溢写的属性在https://prestodb.io/docs/current/admin/properties.html#tuning-spilling这里描述
内存管理和溢写
默认情况下,presto杀掉那些执行内存超过会话属性query_max_memory 或 query_max_memory_per_node。这个机制保证内存的公平分配,防止内存分配造成死锁。当集群中有很多小查询的时候,这是非常有效的。但是会杀掉那些超过限制的大查询。
为了克服这个问题,可撤回的内存概念被提出。一个查询可以请求不限制的内存,但是这个内存可以被任何时候被内存管理回收。当内存被回收,这个查询在内存中的数据被溢写到磁盘上,稍后继续处理。
事实上,当集群是空闲的时候,所有内存都可以获取,一个消耗内存的查询可以用完整个集群的内存。相反的,当集群没有足够的内存,同样的查询当前的数据被强制写到磁盘上。被溢写到磁盘上的查询可能有一个较长的执行时间比完全在内存中运行。
请注意开启溢写到磁盘机制不保证消耗内存的查询运行成功。当加载数据到内存的时候,查询运行程序可能无法将中间数据划分为足够小的块,以便每个块都适合于内存,导致 out of memory 错误。
溢出磁盘
溢写中间数据到磁盘,然后再加载到内存是一个高IO的操作,因此,磁盘可能是这些查询的瓶颈。为了提高性能,建议在分开的磁盘上提供多重路径。相关属性https://prestodb.io/docs/current/admin/properties.html#tuning-spilling。
系统驱动盘不要被用作溢写,也不要运行在JVM运行和写日志的地方。这样做可能会导致系统不稳定。除此之外,建议监控溢写路径磁盘的饱和状态。
presto将溢写路径作为独立的磁盘,没有必要用 RAID 做溢写。
支持的操作
不是所有的操作支持溢写到磁盘,每一个处理溢写不同。目前,这个机制被用于如下操作。
Joins
在join期间,其中一个表被存在内存。这个表被称为生成表。如果另一张表里的记录与生成表里的记录匹配,则被传递给下一个操作。join中最费内存的部分就是生成表。
当任务的并发性大于1,生成表被分区。分区的数目等于任务的并发数task.concurrency 。属性配置如https://prestodb.io/docs/current/admin/properties.html#task-properties
当生成表被分区,溢写磁盘机制能降低join操作需要内存的峰值。当一个查询接近内存限制,生成表的部分分区被溢写到内存,与此同时,这些分区内的另一张表的记录也被写入磁盘。被溢写到磁盘的分区数量决定着占用磁盘空间的大小。
后面,被溢写的分区一个一个的读会内存,完成join操作。
有了这个机制,join操作使用的内存峰值被降低到生成表的最大分区的大小。假设没有数据倾斜,这将是整个生成表的 1/task.concurrency
Aggregations
聚合函数处理一组数据返回一个值。如果分组数目非常大,需要的内存也自然就很多。当启动溢写机制,直接计算的聚合结果被写到磁盘,当有内存资源的时候,它被读入内存合并。
来源:oschina
链接:https://my.oschina.net/u/2000675/blog/2056427