在开始向大家分享之前,先说说 Oracle 的错误的标示体系,大家都知道在 Oracle 数据库中有大量的错误,比如以 ora-开头、tns-开头、crs-开头,当然还有其他工具类的错误开头比如 exp 和 imp 等。
当然都是大家熟悉的错误开头,其中 ora-类错误大家接触的最多,这是和 Oracle 数据库相关的错误类别,今天就和大家分享的是 ora-00481错误。
我们先来看看 ora-00481 的含义及可能的原因。
Ora-00481 错误意思是 lmon 进程 abort。
Ora-00481 错误的可能原因有以下几种:
1. 由 DRM 引起,当 DRM 开始后但是并未完成所致。
2. ASM 或者 database 启动失败造成 RAC 重构时报 ora-00481错误
3. Lmon 与 OCSSD 通信失败出现 ora-00481 错误
4. 实例被驱逐时伴随 ora-00481 错误。
以上4条引起481错误的原因。
下面就这几个可能原因简单在日志中反馈的结果做下分析:
1. 由 DRM 引起的481错误。
由 DRM 引起的 ora-00481错误,是由于 DRM 开始但是并未完成导致,在 lmon 的 trace 文件中会显示 DRM 并未完成的提示:
在上述 trace 中,没有 End DRM(107) 的信息。意思就是 DRM 期间,LMON 进程没有工作导致 DRM 并没有完成,以至于实例被驱逐。在这种情况下需要更多日志信息来确定是由于 DRM 未完成导致的,我们可以按照下述的步骤进行一步步的确定:
A. LMSx trace 文件给出如下类似的信息:
上述显示需要更多的 LOCK ELEMENTS (简称 LE) , 但是没有有效的。
LMS 进程在 DRM 重构的过程中由于 LE 短缺导致失速,然后导致 DRM 超时并造成实例的crash.
这种问题需要打补丁 bug:11875294,bug:12537479,根据补丁内容设置参数_gc_read_mostly_locking。
B. 还有一种情况如下;
在 lmon trace文件中体现如下:
LMON 进程等待 LMD 接收 ftdones。
进一步查看 LMD0 的 trace 文件,来确定为什么 LMD 不工作了,这个需要查看所有节点上的 LMD0 的 trace 文件。如下:
在 trace 文件中 “avl 0”意味着目前该节点可用的 ticket 数量为0;所以 LMS 进程跑出了 flow control tickets 的范围,在该种情况下,Oracle 推荐更新相应补丁来解决此类问题,比如:bug16819962.17452841,17801017,17847764,16088176;或者通过调整初始化参数_lm_tickets 来增加 tickets 的数量;根据我们的实际经验,对于高并发系统来讲,建议调整为5000。
这里很可能人可能并不理解什么是 ticket,这里我再为大家简单介绍一下 Oracle ticket 消息机制,这是 Oracle 为了保证在实例之间传输的消息的平衡和对传输的消息的几率,控制彼此之间的合理流量而引入的一个消息机制,RAC 通过 ticket 对彼此之间传输的流量和几率进行控制。
一个节点发送一则消息队列的同时会带着一个 ticket 到对端,对端的 ticket 会增加。本地的 ticket 会减少,本地节点会根据可用的 buffer 和已经收到的信息以及发送的请求 ticket 的信息(null-req)计算本地可用的 tickets。当本地没有 ticket 可用,本地的 LMS/LMD 就会进入消息等待队列,并持续的检查 ticket latch 里的信息,判断是否有可用的 ticket 的信息可用。直到对端发送回 message,并带回可用的 tickets 后,本地才能再继续发送消息到对端。上述的例子就是由于实例间 ticket 短缺,引发 LMS/LMD 之间消息传输超时出现的故障。
这个可以通过视图 GV$GES_TRAFFIC_CONTROLLER 来获取每个节点上的 avalible 的 ticket 的数量,或者可以通过隐含参数_lm_tickets 来进行控制,该参数默认值是1000,通过该参数可以避免上述出现的错误。
2. 在 alert 中发现如下信息:
并且这条信息是在实例被驱逐或者实例由于 ora-00481abort。
在这种情况下,有三种思路,如下;
① 心跳网络连接问题,
② HAIP 的问题,在这种情况下,先需要确定 HAIP 是否可以正常使用。
③ 服务器负载压力过大。可以通过 oswatcher 来收集系统资源使用情况。
3. 在 alert 中发现如下信息:
Ora-29701 错误,意思 lmon 与 OCSSD of CRS/GridInfrastructure. 丢失连接。
在这种情况有两种思路:
① 确定是否有 job 或者用户误删除了 /tmp/.oracle 和 /var/tmp/.oracle
② 更新补丁 bug 14096821.
Ora-00481 错误可能出现的原因以及日志中的反馈我们已经大概了解了,下面我们就看看用户 crm 库的具体情况。
客户这的 crm 数据库在8月1日早上2节点突然业务连接中断,查看2节点 alert 日志发现日志中报了 ora-00481 错误,并且后续导致2节点实例 abort,在2分钟之内又重新启动,恢复正常。
先介绍下客户这边的环境 HP-Unix + RAC, Oracle 版本10.2.0.4 使用的是裸设备。所以需要收集的日志文件有,database alert 日志,trace 文件(lmon, lmd, lms, diag, lmhb, dia0),按照顺序先收集 database alert 日志,如下:
上述信息中,只是表明了由于481错误终止了实例,所以需要更多的信息来确定问题来源。
在分析 LMON 的 trace 文件之前,简单的描述下 LMON 进程,LMON 进程,主要是监控 RAC 的 GES 信息以及负责检查集群中各个节点的健康情况,当有节点出现故障时,负责进行 reconfig 以及 GRD (globalresource Directory) 的恢复等。
RAC 的脑裂机制,Lmon 进程检查到实例级别出现脑裂时,会通知 clusterware 来进行脑裂操作,当等待超过一定时间,那么 LMON 进程会自动触发 IMR (instancemembership recovery),这实际上也就是我们所说的 Instancemembership reconfig。
其次,lmon 进程主要通过2种心跳机制来检查判断集群节点的健康状态:
① 网络心跳(主要是通过 ping 进行检测)
② 控制文件磁盘心跳,其实就是每个节点的 ckpt 进程每3s更新一次 controlfile 的机制。
现在查看上述中给出的 lmon 的 trace 日志文件:
我们可以看出在 LMON 进程的 trace 文件中最近的记录为4月24日,并没有发现故障时间点8月1日的相关信息。由于是 Oracle LMON 检测到异常后并终止了实例,那么我们进一步分析 LMON 进程;
因此我们这里进一步检查确认是否有相关的有价值的线索。
通过 ls -rtl | greplmon 命令得到最近的 LMON 的 trace 日志。
查看最近的 LMON 的 trace 日志,ngcrm2_lmon_11361.trc
结合 alert 和 LMON trace 查看,时间点顺序是这样的:
时间 1 08:29:43,实例终止,
时间 2 08:30:11.107 在 LMON trace 中 reconfigure 开始,
在结合 alert 日志中
时间 1 08:30:00 实例进程启动
时间 2 08:30:06,实例启动完成,启动后台进程包括 LMON 进程,
时间 3 08:30:18 进程 CRS 重构,
时间 4 08:30:35 database open。
也就是说上述的 LMON 进程的 trace 文件是在实例恢复后的 trace 文件,在之前的就没有,而且在实例恢复后的 LMONtrace 文件中看到 DRM Reconfiguration 都是正常的。所以在这没办法判定是否是由于 DRM 造成的481错误。
需要进一步来查看 lmd 日志和 diag 日志,以及 lms 日志:
Lms 日志(more ngcrm2_lms0_11365.trc)
LMD 日志(ngcrm2_lmd0_11363.trc)
Diag 日志信息(ngcrm2_diag_11357.trc)
在这三个日志中由于设置了 dump_file_size 的大小为 5M,之前的日志都没法查看。
但是在 alert 日志中和 LMON 日志,LMD 日志中多次出现与 DRM 相关的内容,而且在 LMD 日志中,出现的如下两条内容:
以及 LMON 日志中的:
等信息,在结合我们之前分析的 ora-00481 错误出现的几个因素,是由于 DRM 开始后未完成,在实例启动起来后,重新进行未完成的 reconfiguer. 并且在之后的 LMON trace 文件中,还可以看到一些 DRM 开始以及结束的信息,且非常频繁。
总结:基于我们对 Oracle lmon 等进程的原理以及结合前面的种种日志分析,我们认为此次故障跟 Oracle DRM 有极大关系(实际上我们在其他客户案例中遇到了很多类似情况,尤其是 Oracle 10g rac 环境中,DRM 稳定性较差)。
DRM(Dynamic Resourcemanagement)动态资源管理。真正实现是在10.1.0.2之后的版本之后,10g 之前也有。
该特性的设计初衷是为了通过更改所访问资源的 master node 降低跨节点频繁访问需求,通过更改 master node 的节点属性,让访问资源的频繁的节点成为 master node ,把节点之间的块交换放在节点本地以降低节点之间访问块的低价。在 10gR2 之后,file affinity 演化为细粒度更高的 object affinity,并且同时引入了 undoaffinity,只要是满足隐含参数要求,DRM 就会被启用,可以通过 LMON 和 lms 的 trace 文件就可以发现有很多的 remastering. 在11g之后 Oracle 引入了两个重要的指标。Read-mostly locking 以及 reader bypass.。read-mostly locking: 简单的说就是,对于某个对象,比如读非常多,预先给它加一层共享访问锁,所有结点都持有,因而减少了共享锁的申请操作。而当需要写操作时,需申请排它锁时,在每个结点上都申请一个”anti-lock”锁,可以理解为”反锁”,然后再 cache fusion。
reader bypass:与 read-mostly locking 是互斥的,主要是为读少写多的业务进行的优化。reader bypass 同样引入了一种新的锁模式 weakX lock(又称 xw 锁)。可以在S锁没有释放以前,为一个 block 加上一个xw锁,对这个 block 进行修改,但是不允许立刻 commit,直到所有的的S锁都关闭或者降级到N锁,LMS 就会向 xw 锁的持有者发送一条信息可以进行 commit.
该案例中,最终建议用户关闭 DRM,关闭 DRM 可以设置如下两个参数。
但是有一点,客户的环境都是生产系统,而且在1号中午12点之前是出账时间,不允许重启数据库,所以只能临时的增大上述两个参数的值,减少 DRM 被触发的机率,变相的关闭 DRM。在屏蔽 DRM 后,目前数据库至今允许稳定。
更改参数如下:
在11gR2 之后可以通过_lm_drm_disable 可以在线动态禁用 DRM,对于该参数的描述如下:
设置_lm_drm_disable 在不同的 level 有不同的含义。
Level4 disable read mostly
Level 5 disable DRM for all but undo
Level 7 disable DRM for all including undo.
一般情况下建议 level 设置为5。命令如下:
Altersystem set “_lm_drm_disable”=5;
最后总结下,伴随481错误的出现往往就是实例的重启,而且我们也看到了,481错误出现的场景都是在 RAC 环境下,在 RAC 稳定的情况下,唯一考虑的也就是心跳问题和 DRM 问题,这两个问题其实都还是跟各个节点的业务运行情况有关系,为了降低心跳压力和 DRM 重构,最好的手段还是对业务进行分离,如果不然,检查各自的数据库环境的参数,确保不会出现上述相关隐含参数未改的情况,在两节点压力过大的情况下会导致节点实例重启。