Presto系列 | 六、Memory Management

Memory Management

想要正确地配置和管理Presto集群的内存并不是一件容易的事情,这需要靠考虑很多复杂的因素,主要如下。

  • Worker的数量
  • Coordinator和Worker的内存
  • 数据源的数量和类型
  • 查询的特点(小数量的交互查询还是大数据量的批处理)
  • 用户数

Presto是一个多用户系统,同时也是由多个Worker组成的集群,因此其资源管理是一个相当具有挑战性的事情。 通常,我们需要选择一个关注点,配合监视系统并结合当前和即将到来的需求不对的对其进行调整。优化集群的内存在很大程度上依赖于正在运行的工作负载,即需要针对具体的负载类型进行有针对性的优化. 例如,大多数查询包含多个JOIN、Aggregations和窗口函数。如果查询的负载很小,可以将每个查询的内存限制设置的小一些,同时增加并发性。查询的大小可以通过查询类型和处理的数据量来评估。Presto可以通过配置config.properties中的参数来管理内存,主要参数如下

  • query.max-memory-per-node
  • query.max-total-memory-per-node
  • query.max-memory
  • query.max-total-memory

一、Presto将内存划分为两种:

  • User Memory:用于执行汇总、排序等查询时所使用的的内存
  • System memory: 系统为查询引擎本身所提供的内存,包括读写缓冲区、Shuffle、表扫描以及其他操作。

以下参数都是基于这两种内存类型进行配置的:

  • query.max-memory-per-node:在一个worker上。一个查询最大可以使用的User Memory的大小,这些内存主要用于进行聚合操作或者存放输入数据等。

  • query.max-total-memory-per-nodeUser: Memory + System Mempry的最大值,要求大于query.max-memory-per-node,当一个查询分配的User+system的内存大于这个值时,他将被Kill掉;

  • query.max-memory : 一个查询在集群中所有节点上最大可以使用的User Memory大小;

  • query.max-total-memory在整个集群中,一个查询可以使用的User+System Memory的大小。必须大于query.max-memory;

如果一个查询因为超出了这些限制被Kill,同时会提示以下错误:

  • EXCEEDED_LOCAL_MEMORY_LIMIT:意味着query.max-memory-per-node 或者query.max-total-memory-per-node超出了限制
  • EXCEEDED_GLOBAL_MEMORY_LIMIT:query.max-memory或者query.max-total-memory 超出了限制

1.1、案例

让我们看一个真实的案例,该集群由一个Coordinator和10个Worker组成,具体如下:

  • 一个coordinator
  • 10个Worker,通常所有的Worker系统和配置是一样的;
  • 每个Worker的物理内存为50G
  • jvm.config中-Xmx参数配置为38G,即最大的JVM heap
  • query.max-memory-per-node : 13 GB
  • query.max-total-memory-per-node : 16 GB
  • memory.heap-headroom-per-node : 9 GB
  • query.max-memory : 50 GB
  • query.max-total-memory : 60 GB

如上,每个Worker上总共可用的物理内存为50G,我们给操作系统、守护线程以及JVM之外的其他系统组件(如系统监控程序)预留12G内存。因此JVM heap 大小为38G;

当查询很小时,并发可以设置的更高一些。如果我们假设查询是中等或大型的,且允许数据倾斜。那么我们将 query.max-memory 设置成50G,因为这个参数是针对整个集群而言的,所以在配置 query.max-memory 时,我们需要考虑 query.initial-hash-partitions 的值,理想情况下 query.initial-hash-partitions 的值应该小于等于Worker的个数。如果我们配置 query.initial-hash-partitions=8 同时配置max-memory=50那么,50/8=6.25G即如每个节点内存使用的内存为6.25G(假设数据没有倾斜,均匀分布),而上面我们对于的单个节点最大内存的配置是 max-memory-per-node=13G ,即通过预留一倍的空间来应对数据倾斜。

1.2、总结

随着数据分布方式和查询类型的不, 这些参数会有很大的不同。此外,机器的配置和数量也会对此有很大的影响。通过配置 query.low-memory-killer.policy 参数可以避免死锁的发生,该参数可以设置为 total-reservation 或者 total-reservation-on-blocked-nodes

当设置为 total-reservation 时,Presto会杀掉当前集群中最大的查询,以释放资源。
另一方面,当设置为 total-reservation-on-blocked-nodes 时,将会杀掉被锁节点上使用内存最大的查询。

正如你在该例子中看到的,我们在开始时做了一些假设,并对此进行配置,但之后仍然需要根据实际的工作负载进行调整。

例如,如果集群是为用户提供可视化的交互式查询,这种场景通常会产生很多小的查询;同时随着用户的增加也会导致查询数量和并发数的增加。这通常不需要更改内存配置,只是需要增加集群中Worker的个数即可。

另一方面,如果这个小集群添加了一个数据源,且需要对该数据源提供的大量的数据进行复杂的查询,这些查询超出了上面内存的限制,这时你可能需要调整内存了。这就引出了另一个问题,一般建议Presto集群中的所有Worker的配置是一摸一样的,且相同的硬件规格。因此更改这些Worker上的内存通常意味着,对于机器可用物理内存来说新的值可能太大或者太小而无法充分利用整个集群的资源。因此调整内存通常要替换集群中所有的Worker,例如私有云中的虚拟机,或者来自公有云Kubernetes集群中的containers,这些操作或多或少会有些麻烦。

最后值得一提的是,你可能会发现自己对工作负载的评估与实际有很大的不同,例如大量的查询是很小的且执行很快,及时查询的内存占用一般都很小,但是有些却很大,一些包含了很多的分析过程的查询需要较长的运行时间,甚至在一个查询中可能使用不同的数据源。

针对不同的工作负载需要不同的内存配置,甚至是不同的worker配置和监控,此时你需要考虑进一步处理,例如通过使用不同的Presto集群来分离不同的工作负载。

二、Task Concurrency

为了提高Presto集群的性能,可能需要从默认设置中调整某些与任务相关的属性。在本节中,我们将讨论可能需要调优的两个常见属性. 您可以在Presto文档中找到其他几个。所有这些属性都在config.properties中设置:
Task worker threads
默认是机器CPU的个数乘以2。例如,双核处理器的机器使用2 * 6 * 2 共24个worker 线程, 如果你观察到多有的线程都被使用了但是CPU的利用率依旧很低, 你可以通过 task.max-worker-threads 参数增加任务中的CPU数量来提高CPU利用率,从而提高性能。 建议慢慢增加这个数字,因为设置得太高可能会导致负作用,或者由于内存使用量增加和额外的上下文切换而产生不良影响

Task operator concurrency
JOIN 和 Aggregate这些操作符是通过在本地对数据进行分区并并行执行操作符从而实现并行处理的。 例如,按GROUP BY指定的列对数据进行本地分区,然后并行执行多个聚合操作符。 这些并行操作的默认并发性为16。可以通过配置 task.concurrency 来调整改参数。 如果您正在运行许多并发查询,那么由于上下文切换的开销,默认值可能会导致性能下降。 对于只运行少量并发查询的集群,较高的值可以帮助提高并行性,从而提高性能

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值