Presto内存管理包括了单机和集群粒度的内存,有如下参数设置:
- query.max-memory-per-node:单个Query在单个Worker上允许的最大 user memory
- query.max-total-memory-per-node:单个Query在单个Worker上允许的最大 user memory + system memory
- query.max-memory:单个Query在整个集群上允许的最大 user memory
- query.max-total-memory:单个Query在整个集群上允许占用的最大 user memory + system memory
乍看之下,感觉还是很简单的,其实这里面有个大坑!
在填坑之前,有必要给大家铺垫一些Presto的基础知识:
1、Presto的2种内存
- 一种是user memory,用于 input/output/exchange buffers 等
- 另一种是system memory,用于 hash join、agg等
2、Presto的内存池
Presto在版本0.201之前有3种内存POOL,分别是 GENERAL_POOL、RESERVED_POOL 及 SYSTEM_POOL。但是0.201之后,默认 SYSTEM_POOL 是不开启的,由以下参数控制,默认值为false
deprecated.legacy-system-pool-enabled
简单来说,0.201之后,GENERAL_POOL 扮演了之前 GENERAL_POOL 及 SYSTEM_POOL 的作用,提供 user memory 和 system memory。
另外,RESERVED_POOL 作用就是当 GENERAL_POOL 满的时候,将最占用内存的SQL分配到这块内存上来,但是实际使用时,这块内存很少会被使用,原因是:
- 一般使用Presto的业务是用来SQL提速的,不会使用 spill to disk 功能
- 第二,为了服务的稳定性,会限制最大内存和Kill内存策略,所以会出现查询没有被分配到 RESERVED_POOL 之前,SQL将会被系统Kill掉
- 第三,大查询一般会用 Spark/Hive 替代
所以,对于绝大部分Presto使用者,禁止掉 RESERVED_POOL 是正确的选择。
3、新增加的heap-headroom-per-node参数
memory.heap-headroom-per-node
这个内存主要是第三方库的内存分配,无法被统计跟踪,默认值是 Xmx*0.3。
所以,一般情况下,Presto内存分配只需要考虑 GENERAL_POOL 及 heap-headroom-per-node。
4、如何设置 GENERAL_POOL?(天坑)
大多数同学容易将 query.max-total-memory-per-node 这个参数当作是 GENERAL_POOL,这是不对的。其实 query.max-total-memory-per-node 这个参数是设置 RESERVED_POOL 的,即:
RESERVED_POOL = query.max-total-memory-per-node
GENERAL_POOL 不是通过参数直接设置的,需要计算一下:
GENERAL_POOL = Xmx - RESERVED_POOL - memory.heap-headroom-per-node
如果禁用掉 RESERVED_POOL:
GENERAL_POOL = Xmx - memory.heap-headroom-per-node
举个栗子,假如 -Xmx80g,Worker数大于8台:
query.max-memory=120GB # 默认为20GB,query.max-memory-per-node * 8 * 0.8 ,倾斜按照0.8算即可
query.max-memory-per-node=20GB # 默认值0.1*Xmx,一般线上按照0.25*Xmx算,这个最好结合自己并发,如果并发大,大查询多,值最好小一点,稳定性考虑
query.max-total-memory-per-node=32GB # 默认值0.3*Xmx,一般设置为0.4*Xmx
experimental.reserved-pool-enabled=false # 不使用RESERVED_POOL
memory.heap-headroom-per-node=16GB # 默认0.3*Xmx,一般使用的是0.2*Xmx
query.low-memory-killer.policy=total-reservation-on-blocked-nodes # Kill策略,干掉Blocked的最大查询,GENERAL_POOL满了,防止OOM
按照上面的配置,在不使用 RESERVED_POOL 的情况下,GENERAL_POOL = 80GB - 16GB = 64GB。
骚年,你学废了吗?