love wife love life —Roger的Oracle/MySQL/PostgreSQL数据恢复博客

Phone:18180207355 提供专业Oracle/MySQL/PostgreSQL数据恢复、性能优化、迁移升级、紧急救援等服务

PMON failed to acquire latch导致crash的案例联想

本站文章除注明转载外,均为本站原创: 转载自love wife love life —Roger的Oracle/MySQL/PostgreSQL数据恢复博客

本文链接地址: PMON failed to acquire latch导致crash的案例联想

一朋友公司的OA系统挂了(泛微技术支持说是神马神马),友情帮忙分析一下。 如下是alert log信息:

从日志来看,我们可以看到,6月30号08:44:40时出现M000进程无法创建进程的error信息,接着08:46:21开始,
Pmon进程开始报错无法获得latch,最后到08:53:52时间点smon进程出现异常,最后08:53:57时,MMAN进程终止
了数据库实例。

从上面的信息来看,MMAN进程最后强行终止了实例。对于MMAN进程,大家知道它是干什么的么?

首先我们需要了解一下,Oracle数据库中的一些核心进程,如果是单实例环境,那么下面是一些核心进程:
pmon、smon、dbwr、lgwr、reco、ckpt、mman(10g引入)、PSP0. 这些进程中的任何一个进程出现异常都会导致数据库crash。

如果是RAC环境,那么还有lmon,lmd,lck等核心进程。

前面的信息可以看出,smon进程出现了异常,在smon进程报错之前,pmon一直在报错无法获得latch。 下面我们来看下
pmon 进程的trace内容:

可以看到Pmon进程无法获得shared pool Latch,该latch的地址为:600eca50.且该该地址正被pid=944所持有没有释放,如下:

可以看到该进程不但持有了shared pool latch(600eca50),同时还持有library cache latch(3721e0170).

一个进程同时持有2个latch,且从这2个latch来看,显然跟shared pool有关系,我们不难判断可能是内存出现异常了。
同时我们分析日志还发现了如下信息:

可以看到smon进程发现了死进程16087,这里信息不足,不知道该进程是什么。结合前面的总总分析不难判断应该是
跟内存有极大关联。同时最开始的alert log中也报错m000无法创建,该进程是mmon的slave进程。下面我们来分析
mmon进程的trace,发现了如下内容:

可以看到free memory已经为0了,这里较为遗憾的他这里的环境变量配置可能不对,导致调用gdb失败,否则trace
文件中应该还会存在该进程的call stack等信息,不过这里不足以影响我们整个分析过程。

不知道大家发现没有,比较怪异的是这里居然没有使用swap? 而且total也是0M,那么到没有配置swap吗?

据了解,该主机的物理内存为16GB,而SGA分配了12G,PGA分配了2GB。这明显设置有点偏大了。

最后综合前面的信息,我们可能不难判断他这里数据库之所以crash是因为memory资源不足导致的

分析到这里就完了吗?  可能很多人跟我一样存在如下的几个疑问:

1) 进程为什么持有shared pool latch不释放?
2) 进程什么情况需要去申请获得shared pool latch?
3) shared pool latch只有一个吗?为什么导致争用?
4) 如果shared pool latch存在多个children latch,那么是否可以避免这个问题?
要回答上面这几个问题,我们需要通过实验来研究一下。首先来看下我的Linux 5.4+oracle 10.2.0.5 环境:

可以看到shared pool latch最多可以有7个children latch可用。下面我们通过实验来探讨一下(这里准备了多个session)。

当Session 1 poke 之后,Session 2执行如下查询:

正如所料,该查询hang了.

在事先已经连接上的Session 3中进程dump,来观察session 2 hang住之后的情况是什么样的:

roger_ora_21619.trc 文件的部分信息如下:

从前面的测试可以看出,当_kghdsidx_count参数为1时,shared pool是没有subpool的,其只有一个shared pool latch.
虽然从v$latch_children查到有7条记录。 也正是因为这样,当我一个进程持有shared pool latch后不释放,那么其他进程
都进行任何查询都将会hang住,因为必须等待shared pool latch.

我们先将latch释放:

当latch释放之后,session 2立刻返回结果:

到这里,或许很多人都跟我之前的想法一样?之所以会等待,是由于只要一个shared pool latch可用。那么如果存在多个呢?
即有children latch可用的情况下,其他session 还会hang住吗? 我们继续来看下面的实验:

++++Session 1

这里前面的3个child latch应该是可用的.  我测试过程中发现即持有其中任何一个latch,对于新登陆的SQLPLUS会话都会hang住。

接着还测试了一下硬解析,软解析和软软解析的情况:

可以发现,再次执行该SQL,仍然hang,也就是说软解析,仍然会hang.

当Session 2会话多次执行该SQL之后(我们知道执行超过3次,其对应的cursor就会被cache),如下:

对于软软解析的测试结果是这样的;

有点让我匪夷所思,不知道大家看了是什么感慨?

所以我认为对于硬解析和阮解析都是需要获得shared pool latch的,另外对于需要操作shared pool那么都需要获得(这里主要是memory消耗或释放).
因此这也不难理解为什么Oracle PMON进程需要获得shared pool latch了。

那么为什么进程会持有latch不释放呢? 我们知道latch的申请或释放正常情况下都是极快的。一般来讲无非有如下情况:
1)进程本身hang住了
2)进程dead
3)Oracle bug
另外,即使shared pool有多个child latch可用,也会导致争用等待。 只是这里还有一个问题,我始终未能想明白,那就是:

假设现在存在3个可用的child latch,假设其中一个被持有,还有2个可用;如果此时有会话A进行操作,那么会话A会怎么样?

从目前的测试来看,会话A一定会hang住。 跟老熊请教了一下,他的猜测是:Oracle这里会根据进程号来进行hash运算得到一个值,
来确认使用哪个child latch,而不是一定会固定去申请使用某个子latch。

对于这个算法,我也比较赞同,之所以赞同是因为library cache中针对SQL文本进行hash运算,得到bucket编号。 另外oracle

cache buffer的算法也是类似:
假设file 1 block 437,那么计算方式应该是这样:
SQL> select mod(438,4) from dual;

MOD(438,4)
———-
2

即使该block的信息会存在编号为2的bucket里面。
这是一个大胆的猜测,从我目前的测试来看,似乎有点站不住脚。这一点我还需要进一步测试验证。

最后欢迎大家补充!周末会再进行一个详细测试,到时再分享!

One Response to “PMON failed to acquire latch导致crash的案例联想”

  1. simon Says:

    兄弟 网站的背景音乐 能不能关掉啊 好吵闹~~~

Leave a Reply

You must be logged in to post a comment.