案例:Troubleshooting library cache lock(SQL AREA BUILD)

本案例来自南区某客户,数据库版本为rac 19c。故障现象为2节点大约凌晨2点开始,堆积了大量等待library cache lock和library cache:mutex X的session。一直持续了几分钟自动恢复正常。

Snap Id Snap Time Sessions Cursors/Session Instances
Begin Snap: 4250 18-Oct-22 02:00:20 1101 12.5 2
End Snap: 4251 18-Oct-22 03:00:13 1106 12.0 2
Elapsed: 59.89 (mins)
DB Time: 14,394.56 (mins)

Top 10 Foreground Events by Total Wait Time

Event Waits Total Wait Time (sec) Avg Wait % DB time Wait Class
library cache lock 1,931,334 569.8K 295.05ms 66.0 Concurrency
library cache: mutex X 3,686,589 205.1K 55.63ms 23.7 Concurrency
DB CPU 36K 4.2

从awr的一些基本信息来看,确实lc lock和lc mutex x等待非常严重。通常关于mutex类的争用,可以去看看awr中Mutex Sleep Summary部分。

Mutex Sleep Summary

  • ordered by number of sleeps desc
Mutex Type Location Sleeps Wait Time (ms)
Library Cache kgllkal2 81 18,969,541 64,710,767
Library Cache kgllkdl1 85 5,079,086 26,691,704
Library Cache kglhdgn2 106 1,383,344 6,754,413
  • kgllkdl – kernel generic library cache management library cache lock delete
  • kgllkal – kernel generic library cache management library cache lock allocate
  • kglhdgn – kernel generic library cache management object handle get handle, if it doesn’t exist, create it

根据sleep的情况来看,mutex的争用主要来自kgllkal、kgllkdl、kglhdgn,分别对应lc lock的分配和释放。而kglhdgn对应的是library cache handle。

我们知道在父游标句柄中保存有SQL文本。搜索hash链表的目的,就是对比每个父游标句柄中的SQL文本,找到目标父游标句柄。找到之后,要再次以独占方式申请持有类型为“Library Cache”的Mutex,如果遇到竞争,此处的等待事件也是library cache: mutex X,为了加以区分,此处的Mutex Miss通常是“kglhdgn2 106”。
在此处的Mutex保护下,进程将进一步获得父游标句柄上的Library cache lock。Library cache lock获得成功,Mutex才会释放。这也是为什么library cache lock和library cache:mutex X会在top event同时出现的原因。

lc handle上的Mutex,代替的是以前版本的Library Cache Lock Latch。由于要依靠Library Cache Lock实现依赖链,Mutex并没有取代Library Cache Lock,只是把Library Cache Lock Latch替代了。

分析到这里,可以判断问题的根源是library cache lock。此前多篇lc lock的文章都提到过lc lock的分析主要是分析P3参数。通过awr中的ash信息可以查看。

Top Event P1/P2/P3 Values

  • Top Events by DB Time and the top P1/P2/P3 values for those events.
  • % Event is the percentage of DB Time due to the event
  • % Activity is the percentage of DB Time due to the event with the given P1,P2,P3 Values.
Event % Event P1, P2, P3 Values % Activity Parameter 1 Parameter 2 Parameter 3
library cache lock 69.38 “215109965320”,”208720642768″,”5373954″ 0.05 handle address lock address 100*mode+namespace
library cache: mutex X 25.23 “1370341983”,”4514010628096″,”5374033″ 1.54 idn value where

对P3进行换算之后可以查出对应的namespace和请求mode

lc lock等待是发生在SQL AREA BUILD的handle上的,并且请求模式是S,说明当时肯定有session持有X的lc lock或者有X的lc lock请求。

首先说说SQL AREA BUILD,该namespace的lc lock只会发生在硬解析时生成子游标中,Oracle 在11.2 版本引入了Cursor Build Lock 机制,这一机制使得在某个父游标下创建子游标的工作串行化。当获取Build Lock 时,需要持有对应SQL AREA BUILD的Library Cache Lock。

通过_kgl_debug跟踪发现,当产生子游标时,在SQL AREA BUILD上,kgllkal的lockMode为S,而kgllkdl的lockMode为X。其中name部分LXY.$BUILD$.8af744b82f4cff89中的8af744b82f4cff89为sql的full hash value。

那么可以判断如果发生了SQL AREA BUILD上的lc lock争用,那么当时肯定有新的子游标产生。剩下的问题就是分析为何会产生该子游标了。

可以看到故障前实例中存在的子游标是32,而子游标8正是故障时段产生的。故障是2点开始,而该子游标2点05分才被load成功。说明花了5分钟才生成该子游标。

从sql的执行情况来看,该sql本身就是并发非常高的sql。对于产生新子游标这种事情出问题的概率就非常高了。

通常会通过v$sql_shared_cursor去分析子游标不能共享的原因。子游标不能共享的原因会按发现有cursor不能共享的时间以xml的格式添加在reason字段中。

当时32号子游标为啥不能共享的原因可以看到是Bind mismatch。

通过DBMS_SQLTUNE包可以查看子游标的bind值。

childnumber:32

childnumber:8

可以看到绑定变量长度差距很大,明显32和128的varchar2是不能共享的。

后面又发现在故障前,shared pool中大量内存kglhd(handle)和sqla(heap 6)被释放,初步怀疑被flush了shared pool。

 

对于该故障我的建议就是对于高并发的sql,应用尽量使用绑定变量长度一致的绑定变量,避免此类问题发生。

over!!!

此条目发表在Oracle, Oracle troubleshooting分类目录,贴了, 标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注