Oracle 11g 的这个 Bug,有点意思
前言
今天在一套 Oracle 11g RAC 数据库上查询表空间使用率,结果 SQL 执行时报了一个比较熟悉的错误:
ORA-01000: maximum open cursors exceeded
看到 ORA-01000,第一反应一般都是游标没有正常释放,或者数据库的 OPEN_CURSORS 参数设置得太小。
不过这次有点奇怪,只是查个表空间使用率,也没执行什么复杂 SQL,怎么就把游标用完了?
进一步测试发现,同一个 SQL 第一次执行正常,第二次执行就可能报错。
最后查下来,问题并不是应用程序没有关闭游标,而是 Oracle 11.2.0.4 的一个已知 Bug。
本文记录一下整个排查和处理过程。
查个表空间使用率,为什么会报 ORA-01000?
数据库版本为 Oracle 11.2.0.4,双节点 RAC,底层存储使用 ASM。
执行:
SELECT *
FROM DBA_TABLESPACE_USAGE_METRICS;
报错:
ORA-01000: maximum open cursors exceeded
DBA_TABLESPACE_USAGE_METRICS 是 Oracle 提供的表空间使用率视图,平时巡检、监控经常会用到。
这个视图本身并不复杂,但它在计算表空间容量时,需要访问一些数据库内部信息,包括 ASM 磁盘组的剩余空间。
既然报了 ORA-01000,先看看游标参数:
SHOW PARAMETER open_cursors;
SHOW PARAMETER session_cached_cursors;
NAME VALUE
---------------------------- -----
open_cursors 800
session_cached_cursors 50
OPEN_CURSORS 设置为 800,并不算特别小。
当然,参数大不代表不会报错。如果某个会话不断打开游标而不释放,800 同样可能耗尽。
不过,这次的问题出现在一个普通的系统视图查询上,还是需要继续往下查。
为什么第一次查询正常,第二次就报错?
为了缩小范围,继续检查 DBA_TABLESPACE_USAGE_METRICS 底层涉及的固定表。
其中一个比较关键的是:
SELECT COUNT(*)
FROM X$KTTETS;
测试时发现一个很有意思的现象。
第一次执行:
COUNT(*)
----------
33
再次执行相同 SQL,就可能出现:
ORA-01000: maximum open cursors exceeded
换一个会话重新连接,又可以执行一次,随后再次报错。
而且两个 RAC 节点都能复现,这就有点不正常了。
如果是业务程序没有关闭游标,通常需要结合具体应用会话、执行频率和游标数量分析。但现在使用 SYSDBA 连接数据库,连续执行一个固定表查询就能触发错误,问题显然不能简单归结为应用程序。
于是继续检查 ASM 相关视图:
SELECT NAME,
TOTAL_MB,
FREE_MB
FROM V$ASM_DISKGROUP_STAT;
多次执行均正常。
说明 ASM 磁盘组本身可以正常查询,并不是磁盘组无法访问。
问题更可能出在 X$KTTETS 查询过程中调用 ASM 空间信息的内部处理逻辑。
ORA-01000 到底是哪个 SQL 引起的?
前面已经确认,X$KTTETS 连续执行就能复现 ORA-01000,但具体是哪个环节出了问题,还得看 Trace。
这里使用 Oracle 的 Errorstack,在报错时抓取当前会话的诊断信息。
由于问题可以稳定复现,直接在测试会话中开启即可:
ALTER SESSION SET EVENTS
'1000 trace name errorstack level 3';
然后执行之前报错的 SQL:
SELECT COUNT(*) FROM X$KTTETS;
/
/
等 ORA-01000 再次出现后,关闭事件:
ALTER SESSION SET EVENTS
'1000 trace name errorstack off';
接下来找到当前会话生成的 Trace 文件:
SELECT VALUE
FROM V$DIAG_INFO
WHERE NAME = 'Default Trace File';
返回的就是当前会话对应的 Trace 文件路径。
进入服务器查看 Trace,重点搜索 ORA-01000、Current SQL Statement 和 Call Stack Trace 等信息。
这次最终找到了报错时正在执行的内部递归 SQL:
SELECT free_mb
FROM v$asm_diskgroup_stat
WHERE name = :1;
对应 SQL_ID:
6hnhqahphpk8n
绑定变量指向 ASM 数据磁盘组。
更关键的是 Trace 中的调用栈,出现了这些函数:
kttets_cb
ktte_tstat_refresh1
ktte_get_maxsize1
ktte_get_asm_diskgroup_free_space
OCIStmtExecute
从函数名称和调用关系来看,Oracle 在计算表空间容量时,会进一步获取 ASM 磁盘组剩余空间。
而 ORA-01000 就发生在这个内部调用过程中。
这里还有一个比较关键的细节:
Trace 中记录的当前打开游标数量并没有达到 800,但内部递归 SQL 已经触发 ORA-01000。
结合前面的复现现象,基本可以把排查方向转向 Oracle 内部缺陷。
查 MOS,果然是 Oracle 11.2.0.4 的 Bug
接下来去 MOS 搜索相关错误、视图名称以及 Trace 中的函数。
找到了几篇高度相关的文档,其中一篇是:
KB147132:ORA-01000 Max Open Cursors Exceeded After Upgrade To 11.2.0.4
文档描述的故障特征与现场基本一致:
- Oracle 11.2.0.4 环境;
- 查询
DBA_TABLESPACE_USAGE_METRICS出现 ORA-01000; - 涉及
X$KTTETS; - 内部递归 SQL 查询
V$ASM_DISKGROUP_STAT; - 调用栈包含
kttets_cb等函数。
另一篇文档是:KI14848:Bug 17897511
这个 Bug 同样涉及 Oracle 11.2.0.4 中查询 DBA_TABLESPACE_USAGE_METRICS 引发的 ORA-01000。
继续查看补丁关系,发现 Bug 17897511 对应的早期补丁已经被 Patch 18235390 取代。
其中还涉及一个比较特殊的问题:
早期补丁可能引入
ORA-600 [KGHSTACK_UNDERFLOW_INTERNAL_3],而 Patch 18235390 正是针对这个问题的后续修复。
MOS KB147132 还提到了 Patch 18964923。
因此,不能只看 Bug 编号就直接安装补丁,还需要结合 Oracle 版本、平台、README 和补丁之间的关系确认。
这次最终选择先安装:
Patch 18235390
并在安装完成后,通过原来的故障 SQL 验证效果。
补丁很小,但还是需要重启实例
当前数据库环境:
| 项目 | 环境 |
|---|---|
| 数据库版本 | Oracle 11.2.0.4 |
| 架构 | 双节点 RAC |
| 操作系统 | Linux x86-64 |
| 存储 | ASM |
| 原 OPatch 版本 | 11.2.0.3.4 |
| 升级后 OPatch | 11.2.0.3.58 |
| 安装补丁 | 18235390 |
Patch 18235390 的压缩包只有一百多 KB。
解压后可以看到补丁包含:
files/lib/libserver11.a/ktt.o
虽然补丁很小,但涉及 Oracle 数据库内部目标文件,并不是执行一条 SQL 就能生效。
README 明确说明:
This patch is RAC Rolling Installable
也就是支持 RAC 滚动安装,需要注意:
RAC Rolling Installable 不等于 Online Installable。
滚动安装意味着可以逐节点停止实例、安装补丁、重新启动,而不是两个 RAC 节点必须同时停机;但单个节点仍然需要停止对应实例,安装完成后重新启动,才能使用更新后的数据库程序。
对于生产环境,这一点很重要。
如果应用没有正确配置连接故障转移,停止单节点实例仍然可能影响部分业务连接。
先升级 OPatch,再检查补丁冲突
现场原来的 OPatch 版本比较老:
OPatch Version: 11.2.0.3.4
根据补丁 README 的要求,先下载 Patch 6880880,将 OPatch 升级至 11.2.0.3.58。
升级前备份旧的 OPatch 目录,再将新版本解压到 Oracle Home。
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_2
cd $ORACLE_HOME
mv OPatch OPatch_bak
unzip /path/to/p6880880_112000_Linux-x86-64.zip \
-d $ORACLE_HOME
检查版本:
$ORACLE_HOME/OPatch/opatch version
OPatch Version: 11.2.0.3.58
OPatch succeeded.
接下来检查 Inventory:
$ORACLE_HOME/OPatch/opatch lsinventory
确认 Oracle Home 正常,没有 Inventory 异常。
然后进入补丁目录:
cd /home/oracle/patches/18235390
执行冲突检查:
$ORACLE_HOME/OPatch/opatch prereq \
CheckConflictAgainstOHWithDetail -ph ./
Prereq "checkConflictAgainstOHWithDetail" passed.
OPatch succeeded.
再检查磁盘空间:
$ORACLE_HOME/OPatch/opatch prereq \
CheckSystemSpace -ph ./
Prereq "checkSystemSpace" passed.
OPatch succeeded.
两个 RAC 节点分别完成以上检查,结果均正常。
RAC 滚动安装,整个过程比较顺利
确认补丁支持滚动安装、完成 Oracle Home 备份并安排维护窗口后,开始处理第一个节点。
先停止节点 1 的实例:
srvctl stop instance -d orcl -i orcl1 -o immediate
检查 RAC 状态:
srvctl status database -d orcl
此时预期节点 1 已停止,节点 2 仍在运行。
确认目标 Oracle Home 没有其他需要停止的数据库服务后,执行补丁安装:
cd /home/oracle/patches/18235390
$ORACLE_HOME/OPatch/opatch apply
安装过程比较顺利:
Verifying environment and performing prerequisite checks...
All checks passed.
Backing up files...
Applying interim patch '18235390' ...
Patching component oracle.rdbms, 11.2.0.4.0...
Patch 18235390 successfully applied.
OPatch succeeded.
安装完成后检查 Inventory:
$ORACLE_HOME/OPatch/opatch lsinventory
确认:
Interim patches (1) :
Patch 18235390
Bugs fixed:
18235390
OPatch succeeded.
随后启动节点 1:
srvctl start instance -d orcl -i orcl1
确认节点 1 恢复正常,再按照相同步骤处理节点 2。
整个过程采用滚动安装,始终保留一个 RAC 实例运行。
节点 2 安装完成后,检查:
srvctl status database -d orcl
结果:
Instance orcl1 is running on node node1
Instance orcl2 is running on node node2
两个节点的 Inventory 也都能查到 Patch 18235390。
至此,补丁安装完成。
不过,补丁安装成功不代表问题一定解决,最后还得用原来的 SQL 验证。
再查一次表空间使用率,这回正常了
补丁安装完成,两个 RAC 实例也都重新启动了。
接下来重新执行最开始出问题的 SQL。
SELECT COUNT(*)
FROM X$KTTETS;
/
/
/
/
COUNT(*)
----------
34
COUNT(*)
----------
34
COUNT(*)
----------
34
COUNT(*)
----------
34
COUNT(*)
----------
34
连续执行,没有再出现 ORA-01000。
再测试:
SELECT COUNT(*)
FROM DBA_TABLESPACE_USAGE_METRICS;
/
/
/
/
结果同样正常,每次都返回 34 行。
为了进一步验证,还通过 PL/SQL 循环执行了 20 次查询。
SET SERVEROUTPUT ON
DECLARE
v_count NUMBER;
BEGIN
FOR i IN 1..20 LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM X$KTTETS'
INTO v_count;
DBMS_OUTPUT.PUT_LINE(
'Test ' || i || ' : PASS, Rows=' || v_count
);
END LOOP;
END;
/
20 次全部通过,DBA_TABLESPACE_USAGE_METRICS 也进行了相同测试,没有发现异常。
最后分别在两个 RAC 节点上重复执行原来的 SQL,均没有再复现 ORA-01000。
最后总结
这次问题处理起来倒不算复杂,真正花时间的还是前面的定位。
一开始看到 ORA-01000,还以为是游标没有正常释放,检查了参数和相关会话之后,发现并不是这么回事。尤其是 X$KTTETS 第一次查询正常、第二次就报错,这个现象还是比较特别的。
后来通过 Errorstack 找到了 Oracle 内部查询 ASM 空间的递归 SQL,再结合 MOS 文档,才确认是 11.2.0.4 的已知 Bug。
后面的处理就比较简单了,升级 OPatch,两个 RAC 节点分别安装 Patch 18235390,重启实例后重新测试,原来的 SQL 连续执行都正常。
其实 Oracle 11g 现在还有不少生产环境在用,类似这种老版本的 Bug,平时不一定遇得到,碰上了还真容易走弯路。
这次也算积累了一个案例。以后再遇到系统视图查询报 ORA-01000,除了检查游标使用情况,也得考虑一下数据库自身的问题。
- 点赞
- 收藏
- 关注作者
评论(0)