[toc]
https://blog.csdn.net/gv7lzb0y87u7c/article/details/81049861?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0.no_search_link&spm=1001.2101.3001.4242
https://blog.csdn.net/sjtuyunlei/article/details/90369926
https://zhuanlan.zhihu.com/p/101366898
presto内存空间分配#
- System Pool 是用来保留给系统使用的,默认为40%的内存空间留给系统使用。
- Reserved Pool和General Pool 是用来分配query运行时内存的。
- 其中大部分的query使用general Pool。 而最大的一个query,使用Reserved Pool, 所以Reserved Pool的空间等同于一个query在一个机器上运行使用的最大空间大小,默认是10%的空间。
- General则享有除了System Pool和General Pool之外的其他内存空间。
- 在真正执行物理计划前,内存需求都来自于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运行。
保留池选举机制#
Presto内存管理,分两部分:
- query内存管理
- query划分成很多task, 每个task会有一个线程循环获取task的状态,包括task所用内存。汇总成query所用内存。
- 如果query的汇总内存超过一定大小,则强制终止该query。
- 机器内存管理
- coordinator有一个线程,定时的轮训每台机器,查看当前的机器内存状态。
当query内存和机器内存汇总之后,coordinator会挑选出一个内存使用最大的query,分配给Reserved Pool。
内存管理是由coordinator来管理的, coordinator每秒钟做一次判断,指定某个query在所有的机器上都能使用reserved 内存。
如果某台机器上,,没有运行该query,那岂不是该机器预留的内存浪费了?为什么不在单台机器上挑出来一个最大的task执行?#
原因还是死锁,假如query,在其他机器上享有reserved内存,很快执行结束。但是在某一台机器上不是最大的task(即这个task在另一个节点可能只排第二名,被另一个大作业占了保留池, 导致下一步卡住了,无法连续的执行),一直得不到运行,导致该query无法结束。
所以首要目的是保证 此刻已感知到的最大作业尽快执行完毕。
空间不足时杀query的逻辑#
https://blog.csdn.net/eagooqi/article/details/109595271
每次作业提交存在会话级别的配置
query_max_memory 本次查询规定的最大内存
在轮询过程种如果发现内存超出本次查询上限内存, 会杀掉这个query。
还有个会话配置resource_overcommit
如果设为true,后面即使内存暂时超出单作业规定内存,业不会被杀掉
但如果整个集群的内存出现不足,他仍然会被杀掉
集群内存不足的判定:
存在某个worker节点的内存池出现内存不足(即该节点阻塞了),则认为发生了内存溢出