计算引擎内存管理机制及常见错误处理

更新时间:

本文主要介绍XIHE计算引擎的内存机制和原理,以及在查询中常见的内存相关错误的处理方式和调优方式。

XIHE引擎的内存管理机制

架构图

image
  • 控制节点:解析SQL,生成相应的子任务,并将其调度到特定的计算节点上执行;同时监控各计算节点的内存使用情况。

  • 计算节点:真正负责执行计算逻辑的节点,不同节点之间通过网络shuffle的方式进行数据交换。

    在计算节点中,XIHE引擎将可用的物理内存分配为两个不同的区域:

    • 算子内存

      对于分析型计算引擎而言,存在一些常见的算子(例如:Join、Aggregate、Window、TopN等)。在这些算子的执行过程中,需要在内存中存储一部分临时数据(例如,JOIN操作中的hash probe表、Aggregate操作时产生的中间结果)。在相应的算子逻辑执行完成之前,临时数据占用的内存无法释放。此外,这类内存的占比较大,且与查询所处理的数据量直接相关,可能达到百GBTB级别。为优化这类算子所使用的内存,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,从而导致内存不足的问题。

您可以通过 算子级别诊断结果 确认是否存在该问题。

以下解决方式任选一种即可:

数据倾斜

对于JOINAggregate等操作,即便整体数据量有限,若由于分布键不均而导致所有数据集中在单个节点上进行处理,仍可能触发该节点的算子内存上限阈值,从而引发错误。

您可以通过 Stage级别诊断结果 确认是否存在该问题。

  • 建议从业务层面进行优化。例如:在SaaS类应用中对大客户进行单独计算,或在计算之前过滤掉null等异常值。

  • 若在建表时就存在倾斜现象,也可能会导致类似问题,请参考表倾斜诊断的优化方法处理。

数据量过大或数据膨胀

数据膨胀通常发生在不合理的JOIN条件或JOIN顺序中,这不仅会导致查询执行速度降低,还可能引发内存不足等错误。如果原始业务数据量过大,同样可能导致类似问题的出现。

以下解决方式任选一种即可:

  • 如果是数据本身特征导致的Join数据膨胀,例如左右表都大量存在的相同的值,可对这些值单独处理;如果是Join顺序问题导致的数据膨胀,可以手动调整Join顺序

  • 避免使用交叉连接。

  • 可以增加任务处理的并行度(hash_partition_count),让数据更加分散,以便使用更多计算资源来执行。

聚合时基数过大

常见于Aggregate算子或Window算子中(partition by字段),由于唯一值过多导致聚合效果不佳,同时消耗了大量内存。

  • 取消两阶段聚合。具体操作,请参见分组聚合查询优化

  • 增加任务处理的并行度(hash_partition_count)。

  • 对于COUNT DISTINCT类操作,可在SQL语句前添加Hintoptimize_multi_mark_distinct=true

Query exceeded system memory pool limit

流式内存不足,导致出现该报错。导致流式内存不足的原因及解决方法如下:

原因

说明

解决方案

查询了某些较大的VARCHAR字段

XIHE内部,多个数据行将被合并为一个批次进行处理。当查询某些较大的VARCHAR字段(例如JSON、富文本等)时,这些行所占用的临时内存可能会显著增加,从而触发流式内存上限,进而导致报错。

以下解决方式任选一种即可:

  • 在业务侧优化SQL,以避免过多的较大VARCHAR字段参与计算。

  • 在建表过程中,请适当调小block_size参数

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)执行模式下,查询的执行速度可能降低。您可以在集群级别或查询级别切换查询的执行模式