1. Presto的内存模型
presto涉及到的内存分为堆内和堆外内存,堆内内存大小有jvm.config的Xmx参数指定,堆外内存由jvm.config的MaxDirectMemorySize参数指定。presto在lzo等数据源压缩文件的解压过中会使用到。官方建议是将堆内内存的Xmx和Xms设置为系统总内存的80%,剩余的留给堆外内存使用。
在堆内分成两大块,一块是预留/缓存区的内存,大小由memory.heap-headroom-per-node参数指定指定,这块内存presto没有参与管理,是预留给jvm调度,第三方库开销等场景下使用。另外一块是由presto管理的堆内内存,由query.max-total-memory-per-node参数指定。memory.heap-headroom-per-node + query.max-total-memory-per-node的值必须小于Xmx的值。官方建议是memory.heap-headroom-per-node占30%左右的大小。
presto将query.max-total-memory-per-node又分成两块,一块是用户内存,一块是系统内存。用户内存用于聚合和排序操作,系统内存用于shuffle,表扫描等操作。
所有worker的query.max-total-memory-per-node加起来就是整个presto集群可用的总内存query.max-total-memory,所有worker的query.max-memory-per-node加起来就是集群可用的用户内存query.max-total-memory。
2. Presto的内存管理
presto将用户内存和系统内存都使用内存池的方式进行管理,避免不断的申请回收导致性能下降。
presto的内存申请是在Operator操作中完成的。
比如TableScanOperator中申请的系统内存:
public Page getOutput()
{
......
// updating system memory usage should happen after page is loaded.
systemMemoryContext.setBytes(source.getSystemMemoryUsage());
if (strategy.equals(REUSE_STRATEGY_PRODUCER) && page != null) {
setPage(page);
}
return page;
}
比如AggregationOperator中申请的用户内存
public void addInput(Page page)
{
.....
if (useSystemMemory) {
systemMemoryContext.setBytes(memorySize);
}
else {
userMemoryContext.setBytes(memorySize);
}
}