presto是如何保证作业内存不会发生冲突和溢出?presto内存管理机制深入分析
首先,presto分了如下3个内存池
System Pool
System Pool,指系统内存池,是用来保留给系统和缓冲区使用的,默认为40%的内存空间留给系统使用。
看来对于presto来说,作业之间的缓冲区是存在共用的,认为是系统、通用层面的部分。
General Pool
常规内存池,用来分配每个query运行时内存的。
其中大部分的query使用general Pool。
Reserved Pool
保留内存池,用来为可能突然触发的超大作业进行内存保留分配。
即最大的一个query,会使用Reserved Pool
Reserved Pool的空间等同于一个query在一个机器上运行使用的最大空间大小,默认是10%的空间。
在真正执行物理计划前,内存需求都来自于systemMemoryPool,包括临时数据结构,传输buffer等
执行物理计划时,不同的Operator类型都根据需要申请内存,比如aggregationOperator使用getEsctimatedSize()方法预估需要的内存。
这里获取的内存来自于reservatedMemoryPool或者generalMemoryPool,究竟使用哪个pool取决于当前查询是否耗用内存最大
问:为什么要引出一个Reserved内存池且只提供给1个作业使用?
如果没有Reserved Pool, 那么当query非常多,并且把内存空间几乎快要占完的时候,某一个内存消耗比较大的query开始运行。
但是这时候已经没有内存空间可供这个query运行了,这个query一直处于挂起状态,一直在等待可用的内存。
但是其他的小内存query跑完后, 可能只腾出一点点的空间, 又有新的小内存query加进来。由于小内存query占用内存小,很容易找到可用内存。 这种情况下,大内存query就一直挂起直到饿死。
所以为了防止出现这种饿死的情况,必须预留出来一块空间,共大内存query运行。 预留的空间大小等于query允许使用的最大内存。Presto每秒钟,挑出来一个内存占用最大的query,允许它使用reserved pool,避免一直没有可用内存供该query运行。
保留池的选举机制(Reserved池是如何选出来的)
如下图所示:
Presto内存管理,分两部分:
1. query内存(作业内存)管理
query划分成很多task, 每个task会有一个线程循环获取task的状态,包括task所用内存。汇总成query所用内存。
如果query的汇总内存超过一定大小,则强制终止该query。
2. 机器内存管理
coordinator有一个线程,定时的轮训每台机器,查看当前的机器内存状态。
当query内存和机器内存汇总之后,coordinator会挑选出一个内存使用最大的query,分配给Reserved Pool。
内存管理是由coordinator来管理的, coordinator每秒钟做一次判断,指定某个query在所有的机器上都能使用reserved 内存。
问:如果某台机器上,,没有运行该query,那岂不是该机器预留的内存浪费了?为什么不在单台机器上挑出来一个最大的task执行?
原因还是死锁,假如query,在其他机器上享有reserved内存,很快执行结束。但是在某一台机器上不是最大的task(即这个task在另一个节点可能只排第二名,被另一个大作业占了保留池, 导致下一步卡住了,无法连续的执行),一直得不到运行,导致该query无法结束。
所以首要目的是保证 此刻已感知到的最大作业尽快执行完毕。
如何在内存不足时杀掉不需要的query?
每次作业提交存在一个会话级别的配置 query_max_memory,即本次查询规定的最大内存
在轮询过程种如果发现内存超出本次查询上限内存, 会杀掉这个query。
还有个会话配置resource_overcommit
如果设为true,后面即使内存暂时超出单作业规定内存,业不会被杀掉
但如果整个集群的内存出现不足,他仍然会被杀掉
- 集群内存不足的判定:
存在某个worker节点的内存池出现内存不足(即该节点阻塞了),则认为发生了内存溢出
- 点赞
- 收藏
- 关注作者
评论(0)