欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

【OceanBase诊断调优】—— 执行内存占用高问题汇总

最编程 2024-06-03 16:35:24
...

执行内存占用高问题经常在不同环境中遇到, 在内存较大的租户场景下, 问题可能暴露不明显, 但小规格场景下, 如果执行内存占用非常高, 往往有上 G 甚至几十G 的情况, 可能导致整个租户无内存使用。本文汇总执行内存占用高问题。

获取内存高的 mod 的代码 backtrace 方式

对于执行内存占用高的问题,可以使用常态化 memory leak 诊断工具 获取代码 backtrace。一般通过以下步骤可以获取到占用内存高的代码堆栈,具体方法如下。

  • 在 OceanBase 数据库 V2.x、V3.x 版本。

    1. 在 SYS 租户中,打开 mem_leak 监控。

      obclient> alter system set leak_mod_to_check='OB_COMMON_ARRAY';
      
    2. 等待内存模块增长一段时间后,执行如下 SQL 查看泄露堆栈。

      obclient>SELECT * FROM oceanbase.__all_virtual_mem_leak_checker_info ORDER BY alloc_count DESC;
      
    3. 找到 alloc_count 最多的堆栈,通过 addr2line 获取函数名。

      addr2line -pCfe /home/admin/oceanbase/bin/observer xxxxx
      
    4. 联系 OceanBase 数据库技术支持人员协助排查。

    5. 关闭 mem_leak。

      由于打开 mem_leak 监控影响性能,问题定位后及时将 mem_leak 监控关闭,命令如下。

      obclient> alter system set leak_mode_to_check='';
      
  • 在 OceanBase 数据库 V4.0 及以上版本。

    1. 通过视图 GV$OB_MEMORY, 获取占用内存较高的 mod_name。

    2. 通过 mod_name 获取 backtrace。

      select * from oceanbase.__all_virtual_malloc_sample_info where mod_name='xxx' order by alloc_size desc limit 10;
      
    3. 解析 backtrace。

      addr2line -pCfe bin/observer 0x4209973 0x3d56e15 0x3d56d0a 0x41f6ec4 0xe2663a9 0xe266542 0x113e7f85 0xed77810 0xd28eaff 0xd28ea56 0x6f7fe47 0x41dfaec 0x7f80d3580445 0x41dc315
      

执行内存占用高的问题

SqlExecContext 模块

问题描述

repeatspace 等表达式向量化场景 SqlExecContext 模块内存膨胀到 10+g。

问题原因

repeatspace 的结果内存大小不可控,且结果长度很大时仍使用的 varchar 类型存储,在向量化场景会进一步放大内存使用,导致内存很高。

问题诊断
  1. 执行语句中含有 repeat/space 表达式。

  2. 泄漏堆栈中存在如下堆栈信息。

    oceanbase::sql::ObExpr::alloc_str_res_mem()
    oceanbase::sql::ObExprStrResAlloc::alloc()
    oceanbase::sql::ObExprRepeat::repeat()
    
解决方法

OceanBase 数据库 V4.2 版本缓解,V4.3 版本彻底解决。

multi table replace 算子模块

问题描述

SQL_EXEC_CTX_ID 内存膨胀至 190G,租户内存爆。

问题原因

OceanBase 数据库 V3.x 版本的 multi_part_xxx 计划因为未作多批次写入流程,所有的数据都会被 load 在本地,所以当数据量很大的时候,会发生严重的内存膨胀。

问题诊断
  1. 存在 replace into 算子。

  2. 堆栈中存在如下信息。

    oceanbase::sql::ObChunkDatumStore::switch_block(long) 
    oceanbase::sql::ObChunkDatumStore::add_row(
    oceanbase::sql::ObMultiTableReplaceOp::load_replace_row
    oceanbase::sql::ObMultiTableReplaceOp::inner_open()
    
解决方法

OceanBase 数据库 V3.2.3 版本之前存在但不是很明显,V3.2.3 及之后版本, 开向量化时该场景内存使用会明显增加,注意 V3.2.3 版本尚未解决。

聚合函数的参数含 distinct 模块

问题描述

distinct aggration + 向量化场景下内存占用高问题。

问题原因

向量化中会维护 256 组聚合,每组都会用 sort 做去重,导致这里用内存太多。

问题诊断
  1. 执行语句中,聚合函数的参数含 distinct, 比如 sum(distinct c1) 等。

  2. 通过命令过滤内存分配报错日志信息。

    grep 'add row to distinct set failed'
    
解决方法

OceanBase 数据库 V4.2 版本缓解,V4.3 版本彻底解决。

SqlExecutor 模块

问题描述

batch insert 场景内存使用高。

问题原因

insert values 类型 SQL 后跟多行数据时,硬解析时,内存膨胀,另外行数不固定,可能导致不能命中 plan_cache,出现并发硬解析时,同时占用内存就很大。

问题诊断

执行语句为 batch insert,比如 insert into ... values(...), (...), (...) ... ...

解决方法

OceanBase 数据库 V4.0 版本已进行优化,默认关闭,还存在 bad case,而在 V4.3 版本会默认打开优化。优化打开命令。

ALTER SYSTEM SET ob_enable_batched_multi_statement = true;

SqlExecutor/CostBasedRewrite 模块

问题描述

in 个数或 or 很多时, query range 抽取内存占用高。

问题原因

抽取 query range 时,反复深拷导致内存占用高。

问题诊断
  1. SQL 语句中含有大量 in 或者 or 条件。

  2. 使用内存高的 backtrace 中,含有 ObQueryRange。

解决方法

OceanBase 数据库 V4.2 版本解决。

SqlWindoRowStor 模块

问题描述

window function 中,存在某个组数据很多情况场景, 内存占用高。

问题原因

window function 未接入自动内存管理,当前落盘阈值太高。

问题诊断
  1. 通过 SqlWindoRowStor 直接判断。

  2. 执行语句中,含有 over 关键字。

  3. 使用内存高的 backtrace 中,含有 ObWindowFunctionOp::RowsStore::add_row

解决方法

OceanBase 数据库 V4.2 版本解决。

SqlAggrFunGroCo 模块

问题描述

groupconcat aggregate + 向量化场景, 内存占用高问题。

问题原因

groupconcat aggregate 没接自动内存管理。

问题诊断
  1. 通过 SqlAggrFunGroCo 直接判断。

  2. 执行语句中,含有 group_concat

  3. 使用内存高的 backtrace 中,含有 ObAggregateProcessor::group_extra_aggr_calc_batch

解决方法

OceanBase 数据库 V4.2 缓解,V4.3 彻底解决。

SqlCteRow 模块

问题描述

cte 场景, 可能存在内存占用高问题。

问题原因

数据量大、递归层次过高、无限递归场景,判环占用内存高。

问题诊断
  1. 通过 SqlCteRow 这个 mod 直接判断。

  2. recursive cte 无限递归根据 with 子句判断,是否带有终止条件(level < x 等),比如 with cte(n) as (select 1 union select n+1) select * from cte

解决方法

OceanBase 数据库 V3.2.3 版本之前存在但不是很明显,V3.2.3 及之后版本,开向量化时该场景内存使用会明显增加。

ConnectByPump 模块

问题描述

connect by 场景, 可能存在内存占用高问题。

问题原因

递归层次过高时保留 pump node 用于判环, 导致内存占用高。

问题诊断
  1. 通过 ConnectByPump 这个 mod 直接判断。

  2. 无限递归需要根据 connect by 条件判断,是否写法正确(确定 prior 是否遗漏),比如 connect by c1 = c2 时刚好某行数据的 c1 值与 c2 值相同。

解决方法

OceanBase 数据库所有活跃版本均存在该问题。

MysqlRequesReco 模块

问题描述

sql audit queue 内存小规格占用 80M 问题。

问题原因

因为当前 sql audit 内部使用的循环 buffer,默认使用的 1000w 个槽位, 不支持动态调整,固定占用 80+M。

问题诊断

这个 mod 名称 ·MysqlRequesReco·, 表示 sql audit 消耗内存, 可以先通过 SQL 语句 select svr_ip, svr_port, count(*) from gv$ob_sql_audit group by svr_ip, svr_port 查看 sql audit 中的执行记录信息。

  • 如果执行记录数很少,比如只有几百行,同时 sql audit 中内存占用有有超过 100M+,则 sql audit 内存占用可能不合理,属于未知 Bug 缺陷。

  • 如果 sql audit 中记录数很少,同时小于 100M,则是因为 sql audit queue 默认占用 80M 问题,属于已知问题。

  • 如果内存占用高,且 sql audit 记录数很多,则符合预期。

解决方法

OceanBase 数据库 V4.3 版本解决。

DtlIntermRes 模块

问题描述

执行分布式计划时内存占用高。

问题原因

停流量后,内存占用仍然很大:中间结果泄漏;停流量后,内存占用降到很低(执行一些分布式 inner sql ):流量大导致写入大量中间结果。

解决方法

OceanBase 数据库 V4.2 版本已修复,V4.3 版本解决,实施中间结果的自动内存管理。

ObSQLSessionInf 模块

问题描述

大量 session 建连场景,内存占用过高,长时间未释放。

问题原因

session_pool hold 住内存,当前设计不存在释放相应内存。

解决方法

在 OceanBase 数据库 V4.x 版本中添加开关,关闭 session pool。

WindowAggProc 模块

问题描述

WindowAggProc 内存膨胀 5G+;400k 的查询首次执行爆内存,再次执行成功。

问题原因

WM_CONCAT 内存使用过于粗放,数据全部缓存在 arena 中,引发内存膨胀。

解决方法

OceanBase 数据库 V4.3 版本解决。

适用版本

OceanBase 数据库所有版本。