计算引擎内存管理机制及常见错误处理
本文主要介绍XIHE计算引擎的内存机制和原理,以及在查询中常见的内存相关错误的处理方式和调优方式。
XIHE引擎的内存管理机制
架构图
控制节点:解析SQL,生成相应的子任务,并将其调度到特定的计算节点上执行;同时监控各计算节点的内存使用情况。
计算节点:真正负责执行计算逻辑的节点,不同节点之间通过网络shuffle的方式进行数据交换。
在计算节点中,XIHE引擎将可用的物理内存分配为两个不同的区域:
算子内存
对于分析型计算引擎而言,存在一些常见的算子(例如:Join、Aggregate、Window、TopN等)。在这些算子的执行过程中,需要在内存中存储一部分临时数据(例如,JOIN操作中的hash probe表、Aggregate操作时产生的中间结果)。在相应的算子逻辑执行完成之前,临时数据占用的内存无法释放。此外,这类内存的占比较大,且与查询所处理的数据量直接相关,可能达到百GB或TB级别。为优化这类算子所使用的内存,XIHE预留了相应的内存,即算子内存,使这类算子的内存申请与使用更加高效。
流式内存
在计算逻辑的执行过程中,会生成各种临时对象,例如在shuffle操作时产生的临时数据缓冲区、算子内部的数据交换以及TableScan的临时缓存等。这类对象的特征是生命周期短、申请和释放速度较快。它们所消耗的内存在XIHE中被称为流式内存。
优势
XIHE引擎能够将计算任务拆分并分配至多个节点并行执行,从而显著提升数据处理速度。同时,它具备高容错性和可扩展性,能够高效处理海量数据。其主要特性包括:
并行计算:将大数据任务分解为多个子任务,并在集群节点上并行执行,以缩短计算时间。
弹性扩展:支持动态增减计算节点,以适应不同规模的数据处理需求。
多种计算模型:支持实时查询(MPP)、批处理(Batch)等多种计算模式。
防护机制
为了保证计算引擎的稳定性,避免单一大查询导致节点故障进而影响整个集群可用性,XIHE引擎对于算子内存和流式内存的使用增加了相应的限制,包括:
单查询限制:当单个查询所使用的算子内存过多时(例如在Join操作时耗尽了算子内存),该查询继续申请内存将会直接失败。
节点级别限制:单个节点上的算子内存和流式内存均设有上限阈值。当内存耗尽后,后续的查询都会失败。
集群级别的OOM kill机制:当整个集群内存不足时,控制节点将选择终止当前内存消耗最大的查询,以释放内存供其他查询使用。
常见问题
Query exceeded reserved memory limit / Out of Memory Pool size pre cal. available
算子内存不足,导致出现该报错。导致算子内存不足的原因及解决方法如下:
原因 | 说明 | 解决方法 |
Join顺序 | 在Join计算过程中,XIHE优化器会自动估算合适的Join顺序,以确保基于较小的表进行Build;然而,当统计信息过期或由于其他原因导致优化器的预估不准确时,可能会基于大表进行Build,从而导致内存不足的问题。 您可以通过 算子级别诊断结果 确认是否存在该问题。 | 以下解决方式任选一种即可:
|
数据倾斜 | 对于JOIN和Aggregate等操作,即便整体数据量有限,若由于分布键不均而导致所有数据集中在单个节点上进行处理,仍可能触发该节点的算子内存上限阈值,从而引发错误。 您可以通过 Stage级别诊断结果 确认是否存在该问题。 |
|
数据量过大或数据膨胀 | 数据膨胀通常发生在不合理的JOIN条件或JOIN顺序中,这不仅会导致查询执行速度降低,还可能引发内存不足等错误。如果原始业务数据量过大,同样可能导致类似问题的出现。 | 以下解决方式任选一种即可:
|
聚合时基数过大 | 常见于Aggregate算子或Window算子中(partition by字段),由于唯一值过多导致聚合效果不佳,同时消耗了大量内存。 |
|
Query exceeded system memory pool limit
流式内存不足,导致出现该报错。导致流式内存不足的原因及解决方法如下:
原因 | 说明 | 解决方案 |
查询了某些较大的VARCHAR字段 | 在XIHE内部,多个数据行将被合并为一个批次进行处理。当查询某些较大的VARCHAR字段(例如JSON、富文本等)时,这些行所占用的临时内存可能会显著增加,从而触发流式内存上限,进而导致报错。 | 以下解决方式任选一种即可:
|
SELECT时扫描的列过多 | 如果单个列的大小有限,而参与计算的列数过多,同样会导致所占用的临时内存增加,从而触发流式内存的上限。 | 在业务侧优化SQL,避免SELECT时扫描其它多余列,确保只扫描必要的列。 |
查询并发数过高 | 多个查询并发执行时,它们所占用的流式内存总和可能会触发流式内存上限,从而导致后续执行的查询出现错误。 |
The cluster is out of memory, and your query was killed
原因:集群整体的内存不足,触发了控制节点的OOM kill机制。
解决方法:需要逐一分析内存占用较大的查询,并依据上述方法进行优化。具体操作,请参见典型慢查询和查看查询属性与诊断结果。
Query exceeded revocable per request limit / Query exceeded unspill memory limit
原因:此类错误仅在批处理模式(Batch)下出现,通常是由于查询的并发度较低,导致单个节点上的数据量过大。
解决方法:增大查询并发度(batch_hash_partition_count),默认并发度为32,此时可调整为64。例如/* batch_hash_partition_count=64 */
。如果是Join查询,可以增大使用哈希桶的总数量(hybrid_hash_join_bucket_num),默认总数量为16,此时可调整为32。例如/* hybrid_hash_join_bucket_num=32 */
。
调优方法
除了上述查询级别的解决方法外,您还可以通过资源弹性、隔离、作业投递等方法优化系统性能,避免出现因内存不足导致查询失败的情况。
资源组隔离
资源组能够实现不同查询之间计算资源的物理隔离,避免查询间的相互影响。例如,对于SLA要求较高的关键查询,可以采用独立的资源组进行执行,以防受到其他低优先级查询的干扰。同时,资源组支持配置资源弹性计划,能够通过时间或负载的方式实现资源的自动扩缩容,从而有效缓解内存不足的问题。
Serverless投递
在企业版、基础版及湖仓版集群中,可开启自动投递功能。开启后,系统会自动将由于内存不足而报错的查询投递至Job型资源组中运行。企业版、基础版及湖仓版集群每月会提供自动投递的免费使用额度,且Job型资源组会根据所运行作业的大小动态拉起资源,有效降低了使用成本。
批处理(Batch)执行模式
在批处理(Batch)执行模式下,若出现查询内存不足的情况,系统会自动进行溢出处理(spill),将数据写入磁盘,避免因内存不足而导致查询失败。然而由于写入磁盘和调度模式变化等因素的影响,在批处理(Batch)执行模式下,查询的执行速度可能降低。您可以在集群级别或查询级别切换查询的执行模式。