案例:ORA-00600: internal error code, arguments: [4187]

本案例客户来自某省电信,alert日志大量的ORA-00600[4187]报错,已经影响到业务正常运行。

可以看到ORA-00600[4187]并伴随着blockrecover,通常ORA-00600[4XXX]错误都来自于undo相关,并且都会触发BRR,SMON已经遇到1次内部错误,如果smon遇到100次内部错误则会重启实例,由参数_smon_internal_errlimit控制。

ORA-00600 4187在Doc ID 19700135.8上有比较清楚的说明:

Description

大致意思是长期的高tps的环境,当在新的事务绑定到某个undo段某个slot上,将递增wrap#,但是递增后的wrap#超过最大值 KSQNMAXVAL(0xffffffff)。就会抛出ORA-00600[4187]错误。

继续查看trace文件查找报异常的undo段头

异常的undo段头的dump可以看到所有slot的wrap#都非常高,ktuxc中的chd为0009,说明下一次事务将使用slot 9的事务槽,而slot 9的wrap#为 0xfffffff3已经非常接近 KSQNMAXVAL ,但是我们知道每次wrap#重用只会加1,并不会超过 KSQNMAXVAL ,那么为什么会报出ORA-00600[4187]呢?

原因在于重用slot时wrap#+1的算法已经过时了,当前采用的是在执行ktubnd函数为事务绑定undo段时,会调用kjqghd去计算出一个重用slot递增值delta,这个delta也是有限制的,必须小于16(由KTU_MAX_KSQN_DELTA定义),所以就可能会出现 0xfffffff3 +delta的值超过KSQNMAXVAL 。

了解了错误原因,解决方法其实很简单,就是删除异常的undo段或者重建undo表空间,如果删除不掉undo段,比如还有其他活动事务那么可以用_corrupted_rollback_segments屏蔽掉该undo段。mos也提供了脚本去检查哪些undo段面临这样的问题。

这里还有一点需要思考的是,为什么会出现wrap#如此大?仅仅是高TPS吗?我们知道事务绑定UNDO段的原则是尽可能的将活动事务平均的各个undo段上,具体算法为:

  • 在当前undo tablespace中的online undo segment中寻找事务表中没有活动事务的undo segment
  • 如果没有找到则尝试在当前undo tablespace online 那些处于offline状态的undo segment
  • 如果没有找到则尝试在当前undo tablespace创建undo segment并online
  • 如果无法创建则会寻找最近最少使用的undo segment

有一种非常大的可能性就是可以online的undo段太少,经过查看该实例undo表空间大小为1.5g,且不可自动扩展,这才导致了undo事务表的各个slot的wrap#如此之高。

所以针对该case的补充建议是根据高峰期TPS,合理设置undo表空间大小以及_rollback_segment_count。

 

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

发表回复

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