DBA小y
作者DBA小y2017-12-05 12:29
系统工程师, 中亦科技

风险提示:操作系统动态增加CPU带来的数据库重启风险

字数 6623阅读 1755评论 0赞 4

作者:老K


导语

线上的生产系统,因为一些原因,时不时会出现一些意想不到的性能问题,当紧急问题出现时,我们如果无法立即解决,有时通过调整系统硬件资源是一种快速有效的解决应急方式,确保系统能正常运行后,再做根因分析,从根本上解决问题;

最近老K遇到了客户的应急策略导致了数据库重启的案例,翻了翻邮件历史,竟是N年前就已经遇到过了;问题本身不算复杂,然而却可以造成数据库直接重启,影响生产,这里特别分享出来,给大家一个风险提示;

今天老K为大家分享的这么一个案例:

某系统增加新业务,在数据库正常运行,原业务不停业的情况下,在数据库上完成版本投产的相关操作,结果投产过程偏慢,应用维护团队担心投产窗口无法正常完成投产动作,需要系统维护团队帮助分析加快投产动作;然而,在针对这一问题应急之后,数据库却发生了重启,反而更严重的影响了投产动作。

那么,是谁造成了重启呢?我们应急过程中做出了什么错误的判断吗?我们需要怎样避免再次发生类似的悲剧呢?本次分享从最后的故障出发,给大家带来一次隐蔽的应急深坑,同时文末也给出我们总结的一些应急手段引入新问题的经验教训!

Oracle数据库问题,还是找不到原因?
不妨找中亦科技试试,我们将尽最大努力为您找到导致故障和性能问题的根本原因。

问题来了

周六,正是某个客户的投产日,投产时间为晚间19:30开始,持续到翌日早上九点,老K负责现场支持任务。

投产系统多,七点半刚过,各种咨询接踵而至,老K正忙的不亦乐乎,电话过来了:“老K,快来这边帮帮忙看下,应用维护团队说投产动作比较慢,看看有没有什么办法加快下速度?”类似的电话接了不少,问题总要一个一个处理,但是刚刚电话涉及的系统还是比较重要的系统,投产窗口有限,肯定是需要更重视一些,于是答应处理完手边的这个问题紧接着下一个去看看这个系统;

但是,几分钟后电话再次响起:“老K,不好了,这个系统数据库重启了!快来看看吧!”这就尴尬了,难道是因为我没有及时响应他们的问题,系统就撑不住重启了?如果真是这样,那这罪过可就大了!赶紧去到事故现场来处理这个问题。

简单分析,简单结论

1明确情况

问题现场,各路同事都在讨论着这事。这个系统是一套两节点的RAC数据库,数据库版本为11g,这次重启实际上是数据库两个节点的实例都发生了重启;
首先看看alert日志里有没有什么信息显示:
微信图片_20171205115752.jpg

微信图片_20171205115752.jpg

很显然,数据库在19:41时被ASMB进程给终止了,在终止前产生了一些trace文件;ASMB进程是什么进程呢?顾名思义,ASMB进程就是数据库实例与ASM实例进行交互的进程,从这里的报错也可以到,ASMB已经无法连接到ASM实例了;

一般来说,出现这种情况,通常的可能是CRS发生了重启,然后这里我们通过ps –ef查看CRS关键进程发现并未发生过重启;这样看来与ASM有关;于是我们再看ASM的alert日志,关键部分如下:
微信图片_20171205115819.jpg

微信图片_20171205115819.jpg

可以看到ASM实例发生了重启,而重启的原因则是:
微信图片_20171205115841.png
微信图片_20171205115841.png

参数parallel_max_servers被设置为4505,而这个参数值是不合法的,该值的设定范围应该是0到3600之间;在发现了这个错误后CKPT进程终止了ASM实例。

似乎问题就很简单了,parallel_max_servers被置为4505,ASM实例终止,进而导致DB实例终止。那么,这里我们就需要搞清楚几个问题:

parallel_max_servers设置范围是0到3600,这是硬性规定吗?还是说是因为在设定某些值之后导致的?
参数设定错误通常报错即可,为何这里会导致ASM实例重启呢?
修改参数的操作来自于谁呢?与他们的应急操作是否有关系呢?

2分别突破

1) parallel_max_servers参数的限定
对于这种硬性设定,我们不妨先查一下官方手册,查看该参数是否有上限值:
微信图片_20171205115938.png

微信图片_20171205115938.png

可以看到,该值设定的上限就是3600;
2) 参数修改为什么导致ASM实例重启呢?
正常情况下,如果我们在数据库中的修改参数,修改失败直接抛错即可,显然并不会导致数据库实例的重启;
微信图片_20171205120014.jpg
微信图片_20171205120014.jpg

而这里发生的重启,我们可以看到导致重启的进程是CKPT进程:
微信图片_20171205120111.png
微信图片_20171205120111.png

我们可以认为,CKPT进程是数据库实例的关键进程,当它遇到错误时,它直接终止了整个实例;
3) 谁触发了ASM实例上参数的改变?

通常来说,修改(调大)parallel_max_servers参数的目的是允许系统启动更多的并行进程;而对于ASM实例来说,修改这个参数本身似乎并没有太大的意义,毕竟ASM实例都不会open,基本只服务于Database(可能还有一些监控/管理类的语句);那么谁会来修改ASM实例上的参数呢?难道是应急的时候错把ASM实例当做Database了?

看到这里,不妨思考一下?原因其实很简单….

3真相其实很简单

我们在来看看ASM的日志,相关的信息值得思考:
微信图片_20171205120158.jpg

微信图片_20171205120158.jpg

我们可以看到,在参数调整之前,日志中实例发现了CPU count变成了228,紧接着系统就调整了parallel_max_servers值的大小,随后报错宕实例;

这里我们首先需要确认,CPU数的调整会引起parallel_max_servers参数的调整吗?我们再来看看这个参数的相关属性,其默认值确实就是与CPU_COUNT有关的,而且参数本身就是可以动态调整的;
微信图片_20171205120222.jpg

微信图片_20171205120222.jpg

很显然,这里Oracle的代码中似乎在系统调整CPU进而导致parallel_max_servers参数的动态调整时,忘记了该考虑parallel_max_servers还有一个3600的上限,这应该定义为一个bug;我们上MOS核查也很快能找到这个bug:
微信图片_20171205120245.jpg
微信图片_20171205120245.jpg

微信图片_20171205120249.jpg
微信图片_20171205120249.jpg

问题发生在11.2.0.2和11.2.0.3的版本上,在11.2.0.4版本上已经修复;

如此真相
原来,在版本投产过程中应用维护团队发现相关任务的速度达不到预期时,他们就与相关系统负责人沟通,希望通过增加资源的方式来加快其任务的执行速度,于是系统负责人在请示领导后给系统动态增加了内存和CPU(使用的IBM小机,可以动态调整硬件资源),并准备在投产完成后再收回资源,然而在调整CPU的过程中,出现了上述错误,导致数据库重启,投产动作也受到影响!

4那些真相以外的真相

遇到了问题,要想怎么规避这样的问题,怎么样总结一套发现类似问题的方法,养成这样的良好习惯可以帮助我思考的更多更深;
——老K

①若干疑问
看着问题是得到了圆满的分析,然而还有不少疑惑萦绕在我的心头,也是客户所关注的,所以这里先来解答这些问题;

1.为什么Database实例没有因为parallel_max_servers的参数调整而直接重启呢?

这里我们可以再回过头来看database instance的alert日志信息:
微信图片_20171205120427.jpg

微信图片_20171205120427.jpg

同样也看到了CPUcount的变化,调整到了228;但是并没有出现parallel_max_servers参数的动态调整,其实这里主要的原因是,在Database实例中,我们已经在参数文件中指定了parallel_max_servers参数的大小了,在指定了参数的情况下,系统不再根据CPU数动态调整parallel_max_servers参数的大小;

2.为什么ASM实例启动时,没有再因为该参数而无法启动?

在ASM再次重启的时候是怎么计算parallel_max_servers参数值的呢?实际上我们搜索asm的alert日志发现启动实例是并没有设定parallel_max_servers参数;而我们手动设定asm的parallel_max_servers参数值也会报错:
微信图片_20171205120449.jpg

微信图片_20171205120449.jpg

我们发现,在ASM实例中压根就无法设置这个parallel_max_servers参数,哪怕是设定到spfile中也不允许;实际上在启动时不计算、不检查这个参数也就合乎情理了;

3.刚刚调整上去的CPU我再调回来还会宕机吗?

我们从原理上看,这里数据库并不关心CPU count是变大还是变小,一次是变十个还是变一个,它都会重新来计算parallel_max_servers参数的值,那么显然,这里如果再次调整CPU count,如果不是将CPU count调整到足够小,那么再次调整只要调整后的CPU count数计算parallel_max_servers参数的值大于3600,问题将再次出现!

4.如何预防这样的问题呢?

已经知道了这是bug,那么对应的打上相应的补丁一定是根本的解决之道;
而数据中心11.2.0.3版本的系统还非常多,而动态调整CPU也是常见动作,统一安装补丁也需要时间,同时还需要考虑时间窗口,肯定需要一定的周期;那么在此之前我们是否还有临时的预防之策呢?
根据bug文档描述的workaround是手动指定parallel_max_servers参数为小于3600的值,不过我们上面的核查能很明白的看到,ASM实例无法调整该参数,看来官方文档没有考虑ASM实例的情况,也有纰漏,那么我们该怎么办呢?
微信图片_20171205120513.jpg

微信图片_20171205120513.jpg

该如何是好呢?如果是你,你会考虑一些什么来规避这类问题呢?
② 更多思考,更多发现
要从根本上来回答上面的这些问题,其实需要了解数据库到底是如何计算parallel_max_servers参数的;实际上我们可以看看如下描述:
微信图片_20171205120655.png
微信图片_20171205120655.png

微信图片_20171205120659.png
微信图片_20171205120659.png

从上述描述我们可以看到影响参数的若干变量,包括:

PARALLEL_THREADS_PER_CPU:该参数基于操作系统,通常是2;

CPU_COUNT:该参数基于数据库的实际CPU数,但是可以调整;

concurrent_parallel_users:该参数基于实例的内存管理模式配置,默认系数为1/2/4不等;

PROCESSES:该参数值来实例启动时的PROCESSES参数;

可以看到,parallel_max_servers的参数值通过两方面的计算取min值,也就是取自min(parallel_threads_per_cpucpu_countconcurrent_parallel_users * 5,processes-15);这两个方面来看,其中一部分确实与CPU有关,而另一方面似乎只与processes有关,我们再查11.2的references:
微信图片_20171205120726.jpg

微信图片_20171205120726.jpg

processes参数的值默认是100;如果没有人调整过ASM实例的process参数的值的话,那么这里计算parallel_max_servers的值应该是min(PARALLEL_THREADS_PER_CPU CPU_COUNT concurrent_parallel_users * 5,100-15),这里即使前面计算的值再大,这里计算出来的值也只应该是85而已,也就远不会超过3600;

难道真的是又有谁修改了ASM实例的PROCESSES参数值吗?还是官方的reference是错误的呢?如果是你,你会怎么进一步核查这个参数呢?

③ 最后一部分真相
遇到这样的情况,我们首先检查并没有发现两个节点alert日志存在修改记录;那么难道reference真的有误?事实上我们看的是11.2的reference,当前的11.2.0.3版本发布时间在reference之后很久,我们不妨再通过MOS核查确认processes值默认值的计算方法:
微信图片_20171205122555.jpg

微信图片_20171205122555.jpg

在MOS文档“升级到11.2.0.3/11.2.04 Grid/ASM所需要知道的事”中指出,ASM的processes参数的默认值计算是“available CPU cores * 80 + 40”,当然,这里processes参数不会随着CPU数动态改变,只会在实例启动时计算;

我们截取之前时段AWR报告中拿到的CPU cores数:
微信图片_20171205122617.jpg

微信图片_20171205122617.jpg

那么这里,parallel_max_servers的值计算就是:
min(PARALLEL_THREADS_PER_CPUCPU_COUNTconcurrent_parallel_users5,last_CPU_cores80+40-15)
代入实际值即为:
min(222845, 5680+40-15)即 min(9120,4505)=4505>3600;
从这里也可以看出,在该系统即使调小CPU,如果不能调整到90个CPU,那么ASM将再次重启!
④ 应对之策

到这里,参数的计算来源算是一清二楚了;对于该问题的后续,我们给客户的应对之策包括:
后续针对所有11.2.0.3,打上对应的补丁,避免再次中招;
在补丁打上之前,在database实例确保手动设置parallel_max_servers为小于3600的值,在ASM实例设置processes值为小于3600的值;
如无必要,我们在没有充足理由调整系统CPU/内存的时候,不要轻易调整系统资源;

⑤ 真的需要调整CPU吗?

后续再了解整个情况后,我们再回过头看系统投产过程中所谓慢的情况,其实只是大量新插入记录的表未及时收集统计信息导致执行计划不够好而造成的执行缓慢;虽然当时CPU使用率相较之前确实偏高,但是在这种情况下,不通过收集统计信息,重新执行语句的情况下,通过增加CPU/内存这两种常用的应急手段实际上毫无帮助;在本次CASE中,增加CPU的动作反而造成了数据库宕机

我们遭遇了什么

我们再来回顾整个事情的前后,以及数据库本身的动作:
应用团队认为SQL执行缓慢,系统CPU使用率较高,建议扩容CPU/内存;
在没有及时分析问题根本原因的情况下,满足应用团队需求扩容系统CPU/内存,其中CPU数扩容到228;
数据库发现CPU扩容到228,Database 实例因为手动设置了parallel_max_servers参数,不再调整该参数;ASM实例没有设置parallel_max_servers参数,于是在代码中调整了parallel_max_servers参数;
调整的目标值是min(PARALLEL_THREADS_PER_CPUCPU_COUNTconcurrent_parallel_users5,last_CPU_cores80+40-15),即min(222845, 5680+40-15)即 min(9120,4505)=4505;
CKPT进程在设置该值之前,因为遭遇bug,未能校验4505值是否超过了parallel_max_servers的硬性上限值3600;
CKPT进程在设置parallel_max_servers值为4505时,遭遇错误ora-00068;CKPT作为系统关键进程,遇到无法完成的错误,终止ASM实例;
ASM实例终止后,Database 实例无法访问ASM,同时终止;
CRS发现Database 实例和ASM实例都终止,于是恢复ASM实例和Database实例;
在再次启动ASM实例时,不需要考虑parallel_max_servers参数,ASM实例正常启动,Database实例正常启动;整个重启完成。
从这里看,一个看似有益无害、多多益善的决定,让一套系统发生了重启,所以,应急需谨慎,最好做到对症下药,避免出现意想不到的结果。

风险提示

在数据库版本为11.2.0.2/11.2.0.3的情况下,对于数据库实例,建议手动设置parallel_max_servers参数,对于ASM实例,建议手动设置processes值为小于3600的值,避免出现CPU数量过高的情况下,动态调整CPU数造成的Database/ASM实例重启的情况。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

4

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广