技术培训 | RAC 宕机罪犯案情探析之子游标



  • 主题:RAC 宕机罪犯案情探析之子游标

    时间:6 月 7 日 20:00 —— 21:30

    地点:QingCloud 技术分享群,文末有二维码。

    讲师:

    图片 1.png
    李轶楠(ORA - 600),Oracle ACE,高级培训专家,ITPUB Oracle 版主。

    从事 Oracle 培训及技术服务行业15年,多年的积累,对 Oracle 数据库的设计规划、日常管理、代码优化、故障处理、客户培训等各项工作具有非常丰富的经验。

    十年以上培训经验,培训客户行业涉及金融、电信、税务、公安、电力路等各个行业,为上千的企业客户提供了高质量的技术培训,为企业的信息化建设培养了大量相关人才,培训学员人数上万。同时为客户提供专业 Oracle 技术服务,为客户设计部署稳定的系统架构,解决各种数据库疑难故障,优化数据库应用系统性能,保证了客户数据库的正常运行。

    本期内容介绍:

    核心系统的节点宕机,居然是 SQL子游标过多导致,子游标与实例宕机会有什么关系?笔者又是怎样发现他们之间关系的?且看专家如何抽丝剥茧,层层深入发现线索,并逐步还原犯罪场景,找出真实原因。

    提问福利:

    微信评论提出问题并被采纳的同学将有机会获得青云QingCloud 代金券,数量有限,赶快来提问吧~

    往期技术分享:

    报名方式:

    报名请扫描小编二维码,发送暗号: 听课 ,小编将会拉你进群:



  • 大家好,我是云和恩墨的李轶楠,不过网上的朋友更习惯叫我600,所以我也慢慢熟悉了这个称呼,其实这个称呼来自于ITPUB论坛上当时我注册的论坛ID“ORA-600”,因为这个ID跟Oracle的著名错误号一样,很容易给大家留下深刻印象,所以被我借用了过来,呵呵。这些年通过论坛上认识了很多朋友,也结识了现在与我一起奋战的恩墨小伙伴们。
    闲话不多说,我们来看看我们今天要分享的主题吧,这些年我们积累了大量的客户群体,也意味着我们面对着各种复杂的环境与事件,后续我会把我们小伙伴们所遭遇到的各种或者经典、或者灵异、或者有趣的case,逐一做成案件分析来分享给大家,希望大家喜欢。今天就以去年我们所遇到的一次RAC节点宕机的故障作为开场吧。

    1. 案情描述

    2015年6月的一个傍晚,大雨滂沱,正坐在家里发呆中,突然被一阵铃声惊醒。拿起电话,发现是客户来电,于是赶紧接听:
    ”我们的核心系统在晚上9点多突然有一个节点挂了,实例自动重启。虽然没有影响业务,但这种无缘无故的重启发生在核心系统上,直接威胁我们的业务运行,领导很重视,所以今天必须把原因找到,多晚都要给出结果,拜托了!“

    2. 案情分析

    听到客户的描述,心里第一个反应是:还好,只是单节点重启,问题本身应该不严重,至少对业务影响并不大,看来这大雨天是不用淋雨去客户现场了。。。呵呵,小心思而已。
    客户目前急需的是快速给出问题的原因,以便根据情况作出后续的规避措施,所以需要尽快拿到现场的一些数据来做分析,毕竟分析所需要的信息数据距离故障时间越近,精准度就越高,越有利分析

    经过进一步的沟通,得到了一些案发时的基本信息:

    1. 重启的是整个数据库架构的2节点,这个库是核心系统,晚上也有业务;
    2. 重启实例的情况其实以前也发生过,只不过发生的不多;(潜台词是也许这不是个案,以前的重启意味着可能这个问题一直存在)
    3. 当前数据库版本为11.2.0.1。(看到每个大版本的第一个小版本,总是觉得这种系统会BUG缠身。。。虽然夸大了点,但我们确实遇到了不少这种小版本的BUG)

    当然,很明显只听客户描述是不够的。于是,我远程登录了客户的服务器,开始做进一步检查。
    在开始分析之前,先跟大家及一下故障分析的常规思路,也便于初学者在遇到问题的时候知道从何处入手。

    • 在遇到故障时,首先要辨识一下当前的场景主要是性能问题的还是真的故障;
    • 如果是性能问题,那就需要收集当时的系统性能信息与数据库性能信息,awr、ash,或者系统的nmon、top之类都可以;
    • 如果是故障,那就要检查数据库的告警日志与跟踪文件了,非常典型的就是alertSID.log,这里面往往给了我们进一步追踪痕迹的指引。除此之外,各个进程的trace文件,asm的trace文件以及RAC的各种log、trace文件都会给出一些故障的原因或者印记,具体的这些文件所在目录大家都应该熟悉,最典型的就是通过background_dump_dest、user_dump_dest参数去查找(注意,rac的log和trace文件与数据库的目录并不在一起,可以检查$GRID_HOME/log/<hostname>的各个子目录),更详细的在这里就不再展开了。
    • 另外,当遭遇这些问题的时候,如果有MOS账号的话,建议首先去MOS中查看是否有故障相关的BUG或者技术文章,这既是快速诊断问题、解决问题的途径,也是DBA快速成长的重要手段。关于MOS的使用,大家可以加公众号“oracle”,在其中可以看到5月5日发的一篇“Oracle初学者入门指南-什么是Metalink或MOS?”

    好吧,回到我们的案例中:

    1、下面是节点2的alert log部分内容:

    Fri Jun 26 20:24:52 2015
     Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_p001_13581.trc  (incident=204565):
     ORA-00600: 内部错误代码, 参数: [kksfbc-wrong-kkscsflgs], [39913467504], [33], [], [], [], [], [], [], [], [], []
     Incident details in: /u01/app/oracle/diag/rdbms/orcl/orcl2/incident/incdir_204565/orcl2_p001_13581_i204565.trc
     Fri Jun 26 20:25:06 2015
     Trace dumping is performing id=[cdmp_20150626202506]
     Fri Jun 26 20:25:06 2015
     Sweep [inc][204565]: completed
     Sweep [inc2][204565]: completed
     Fri Jun 26 20:25:18 2015
     Trace dumping is performing id=[cdmp_20150626202517]
     。。。。。
     Fri Jun 26 21:21:08 2015
     Archived Log entry 164580 added for thread 2 sequence 48360 ID 0xa822d65a dest 1:
     Fri Jun 26 21:41:09 2015
     Thread 2 advanced to log sequence 48362 (LGWR switch)
       Current log# 2 seq# 48362 mem# 0: +DATA/orcl/onlinelog/redo21.log
       Current log# 2 seq# 48362 mem# 1: +DATA/orcl/onlinelog/redo22.log
     Fri Jun 26 21:41:09 2015
     Archived Log entry 164584 added for thread 2 sequence 48361 ID 0xa822d65a dest 1:
     Fri Jun 26 21:50:26 2015
     LCK0 (ospid: 29987) waits for latch 'object queue header operation' for 77 secs.
     Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_lmhb_29939.trc  (incident=204141):
     ORA-29771: process MMON (OSID 29967) blocks LCK0 (OSID 29987) for more than 70 seconds
     Incident details in: /u01/app/oracle/diag/rdbms/orcl/orcl2/incident/incdir_204141/orcl2_lmhb_29939_i204141.trc
     MMON (ospid: 29967) is blocking LCK0 (ospid: 29987) in a wait
     LMHB (ospid: 29939) kills MMON (ospid: 29967).
     Please check LMHB trace file for more detail.
     Fri Jun 26 21:51:06 2015
     Restarting dead background process MMON
     Fri Jun 26 21:51:06 2015
     MMON started with pid=213, OS id=16612
     Fri Jun 26 21:51:09 2015
     Sweep [inc][204141]: completed
     Sweep [inc2][204141]: completed
     Fri Jun 26 21:54:10 2015
     LMS1 (ospid: 29929) waits for latch 'object queue header operation' for 81 secs.
     LCK0 (ospid: 29987) has not called a wait for 85 secs.
     Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_lmhb_29939.trc  (incident=204142):
     ORA-29770: global enqueue process LMS1 (OSID 29929) is hung for more than 70 seconds
      Incident details in: /u01/app/oracle/diag/rdbms/orcl/orcl2/incident/incdir_204142/orcl2_lmhb_29939_i204142.trc
     Fri Jun 26 21:54:20 2015
     Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_lmhb_29939.trc  (incident=204143):
     ORA-29770: global enqueue process LCK0 (OSID 29987) is hung for more than 70 seconds
     Incident details in: /u01/app/oracle/diag/rdbms/orcl/orcl2/incident/incdir_204143/orcl2_lmhb_29939_i204143.trc
     ERROR: Some process(s) is not making progress.
     LMHB (ospid: 29939) is terminating the instance.
     Please check LMHB trace file for more details.
     Please also check the CPU load, I/O load and other system properties for anomalous behavior
     ERROR: Some process(s) is not making progress.
     LMHB (ospid: 29939): terminating the instance due to error 29770
     Fri Jun 26 21:54:21 2015
     opiodr aborting process unknown ospid (26414) as a result of ORA-1092
     Fri Jun 26 21:54:21 2015
     ORA-1092 : opitsk aborting process
     Fri Jun 26 21:54:21 2015
     System state dump is made for local instance
     System State dumped to trace file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_diag_29889.trc
     Instance terminated by LMHB, pid = 29939
     Sat Jun 27 12:52:23 2015
     Starting ORACLE instance (normal)
     LICENSE_MAX_SESSION = 0
     LICENSE_SESSIONS_WARNING = 0
     Interface type 1 eth1 172.16.0.0 configured from GPnP Profile for use as a cluster interconnect
     Interface type 1 eth0 192.168.0.128 configured from GPnP Profile for use as a public interface
     Picked latch-free SCN scheme 3
     Autotune of undo retention is turned on.
     LICENSE_MAX_USERS = 0
     SYS auditing is disabled
    

    在告警日志中我们发现一个很明显的ORA-600错误,同时也发现一些其他的ORA报错,见上面标红部分。于是我们对这些错误分别进行了分析,发现:

    1)ORA-600 [kksfbc-wrong-kkscsflgs] (Doc ID 970885.1) 确实是一个bug,在MOS上有说明:

    NB Bug Fixed Description
    9067282 11.2.0.1.2, 11.2.0.1.BP01, 11.2.0.3, 12.1.0.1 ORA-600 [kksfbc-wrong-kkscsflgs] can occur
    9066130 10.2.0.5, 11.1.0.7.2, 11.2.0.2, 12.1.0.1 OERI [kksfbc-wrong-kkscsflgs] / spin with multiple children
    8828328 11.2.0.1.1, 11.2.0.1.BP04, 11.2.0.2, 12.1.0.1 OERI [kksfbc-wrong-kkscsflgs]
    8661168 11.2.0.1.1, 11.2.0.1.BP01, 11.2.0.2, 12.1.0.1 OERI[kksfbc-wrong-kkscsflgs] can occur

    但MOS上并未说明该BUG会导致实例宕机,这个600错误看来应该与此次重启关系不大,好吧,作为一个问题记下来就是了。

    2) 在故障时间点,LMHB 进程check发现mmon进程阻塞了LCK0进程,超过70s,因此尝试kill MMON进程,该进程被kill之后将会自动重启。
    可以看到在Jun 26 21:51:06 时间点,MMON进程重启完成。

    这里在插播一件事,正好就在前几天,我们的客户也遇到了MMON进程的相关问题,在这也顺便分享给大家:客户的MMON进程被Kill之后并未自动启动,导致AWR等性能信息无法自动收集,因此客户希望能够在不启动数据库的情况下启动MMON,再想了各种办法之后,最终找到了方法:

    Restart the database instance
    

    或者

    Set the instance to "restricted session" mode and then bring it back to normal mode using following commands as SYSDBA:
    alter system enable restricted session;
    alter system disable restricted session;
    

    大家也可以搜寻一下MOS上的文章,看到相关的信息:文档 ID 2023652.1

    接下来,在Jun 26 21:54:10,LMS1进程报错无法获得latch(object queue header operation) 超过85秒。

    注: LMHB是11gR2中引入的后台进程,官方文档介绍是Global Cache/Enqueue Service Heartbeat Monitor,Monitor the heartbeat of LMON, LMD, and LMSn processes,LMHB monitors LMON, LMD, and LMSn processes to ensure they are running normally without blocking or spinning。 该进程负责监控LMON、LMD、LMSn等RAC关键的后台进程,保证这些background process不被阻塞或spin。 LMHB是Lock Manager Heartbeat的缩写。

    2、为了更清楚的理清线索,我们根据节点2的alert log信息,整理出如下的时间线点:

    Jun 26 20:24:52   ORA-00600  [kksfbc-wrong-kkscsflgs]
    Jun 26 21:50:26   LCK0 (ospid: 29987) waits for latch 'object queue header operation' for 77 secs
                      MMON (OSID 29967) blocks LCK0 (OSID 29987) for more than 70 seconds
                      MMON (ospid: 29967) is blocking LCK0 (ospid: 29987) in a wait
                      LMHB (ospid: 29939) kills MMON (ospid: 29967)
                      
    Jun 26 21:51:06   MMON started with pid=213, OS id=16612   
    
    Jun 26 21:54:10   LMS1 (ospid: 29929) waits for latch 'object queue header operation' for 81 secs
                      LCK0 (ospid: 29987) has not called a wait for 85 secs
                      ORA-29770: global enqueue process LMS1 (OSID 29929) is hung for more than 70 seconds
                      
    Jun 26 21:54:20   ORA-29770: global enqueue process LCK0 (OSID 29987) is hung for more than 70 seconds
                      ERROR: Some process(s) is not making progress.
                      LMHB (ospid: 29939) is terminating the instance 
                      LMHB (ospid: 29939): terminating the instance due to error 29770  
    

    从最后的信息可以看出,在21:54:20时间点,LMHB进程强行终止了数据库实例. 而终止实例的原因是LMHB进程发现LCK0进行hung住了,而且超过了70s。在从前面的信息也可以看出,实际上在21:54:10时间点,LCK0进程就已经没有活动了了,而且在该时间点LMS1进程也一直在等待latch。很明显,如果LMS1进程无法正常工作,Oracle为了保证集群数据的一致性,为了避免脑裂,必然将问题节点强行驱逐重启。
    那么LMS1在等什么呢?LCK0为什么被Hung住了?

    3、lms1进程的情况

    让我们来看看LMS1到底在干什么?
    检查orcl2_lmhb_29939_i204142.trc,而该trace 文件产生的时间点是:Jun 26 21:54:10:

    SO: 0x9a1175160, type: 2, owner: (nil), flag: INIT/-/-/0x00 if: 0x3 c: 0x3
     proc=0x9a1175160, name=process, file=ksu.h LINE:11459, pg=0
    (process) Oracle pid:14, ser:1, calls cur/top: 0x9b17e5330/0x9b17e0e60
              flags : (0x6) SYSTEM
              flags2: (0x100),  flags3: (0x0) 
              intr error: 0, call error: 0, sess error: 0, txn error 0
              intr queue: empty
    ksudlp FALSE at location: 0
      (post info) last post received: 0 0 116
                  last post received-location: kjc.h LINE:1810 ID:KJCS Post snd proxy to flush msg
                  last process to post me: 991126330 1 6
                  last post sent: 41134582880 162 1
                  last post sent-location: ksl2.h LINE:2160 ID:kslges
                  last process posted by me: 9811032c8 1 14
      (latch info) wait_event=0 bits=a
            Location from where call was made: kcbo.h LINE:890 ID:kcbo_unlink_q_bg: 
        waiting for 993cfec60 Child object queue header operation level=5 child#=117 
            Location from where latch is held: kcl2.h LINE:3966 ID:kclbufs: 
            Context saved from call: 0
            state=busy(shared) [value=0x4000000000000001] wlstate=free [value=0]
            waiters [orapid (seconds since: put on list, posted, alive check)]:
             14 (95, 1435326858, 4)
             21 (94, 1435326858, 7)
             waiter count=2
            gotten 73961423 times wait, failed first 4752 sleeps 1927
            gotten 33986 times nowait, failed: 4
            possible holder pid = 36 ospid=29987
        on wait list for 993cfec60
        holding    (efd=5) 9b59be480 Child gc element level=3 child#=20 
            Location from where latch is held: kcl2.h LINE:3535 ID:kclbla: 
            Context saved from call: 0
            state=busy(exclusive) [value=0x200000000000000e, holder orapid=14] wlstate=free [value=0]
        holding    (efd=5) 9b45cac50 Child cache buffers chains level=1 child#=61221 
            Location from where latch is held: kcl2.h LINE:3140 ID:kclbla: 
            Context saved from call: 0
            state=busy(exclusive) [value=0x200000000000000e, holder orapid=14] wlstate=free [value=0]
      Process Group: DEFAULT, pseudo proc: 0x9b11ca008
      O/S info: user: oracle, term: UNKNOWN, ospid: 29929 
      OSD pid info: Unix process pid: 29929, image: oracle@ebtadbsvr2 (LMS1)
    

    从LMS1进程的信息来看,LMS1 进程所等待的资源(object queue header operation)正被ospid=29987 持有,那么29987又是什么呢?

    4、进一步分析下ospid=29987 是什么?

    让我们接着往下看:

     SO: 0x9911283b0, type: 2, owner: (nil), flag: INIT/-/-/0x00 if: 0x3 c: 0x3
     proc=0x9911283b0, name=process, file=ksu.h LINE:11459, pg=0
    (process) Oracle pid:36, ser:2, calls cur/top: 0x9b17e58e0/0x9b17e58e0
              flags : (0x6) SYSTEM
              flags2: (0x0),  flags3: (0x0) 
              intr error: 0, call error: 0, sess error: 0, txn error 0
              intr queue: empty
    ksudlp FALSE at location: 0
      (post info) last post received: 0 0 35
                  last post received-location: ksr2.h LINE:603 ID:ksrpublish
                  last process to post me: 981110608 118 0
                  last post sent: 0 0 36
                  last post sent-location: ksr2.h LINE:607 ID:ksrmdone
                  last process posted by me: 9911283b0 2 6
      (latch info) wait_event=0 bits=20
        holding    (efd=3) 993cfec60 Child object queue header operation level=5 child#=117 
            Location from where latch is held: kcl2.h LINE:3966 ID:kclbufs: 
            Context saved from call: 0
            state=busy(shared) [value=0x4000000000000001] wlstate=free [value=0]
            waiters [orapid (seconds since: put on list, posted, alive check)]:
             14 (95, 1435326858, 4)
             21 (94, 1435326858, 7)
             waiter count=2
      Process Group: DEFAULT, pseudo proc: 0x9b11ca008
      O/S info: user: oracle, term: UNKNOWN, ospid: 29987 
      OSD pid info: Unix process pid: 29987, image: oracle@ebtadbsvr2 (LCK0)
    

    最后一句很明显的告诉我们,29987原来就是LCK0进程。这意味着lms1 进程所等待的资源正被LCK0 进程所持有。而同时还有另外一个进程orapid=21 也在等待该进程。通过分析我们分析发现:
    orapid=21,是dbw2进程,即数据库写进程。

    注:这里解释一下,orapid是oracle中的进程id,而pid则是os上的进程id。所以orapid=21从v$process中可以查到是dbw2,而orapid=14是lms1.

    5、从数据库alert log来看,在Jun 26 21:54:10 有提示lck0 进程已经超过85秒没有响应

    LCK0 (ospid: 29987) has not called a wait for 85 secs
    

    根据时间点来计算,大概在Jun 26 21:52:45点左右开始,LCK0进程即没有响应了。
    那么很明显,我们只要知道LCK0进程为什么会hung,就知道了此次故障的原因。
    那么我们来看看LCK0的trace文件,看能不能看到一些线索。

    6、LCK0进程的trace信息

    *** 2015-06-26 21:50:29.329                                                                                Process diagnostic dump for oracle@ebtadbsvr2 (LCK0), OS id=29987,  
    pid: 36, proc_ser: 2, sid: 1729, sess_ser: 3                                                          
    -------------------------------------------------------------------------------                                             
    loadavg : 6.47 26.96 34.97                                                                                                 
    Memory (Avail / Total) = 10598.05M / 64421.55M                           
    Swap (Avail / Total) = 20256.00M /  20479.99M            
    F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD           
    0 S oracle   29987     1  0  76   0 - 10541946 semtim Apr05 ?     01:25:21 ora_lck0_orcl2 
    Short stack dump:                                        
    ksedsts()+461<-ksdxfstk()+32<-ksdxcb()+1782<-sspuser()+112<-__restore_rt()<-semop()+7<-skgpwwait()+156<-kslgess()+1799<-ksl_get_shared_latch()+620<-kclbufs()+272<-kclanticheck()+412<-kclahrt()+88<-ksbcti()+212<-ksbabs()+1732<-kclabs()+186<-ksbrdp()+923<-opirip()+623<-opidrv()+603<-sou2o()+103<-opimai_real()+266<-ssthrdmain()+214<-main()+201<-__libc_start_main()+244<-_start()+36
    
    *** 2015-06-26 21:54:18.438
    Process diagnostic dump for oracle@ebtadbsvr2 (LCK0), OS id=29987,
    pid: 36, proc_ser: 2, sid: 1729, sess_ser: 3 
    -------------------------------------------------------------------------------
    loadavg : 2.04 13.34 27.63
    Memory (Avail / Total) = 9519.06M / 64421.55M
    Swap (Avail / Total) = 20256.00M /  20479.99M
    F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
    0 R oracle   29987     1  0  85   0 - 10541965 ?   Apr05 ?        01:26:55 ora_lck0_orcl2
    Short stack dump: 
    ksedsts()+461<-ksdxfstk()+32<-ksdxcb()+1782<-sspuser()+112<-__restore_rt()<-kcbo_get_next_qheader()+255<-kclbufs()+321<-kcldirtycheck()+231<-kclahrt()+93<-ksbcti()+212<-ksbabs()+1732<-kclabs()+186<-ksbrdp()+923<-opirip()+623<-opidrv()+603<-sou2o()+103<-opimai_real()+266<-ssthrdmain()+214<-main()+201<-__libc_start_main()+244<-_start()+36
    
    

    从上述lck0进程的几个时间点的信息来看,第一个时间点21:50:29 :wchan 为semtim。wchan,表示进程sleeping的等待表现形式。semtim表示在该时间点,lck0 进程一直处于sleep状态。所谓的sleep状态,是进程持有的资源是不会释放的。

    而在第2个时间点21:54:18,lck0进程的wchan状态是 ?,这表示未知,如果是为空,则表示该进程处理running状态。在21:50到21:52 时间段内,LCK0进程仍然没有恢复正常。那么LCK0到底被什么阻塞了(或者说它需要的资源被谁占用了)?
    同时也可以看到内存和swap都空闲很多,CPU也并不很忙。

    7、继续检查trace,在21:50时间点我们发现,lck0进程是被MMON进程锁阻塞了

    SO: 0x9d10f97c0, type: 2, owner: (nil), flag: INIT/-/-/0x00 if: 0x3 c: 0x3
     proc=0x9d10f97c0, name=process, file=ksu.h LINE:11459, pg=0
    (process) Oracle pid:31, ser:1, calls cur/top: 0x965657408/0x9b17e3f18
              flags : (0x2) SYSTEM
              flags2: (0x20),  flags3: (0x0) 
              intr error: 0, call error: 0, sess error: 0, txn error 0
              intr queue: empty
    ksudlp FALSE at location: 0
      (post info) last post received: 0 0 35
                  last post received-location: ksr2.h LINE:603 ID:ksrpublish
                  last process to post me: 9911283b0 2 6
                  last post sent: 0 0 26
                  last post sent-location: ksa2.h LINE:282 ID:ksasnd
                  last process posted by me: 9911283b0 2 6
      (latch info) wait_event=0 bits=26
        holding    (efd=7) 993cfec60 Child object queue header operation level=5 child#=117 
            Location from where latch is held: kcbo.h LINE:884 ID:kcbo_link_q: 
            Context saved from call: 0
            state=busy(exclusive) [value=0x200000000000001f, holder orapid=31] wlstate=free [value=0]
            waiters [orapid (seconds since: put on list, posted, alive check)]:
             36 (82, 1435326627, 1)
             21 (81, 1435326627, 1)
             waiter count=2
        holding    (efd=7) 9b5a5d630 Child cache buffers lru chain level=2 child#=233 
            Location from where latch is held: kcb2.h LINE:3601 ID:kcbzgws: 
            Context saved from call: 0
            state=busy [holder orapid=31] wlstate=free [value=0]
        holding    (efd=7) 9c2a99938 Child cache buffers chains level=1 child#=27857 
            Location from where latch is held: kcb2.h LINE:3214 ID:kcbgtcr: fast path (cr pin): 
            Context saved from call: 12583184
            state=busy(exclusive) [value=0x200000000000001f, holder orapid=31] wlstate=free [value=0]
      Process Group: DEFAULT, pseudo proc: 0x9b11ca008
      O/S info: user: oracle, term: UNKNOWN, ospid: 29967 
      OSD pid info: Unix process pid: 29967, image: oracle@ebtadbsvr2 (MMON)
    

    从上面的trace可以看到之前一直被等待的993cfec60 资源(Child object queue header operation)正被 mmon进程持有。

    21:50:29的时候LCK0在等待mmon释放资源,而此时mmon出现异常,因此在21:51:06 mmon 进程被LMHB强制重启。然后在重启后,由于mmon的异常,导致21:54:18该资源仍无法被lck0 进程正常持有,最终导致21:54:20LMHB进程强制重启了整个实例。
    因此,最终的罪魁祸首是mmon进程。

    Fri Jun 26 21:50:26 2015
     LCK0 (ospid: 29987) waits for latch 'object queue header operation' for 77 secs.
     Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl2/trace/orcl2_lmhb_29939.trc  (incident=204141):
     ORA-29771: process MMON (OSID 29967) blocks LCK0 (OSID 29987) for more than 70 seconds
     Incident details in: /u01/app/oracle/diag/rdbms/orcl/orcl2/incident/incdir_204141/orcl2_lmhb_29939_i204141.trc
     MMON (ospid: 29967) is blocking LCK0 (ospid: 29987) in a wait
     LMHB (ospid: 29939) kills MMON (ospid: 29967).
     Please check LMHB trace file for more detail.
     Fri Jun 26 21:51:06 2015
     Restarting dead background process MMON
     Fri Jun 26 21:51:06 2015
     MMON started with pid=213, OS id=16612
    

    mmon进程Oracle是用于进行AWR信息收集的。既然案情发生的原因与它有关,那么接下来的分析自然是查看它的相关trace了。

    8、检查MMON的相关trace 可以看到,MMON进程负责处理对象的统计信息。

    从trace中可以看到大量的cursor包含了太多的子游标,例如:

    User=b1456358 Session=c146d760 ReferenceCount=1 Flags=CNB/[0001] SavepointNum=558d5760 
          LibraryHandle:  Address=2f79eb08 Hash=3dec6f4a LockMode=N PinMode=0 LoadLockMode=0 Status=VALD 
            ObjectName:  Name=        select time_mp, scn, num_mappings, tim_scn_map from smon_scn_time   where scn =    (select max(scn) from smon_scn_time where scn <= :1)
    
              FullHashValue=c36d5a579fdc3e19733192893dec6f4a Namespace=SQL AREA(00) Type=CURSOR(00) Identifier=1038905162 OwnerIdn=0 
            Statistics:  InvalidationCount=0 ExecutionCount=23741 LoadCount=107 ActiveLocks=1 TotalLockCount=6093 TotalPinCount=1 
            Counters:  BrokenCount=1 RevocablePointer=1 KeepDependency=106 KeepHandle=106 
    BucketInUse=6092 HandleInUse=6092 
            Concurrency:  DependencyMutex=2f79ebb8(0, 0, 0, 0) Mutex=2f79ec30(0, 87578, 0, 0) 
            Flags=RON/PIN/TIM/PN0/DBN/[10012841] 
            WaitersLists:  
              Lock=2f79eb98[2f79eb98,2f79eb98] 
              Pin=2f79eba8[2f79eb78,2f79eb78] 
            Timestamp:  Current=04-05-2015 09:48:42 
            LibraryObject:  Address=dff3bc60 HeapMask=0000-0001-0001 Flags=EXS[0000] Flags2=[0000] PublicFlags=[0000] 
              ChildTable:  size='112' 
                Child:  id='0' Table=dff3cb60 Reference=dff3c5b0 Handle=2f79e908 
                Child:  id='1' Table=dff3cb60 Reference=dff3c8e0 Handle=2f4e2d90 
                Child:  id='2' Table=dff3cb60 Reference=df3e7400 Handle=2f8c9e90 
                Child:  id='3' Table=dff3cb60 Reference=df3e76e8 Handle=2f8abce8 
                ......
                ......
                Child:  id='101' Table=dc86f748 Reference=df02d368 Handle=288e6460 
                Child:  id='102' Table=dc86f748 Reference=dd65c3e0 Handle=274d0b40 
                Child:  id='103' Table=dc86f748 Reference=dd65c6c8 Handle=29aa92f8 
                Child:  id='104' Table=dc86f748 Reference=dd65c9b8 Handle=26f3a460 
                Child:  id='105' Table=dc86f748 Reference=dd65ccd0 Handle=25c02dd8 
            NamespaceDump:  
              Parent Cursor:  sql_id=76cckj4yysvua parent=0x8dff3bd48 maxchild=106 plk=y ppn=n 
                Current Cursor Sharing Diagnostics Nodes:  
                 ......
                 ......
                  Child Node: 100  ID=34 reason=Rolling Invalidate Window Exceeded(2) size=0x0 
                    already processed:   
                  Child Node: 101  ID=34 reason=Rolling Invalidate Window Exceeded(2) size=0x0 
                    already processed:   
    

    类似上面的信息非常多。很明显,上述parent cursor包含了大量的子游标,这是为什么在20点-21点(节点2还未重启前的时段)的awr报告中出现大量cursor: mutex S 的原因,如下是这个时段的等待事件:

    Event Waits Time(s) Avg wait (ms) % DB time Wait Class
    DB CPU 47,072 93.05
    cursor: mutex S 31,751,317 18,253 1 36.08 Concurrency
    gc cr multi block request 359,897 1,281 4 2.53 Cluster
    gc buffer busy acquire 10,465 686 66 1.36 Cluster
    library cache lock 9,285 550 59 1.09 Concurrency

    在mmon正常通过内部SQL收集系统信息时,根本不应该出现这种情况,而此时MMON进程却出现异常,这个异常看来应该是与cursor子游标过多有关了。

    9、最后数据库实例被强行终止的原因是lck0进程出现异常导致lmhb进程强行终止instance
    在最后instance终止之前的diag dump中,lck0进程的状态仍然是hang的状态,同时也阻塞了3个其他session,如下:

        SO: 0x9914dbce8, type: 4, owner: 0x9911283b0, flag: INIT/-/-/0x00 if: 0x3 c: 0x3
         proc=0x9911283b0, name=session, file=ksu.h LINE:11467, pg=0
        (session) sid: 1729 ser: 3 trans: (nil), creator: 0x9911283b0
                  flags: (0x51) USR/- flags_idl: (0x1) BSY/-/-/-/-/-
                  flags2: (0x408) -/-
                  DID: , short-term DID: 
                  txn branch: (nil)
                  oct: 0, prv: 0, sql: (nil), psql: (nil), user: 0/SYS
        ksuxds FALSE at location: 0
        service name: SYS$BACKGROUND
        Current Wait Stack:
          Not in wait; last wait ended 1 min 39 sec ago 
        There are 3 sessions blocked by this session.
        Dumping one waiter:
          inst: 2, sid: 1009, ser: 1
          wait event: 'latch: object queue header operation'
            p1: 'address'=0x993cfec60
            p2: 'number'=0xa2
            p3: 'tries'=0x0
          row_wait_obj#: 4294967295, block#: 0, row#: 0, file# 0
          min_blocked_time: 81 secs, waiter_cache_ver: 14285
        Wait State:
          fixed_waits=0 flags=0x20 boundary=(nil)/-1
    

    对于数据库进程,如果状态不是dead,而是busy,而且持有latch不释放,那么这意味着该进程已被挂起,lck0 持有的latch是object queue header operation。oracle mos文档也有关于该event 的描述如下:Scans of the object queue in the buffer cache can hold the “object queue header operation”。

    基于上述的分析,我们最终判断,lck0 进程出现问题的原因与cursor 子游标过多有关。同时,这又与在11.2.0.1版本上的child cursor总数阀值限制过高有关(实际在版本10g中就引入了该Cursor Obsolescence游标废弃特性,10g的child cursor 的总数阀值是1024,即子游标超过1024即被过期,但是这个阀值在11g的初期版本中被移除了。这就导致出现一个父游标下大量child cursor即high version count的发生;由此引发了一系列的版本11.2.0.3之前的cursor sharing 性能问题。这意味着版本11.2.0.1和11.2.0.2的数据库,将可能出现大量的Cursor: Mutex S 和 library cache lock等待事件这种症状,进而诱发其他故障的发生。

    因此, 强烈建议11.2.0.3以下的版本应尽快将数据库版本升级到11.2.0.3以上(11.2.0.3中默认就有”_cursor_obsolete_threshold”了,而且默认值为100),或者通过_cursor_features_enabled 和106001 event来强制控制子游标过多的情况。

    3. 结案陈词

    该案例的分析还是有些曲折,因为常见导致单节点故障最常见的情况主要是心跳、节点资源之类,而该案例的诱发原因相对有些诡异,先是出现了ora-600错误,然后又报了kill mmon的信息,这都让案情分析有些扑朔迷离,当然,最终我们还是找出了问题的主要根源。

    通过该起案件我们发现:

    1. 数据库版本的选择绝对是影响系统稳定性的关键要点;
    2. 不要以为性能问题只是影响用户体验,有些性能问题是会诱发系统一系列问题的;
    3. 问题的分析不要想当然,通过trace逐步递进,结合原理与经验,才能更为准确的确定问题;
    4. 子游标过多千万不能小视,最好能找出根源并解决它,如果确实不好解决,那么可通过设置隐含参数_cursor_features_enabled 和106001 event强制失效子游标的方式来防止子游标过多的情况,操作如下:
    SQL> alter system set "_cursor_features_enabled"=300 scope=spfile;
    SQL> alter system set event='106001 trace name context forever,level 1024' scope=spfile;
    

    正常重启数据库即可。

    Q&A

    1、在什么情况下可以重用父游标和子游标呢?

    父游标只要SQL代码共享就可以重用,子游标的要求的比较多,特别是当使用了绑定变量或者谓词字段的数据分布倾斜的时候,很容易出现多个子游标的情况,具体子游标不能共享的原因,可以查v,这个视图里的一堆字段表明了某个特定父游标的子游标不能共享的各种原因

    2、请问一下,监测rac心跳能否用直连网线?一般你们怎么做?

    rac的心跳从原理上是可以使用直连网线的,但无论是稳定性还是传输速率都不能完全满足心跳的要求,因此Oracle从9i开始,在白皮书里明确写了不允许使用直连线的方式,主要就是出于心跳稳定和传输速率考虑。其实如果心跳压力非常小的话,用直连肯定也可以,只是用rac的大部分是核心,一般不愿意去冒险。

    3、能不能简单说下 rac 的高可用和我们平时做的双机热备有哪些区别呀。

    rac的高可用是两节点的数据库实例同时可用,而传统的ha则只是在一个节点上可用实例,另一个节点的实例并没有启动,因此,简单来说,rac比ha至少在高可用能力上更强(两节点同时在用,一旦单节点故障,故障节点的会话可以无缝切换到另一可用节点,前端没有业务中断的感觉,当然,这个需要配置好才行),而ha一旦单节点故障,业务一定得中断,等待另一节点实例起来之后才能连接。 同时,rac也能同时发挥两台机器的效能,而ha的一个节点完全是浪费着(有的用户为了避免这种浪费,就把两个库分别在ha的两个节点运行,让两节点的两个库互为热备)

    4、请问除了子游标以外,还有哪些因素会导致,RAC宕机或者导致其不稳定。

    rac不稳定的因素很多,最典型的就是心跳线不稳定或者心跳线出现数据风暴,此外,11g的DRM特性也很容易导致rac单节点宕机,一般我们都会建议禁用DRM特性。此外,11g还有很多新特性都会诱发节点宕机,比如我们以前还遇到过由于asm实例内存太小,而在rac的asm上部署的数据库太多导致asm实例挂掉,从而导致rac库宕掉的。原因很多了

    5、能否简单介绍下 在 oracle优化中对游标的优化思路与RAC常用优化方向。

    游标的优化思路,最简单也是最根本的就是在适当的场景下用绑定变量,在不该用的时候不要乱用绑定。比如,谓词倾斜的字段就极度不适合绑定。另外,统计信息的准确性,尤其是倾斜字段的统计信息准确性也直接影响着子游标的产生。还有一些参数也要注意,特别是cursor_sharing,宁愿设置成force,也尽量不要用similar,similar很容易遭遇bug,导致一堆子游标撑爆shared pool。最后就是我们那个案例中的不同版本对子游标数的限制,不能放任子游标无穷增长。
    rac的优化牵扯面比较多,我先零零星星写一些吧,太多了。比如sequence,在rac下一定要开启cache,而且不能太小,我们对于一些常用的sequence甚至建议开启cache到500以上,决不能使用order。
    再比如如果发现GC的enq特别多,那么就要考虑做业务分割,把操作不同表的会话连接到不同的节点实例上,减少两节点对同一张表的征用。

    6、请说一下,RAC宕机的处理思路,谢谢。

    对于宕机,基本上都是从数据库的alert.log看起,一般告警日志里都会有最后宕掉时数据库做的事情,甚至有更为详细的trace文件信息,那么就需要根据这些信息结合rac各进程的关系来进行分析,这个的确不是一两句话能说的完的。总之,肯定是要看数据库告警日志和crs日志的,asm的日志有时候也要看。而导致宕机的原因同样五花八门,有些是系统原因,比如asm存储阵列出问题、光纤链路不稳定、swap耗尽等等,有些是数据库问题,比如心跳检测超时,为了恢复出问题的节点,自动宕掉那个节点重启,比如由于一些数据库的bug或者异常导致Oracle的某些关键进程被强制杀掉之类。。。可能性非常多了



  • 请问除了子游标以外,还有哪些因素会导致,RAC宕机或者导致其不稳定。



  • 能否简单介绍下 在 oracle优化中对游标的优化思路与RAC常用优化方向



  • 请说一下,RAC宕机的处理思路,谢谢。



  • 问题 整理

    1、在什么情况下可以重用父游标和子游标呢?

    2、请问一下,监测rac心跳能否用直连网线?一遍你们怎么做?

    3、能不能简单说下 rac 的高可用和我们平时做的双机热备有哪些区别呀。

    4、请问除了子游标以外,还有哪些因素会导致,RAC宕机或者导致其不稳定。

    5、能否简单介绍下 在 oracle优化中对游标的优化思路与RAC常用优化方向。

    6、请说一下,RAC宕机的处理思路,谢谢。


登录后回复
 

与 青云QingCloud 社区 的连接断开,我们正在尝试重连,请耐心等待