observer 内存超限

【 使用环境 】生产环境
【 OB or 其他组件 】observer
【 使用版本 】4.2.0_CE
【问题描述】Observer 查询报错4013(HY001): No memory or reach tenant memory limit
【复现路径】问题出现前后相关操作
【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):

【SOP系列 22 】——故障诊断第一步(自助诊断和诊断信息收集)

【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手] 即可召唤小助手,欢迎试用!

6 个赞

根据您描述的问题,OceanBase 数据库在查询过程中遇到了错误代码 4013 (HY001): “No memory or reach tenant memory limit”,这表明可能是内存相关的问题。针对此情况,建议使用 obdiag 工具来收集日志信息,并尝试通过根因分析功能定位问题的根本原因。

根因分析场景: 内存问题

根因分析命令:

obdiag rca run --scene=observer.memory

这条命令将帮助诊断与内存限制或不足相关的具体问题,包括但不限于租户达到其内存限制的情况。

日志采集场景: 内存问题

日志采集命令:

obdiag gather scene run --scene=observer.memory

上述命令会收集与内存消耗及配置相关的日志文件,这对于进一步理解为何发生内存不足错误非常关键。

执行完以上命令后,请将生成的日志压缩包分享给我们以便深入分析。此外,为了更准确地定位问题,还需要您提供以下额外的信息:

  1. 发生该问题的具体时间点。
  2. 当前OceanBase集群中涉及的租户及其内存设置(例如,每个租户的最大内存限制)。
  3. 是否有同时运行的大规模操作(如大数据量导入、大量并发查询等)可能导致内存紧张?
  4. 在遇到此错误之前是否有增加过租户数量或者调整过租户的资源分配?

请您按照上述指导操作,并尽快反馈所需资料,这样我们可以更快地为您解决问题。感谢您的配合!

附上敏捷诊断工具 obdiag 使用帮助链接

先看下物理内存情况,再看OB里的system_memory_limit,再看租户内存情况

obclient -h127.0.0.1 -P2881 -uroot@sys -A -p 试一下sys租户能登录么?
若 sys 能登录,说明主要是 obmysql 租户内存问题;若 sys 也 4013,则更可能是 整机或 OB Server 级内存问题。

sys 租户也无法登录

请问是低版本的OB有内存泄露问题吗? 设备已经很长时间没有重启了

有,420版本很早了,有可能内存泄露,重启恢复后建议尽快升级下版本

学到了

666

快速

好,支持。

OceanBase -4013租户内存超限日志分析培训案例

从未知 SQL 起步 · 全链路日志 · 内存模板溯源

OceanBase Database 3.2.3 专版 · 修订版

文档版本 v1.1(相对 v1.0:纠正“上帝视角过滤”,补全链路日志)
发布日期 2026年07月31日
目标版本 OceanBase Database 3.2.3 / OBProxy
适用对象 值班 DBA / 中高级数据库运维工程师
案例环境 集群 obv3 · 节点 172.16.104.28(observer06)
值班已知信息 约 23:10 出现 ORA-00600/-4013(不知具体 SQL)
结论摘要 SQL_EXEC_CTX_ID(ctx_id=5)占满租户 4GB 上限
Proxy 日志 /home/admin/obproxy/log
Observer 日志 /home/admin/oceanbase/log
密级 内部资料

一、值班起始态势(你真正知道什么)

本案例按真实值班建模。假设业务/监控只给了如下信息,除此之外一无所知:

已知项 取值 未知项(待日志发现)
报错现象 ORA-00600 / -4013,提示 No memory or reach tenant memory limit 具体 SQL 文本
大致时间 2026-07-30 23:10 前后 用户名、租户名(若工单未写)
接入点 经 OBProxy 访问(端口 2883 一类) 落到哪台 Observer
环境 集群 obv3,节点可登录 172.16.104.28 内存模板 / ctx_id

因此分析原则是:先宽后窄——用时间/错误码捞出失败请求,再从日志字段里“读出”租户、用户、SQL、Trace、后端地址,最后用 Trace 到 Observer 定位内存模板。

二、日志目录与各文件作用

2.1 OBProxy(/home/admin/obproxy/log)

日志文件 作用 本案例优先级
obproxy_error.log 失败请求总账:时间、集群/租户/用户、SQL、错误码、错误信息、耗时、客户端、后端 Observer、Trace ID P0 首查
obproxy_digest.log 请求摘要(含失败),可交叉核对耗时与路由 P1 佐证
obproxy_slow.log 慢请求;大对象/长 PL 常出现 P1 佐证
obproxy.log 主运行日志(连接/会话/路由),体量大、常滚动 P2 深挖会话
obproxy_stat.log 统计类 P3
obproxy_diagnosis.log 诊断类 P3
obproxy_xflush.log 高频刷盘/监控,体积最大 一般不用于单 SQL 根因
obproxy_trace / pool / limit 细 Trace、连接池、限流(本环境常为空) 按需

2.2 Observer(/home/admin/oceanbase/log)

日志文件 作用 本案例优先级
observer.log / observer.log.YYYYMMDDHHMMSS 执行端全量日志;注意滚动归档 P0(按 Trace 查归档)
observer.log.wf WARN/ERROR/FATAL 过滤,体积更小 P0 快速扫 ERROR
rootservice.log(.wf) RS 元数据/均衡 本案例无关
election.log 选举 本案例无关
obesi-daemon.log 守护进程 本案例无关

【滚动提醒】

本案例故障在 23:10,当前 observer.log 可能已从更晚时间重开写。实际命中文件:observer.log.20260730231446(覆盖约 23:08~23:14)。

三、实战排查步骤(从未知 SQL 起步)

步骤 A:进 Proxy 错误日志——只用时间窗

是的,入口就是 obproxy_error.log。正确首查示例:

A1 首查命令(推荐)

cd /home/admin/obproxy/log

正确:只按时间窗(值班已知“大约 23:10”)

grep “2026-07-30 23:1” obproxy_error.log

若时间窗内噪声多,再用错误特征收窄(仍不知道 SQL 名)

grep “2026-07-30 23:1” obproxy_error.log | grep -E “4013|No memory|tenant memory|ORA-00600”

本案例时间窗内命中 1 条失败请求(字段已由 Proxy 写全):

【链路日志 ①】obproxy_error.log(发现 SQL/用户/Trace/后端)

2026-07-30 23:10:03.368589,obv3,obv3:oboracle:JAMES,OB_ORACLE,OB_MYSQL_COM_QUERY,OTHERS,failed,600,

BEGIN%0A test_clob(52428800);%0AEND;,15879817us,0us,0us,15878636us,

Y0-00007F0070CFF760,YB42AC10681C-000657B5B185F478-0-0,

172.16.104.22:15296,0,172.16.104.28:2881,

ORA-00600: internal error code, arguments: -4013, No memory or reach tenant memory limit,

YB42AC10681C-000657B5B185F478-0-0

步骤 B:从 error 行“读出”后续检索条件

到这一步,SQL 名、用户名才第一次进入你的知识集。把它们整理成工作表:

字段 从 error 日志读出的值 后续用途
时间 2026-07-30 23:10:03.368589 对齐 Observer 时间
集群/租户/用户 obv3 / oboracle / JAMES 确认业务归属
SQL BEGIN test_clob(52428800); END; 根因关联业务写法
错误 600 / ORA-00600 / -4013 与客户端一致
耗时 15879817 us ≈ 15.88 s 可对照 slow
客户端 172.16.104.22:15296 回溯来源
后端 Observer 172.16.104.28:2881 决定上哪台机器查 observer.log
Trace ID YB42AC10681C-000657B5B185F478-0-0 Observer 全链路主键

【关键认知】

test_clob、JAMES 不是“过滤条件的来源”,而是“error 日志的产物”。之后若再 grep test_clob,那是二次精确检索,不是首查。

步骤 C:同机 Proxy 侧交叉佐证(可选)

此时已有 Trace,可用 Trace 去 digest/slow 做交叉确认(仍不必猜 SQL):

A2 用 Trace 交叉(已从 error 获得)

TRACE=YB42AC10681C-000657B5B185F478

grep “$TRACE” obproxy_digest.log

grep “$TRACE” obproxy_slow.log

【链路日志 ②】obproxy_digest.log

2026-07-30 23:10:03.368578,obv3,obv3:oboracle:JAMES,OB_ORACLE,OB_MYSQL_COM_QUERY,OTHERS,failed,600,

BEGIN%0A test_clob(52428800);%0AEND;,15879817us,…,YB42AC10681C-000657B5B185F478-0-0,

…,172.16.104.28:2881

【链路日志 ③】obproxy_slow.log(长耗时失败,落入慢日志)

2026-07-30 23:10:03.368585,obv3,obv3:oboracle:JAMES,OB_ORACLE,OB_MYSQL_COM_QUERY,OTHERS,failed,600,

BEGIN%0A test_clob(52428800);%0AEND;,15879817us,…,YB42AC10681C-000657B5B185F478-0-0,

…,172.16.104.28:2881

步骤 D:切到后端 Observer,按 Trace 深挖

D1 Observer 首查

后端已从 error 得知:172.16.104.28:2881

ssh root@172.16.104.28

cd /home/admin/oceanbase/log

找覆盖 23:10 的滚动文件

ls -lrt observer.log.2026073023*

本案例命中:

observer.log.20260730231446

只用 Trace(不要猜 SQL)

grep “B185F478” observer.log.20260730231446 | grep -E “ERROR|WARN|alloc|4013|SQL_EXEC”

步骤 E:读出内存模板 SQL_EXEC_CTX_ID

同一 Trace 下,分配失败链如下(按时间顺序):

四、全链路关键日志清单(按时间)

以下为本案例从“内存触顶”到“返回客户端”的完整关键日志。培训时建议按序号逐条讲解。

4.1 触顶前兆(租户已接近 4GB)

④ 租户内存高压(故障前约 1 秒)

【链路日志 ④】observer.log.20260730231446

[2026-07-30 23:10:02.845840] INFO [COMMON] ob_tenant_mgr.cpp:1577

A minor freeze is needed(

mem_tenant_limit=4294967296, # 4GB

mem_tenant_hold=4206886912, # ≈3.92GB,已很高

tenant_id=1002)

4.2 分配失败主链(同一 Trace)

⑤~⑱ Observer 同 Trace 关键链

Trace = YB42AC10681C-000657B5B185F478-0-0

【⑤】23:10:03.333462 ERROR [COMMON] sync_wash_mbs (ob_kvcache_store.cpp:449)

can not find enough memory block to wash(ret=-4273, size_washed=0, size_need_washed=14680064)

→ 想从 KVCache 刷出约 14MB 失败

【⑥】23:10:03.337058 WARN [COMMON] sync_wash_mbs (ob_kv_storecache.cpp:793)

sync_wash_mbs failed(ret=-4273, tenant_id=1002, wash_size=14680064, wash_single_mb=false)

【⑦】23:10:03.337066 WARN [COMMON] alloc_chunk (ob_resource_mgr.cpp:121)

sync_wash_mbs failed(ret=-4273, tenant_id=1002, wash_size=14680064, wash_single_mb=false)

【⑧】23:10:03.337075 WARN alloc_block (ob_page_manager.h:199)

oops, alloc failed, tenant_id=1002 ctx_id=5 hold=3523215360 limit=9223372036854775807

【⑨】23:10:03.337082 WARN alloc (ob_allocator_v2.cpp:51)

[OOPS] alloc failed reason: tenant memory has reached the upper limit

(tenant_id: 1002, tenant_hold: 4290772992, tenant_limit: 4294967296, alloc_size: 10485760)

→ 根因定性:租户上限触顶(不是 ctx 单独限流)

【⑩】23:10:03.337095 WARN alloc (ob_allocator_v2.cpp:56)

oops, alloc failed, tenant_id=1002, ctx_id=5, ctx_name=SQL_EXEC_CTX_ID,

ctx_hold=3523215360, ctx_limit=9223372036854775807,

tenant_hold=4290772992, tenant_limit=4294967296

→ ★ 内存模板答案:SQL_EXEC_CTX_ID(ctx_id=5),hold≈3.28GB

【⑪】23:10:03.337109 WARN alloc_new_page (page_arena.h:334)

cannot allocate memory.sz=9731831, pages_=562, total_=2949748480

→ 本会话 page arena 已堆积约 2.75GB

【⑫】23:10:03.337118 ERROR [PL] calc_write_result (ob_dbms_lob.cpp:696)

alloc memory failed(ret=-4013, res_len=9731799)

→ PL/DBMS_LOB 层暴露 -4013

【⑬】23:10:03.337174 WARN [PL] write (ob_dbms_lob.cpp:784)

fail to calc(ret=-4013)

【⑭】23:10:03.337236 WARN [PL] writeappend (ob_dbms_lob.cpp:1080)

fail to calc dbms_lob.write procedure(ret=-4013, … payload_size:9699032 …)

→ 业务动作:DBMS_LOB.WRITEAPPEND;当时临时 LOB 逻辑大小仅约 9.3MB

【⑮】23:10:03.367758 WARN [PL] execute (ob_pl.cpp:2632)

Unhandled exception has occurred in PL(*ctx_.status_=-4013, ret=-4013)

【⑯】23:10:03.367973 WARN [SERVER] response_result (ob_sync_cmd_driver.cpp:118)

close result set fail(cret=-4013)

【⑰】23:10:03.368037 WARN [SERVER] response_result (ob_sync_cmd_driver.cpp:124)

result set open failed, check if need retry(ret=-4013, cli_ret=-4013, retry_ctrl_.need_retry()=0)

【⑱】23:10:03.368123 WARN [SERVER] do_process (obmp_query.cpp:735)

execute query fail(ret=-4013, …)

→ Observer 向 Proxy/客户端返回失败

4.3 回到 Proxy:错误返回客户端

Observer 在 23:10:03.368123 判定失败后,Proxy 在约 23:10:03.368589 写入 error/digest/slow(即链路日志 ①②③)。客户端看到 ORA-00600 / -4013。

4.4 链路总览图

因果方向(自下而上发生,自上而下呈现给 DBA)

客户端 ORA-00600/-4013

obproxy_error / digest / slow ←①②③ (发现 SQL、用户、Trace、后端)

Observer 返回失败 ←⑱

PL 未处理异常 / WRITEAPPEND ←⑫⑬⑭⑮

alloc 失败 + 打出 ctx_name ←⑧⑨⑩⑪ ★ SQL_EXEC_CTX_ID

sync_wash 失败 (-4273) ←⑤⑥⑦

租户内存已高压 ←④

业务:循环 DBMS_LOB.WRITEAPPEND 构造大临时 CLOB

五、根本原因与数字结论

【根本原因】

租户 oboracle(tenant_id=1002)在 172.16.104.28 的 Unit 内存上限为 4GB。PL 过程通过 DBMS_LOB.WRITEAPPEND 循环扩容临时 CLOB,内存记在 SQL_EXEC_CTX_ID(ctx_id=5)。执行期 Arena 等机制使旧缓冲延迟回收,SQL_EXEC_CTX 占用飙至约 3.28GB,租户 hold 逼近 4GB;再申请约 10MB 时 wash 失败,返回 -4013。

注意:失败时 LOB 逻辑大小仅约 9.3MB,远小于 4GB——是执行期内存放大,不是“50MB 对象本身超限”。

项目
内存模板 SQL_EXEC_CTX_ID(ctx_id=5)
tenant_limit 4294967296(4GB)
tenant_hold(失败瞬间) 4290772992(≈3.996GB)
SQL_EXEC_CTX hold 3523215360(≈3.28GB)
本次申请 alloc_size=10485760;res_len≈9731799
Unit 配置名 config_oboracle_zone1_u2c4g_knb
Trace ID YB42AC10681C-000657B5B185F478-0-0

六、处置建议(简)

• 紧急:确认会话结束/必要时杀会话,观察租户内存回落。

• 规避:禁止单会话内用 WRITEAPPEND 堆超大临时 LOB;改为分批/流式写入。

• 容量:短期可扩 unit memory,但必须同步改写法,否则只是推迟触顶。

七、培训考核(强调方法论)

考题 合格标准
首查该用哪类过滤条件? 时间窗和/或 4013/No memory;不能一上来用 SQL 名/用户名
test_clob、JAMES 从哪来? 从 obproxy_error.log 字段读出,不是先验知识
如何定位到哪台机器? error 日志中的后端地址 172.16.104.28:2881
Observer 用什么做主键? Trace ID(B185F478…)
哪个内存模板? SQL_EXEC_CTX_ID / ctx_id=5
触顶的是什么? tenant_limit(4GB),不是 ctx_limit
举出至少 5 条链路关键日志 能覆盖 wash→alloc→ctx_name→dbms_lob→proxy error

【考官标准答案卡】

入口文件:obproxy_error.log

首查:grep 时间窗(可选再 grep 4013/No memory)→ 读 Trace/后端/SQL/用户

深挖:observer.log.20260730231446 + Trace

模板:SQL_EXEC_CTX_ID(ctx_id=5)

根因:租户 4GB 上限触顶 + WRITEAPPEND 导致 SQL_EXEC_CTX 暴涨

666

go go!!!

这篇文章写得真不错,很有启发性。