罕见故障!数据库对象编号达到最大值,必须重新建库!

简介:
引言
 
 

 

 

这个元旦不太平,刚刚发生了全球几百套MongoDB数据库数据被人删除,讨要比特币做赎金的事件,这就又发生了一件诡异、罕见的事。

 

你也许从来没想过,居然有一天,你的数据库会创建不了对象,是因为42亿个对象编号用到极限!而我居然真的遇到了!

 

故障现象
 
 

 

是的,甭论是要创建全局临时表,或者是序列,或者索引,都通通报错!

 

 

是的,甭说是你,就是全球,也没几个人遇到过,看看MOS文章就知道了:

 

 

唯一的一篇文章,告诉你遇到了一个bug,文章里对这个bug的简单描述是这样:

 

如果你遇到ORA-600 [kkdlron-max-objid]错误,说明新建对象的对象编号(Object ID)超过数据库限制了!从MOS文章和我们创建对象遇到的错误看,这个数据库限制的最大对象编号是4254950911!这个bug在某些操作系统平台的某些版本上是有补丁支持的,但是,但是,但是,重要的事情说三遍!这个所谓的补丁,也只不过是把这个数据库限制的最大编号增大了一点儿而已,让你好重建数据库,然后在逻辑导入所有表,这些表会重新获得新的对象编号。

 

那你肯定会关心,额滴神啊,我十几个TB的数据,逻辑导入是一个小工程啊,要申请停机时间啊,这要老命了!

 

这么个幺蛾子的情况,为什么偏偏就被我遇到了呢?

 

是的,这种情况极为少见,但不是不会发生,墨菲定律大家都懂的,莫非,莫非,莫非就偏偏碰见了你!

 

有大量分区表或索引,对象会很频繁drop然后又create的数据库系统,就容易中招了!

 

故障分析
 
 

 

首先来看看我们中招的数据库,数据库对象的最大编号是多少:

 

 

慢着!

 

报错信息说的啥?那个编号是4254950911,比当前数据库系统中最大编号大460567, 难道是每个数据库对象编号不是顺序来的,而是中间要隔40多万!

 

我们将数据库最新创建的对象按时间倒序排列,可以看到相连两个对象编号差别最大是1447773(WRH对象和SP对象),最小是1。这说明一个问题,对象创建时,编号还是顺序连续来的。

 

 

事实上,这个对象编号它就是一个数据库“序列”。(题外话,你有没有想过序列重置?思考下到底行还是不行?)

 

SQL> SELECT dataobj# FROM sys.obj$ where name='_NEXT_OBJECT';

DATAOBJ#

----------

4254950908

SQL> select max(object_id),max(DATA_OBJECT_ID) from dba_objects ;

MAX(OBJECT_ID) MAX(DATA_OBJECT_ID)

-------------- -------------------

4254909633 4254950794

 

从中我们可以看出,它申请的下一个序列值是4254950908,与创建对象报错的值4254950911仅仅只相差3而已。说明我们数据库中目前还存在的最大对象编号之后,还是创建过几十万次对象的。

 

那接下来我们看看最近几天创建的数据库对象,每天的最大ID是多大呢,也就是说数据库编号每天增幅大概多少?

 

 

我们可以看到,最近10天,每天数据库对象编号增长,最小是202万,最大是459万。

 

 

这个数据库是2013年创建的。

 

如果按照每日最大增幅算,4年时间最大的对象编号应该是:

 

4*365*4591144=6703070240

 

如果按照上图显示的最小增幅算,最大的对象编号应该是:

 

4*365*2028717=2961926820

 

而当前最大数据库对象编号是4254490344,在这两个数之间。也就是说,一句话,每天的数据库对象编号增幅达百万级。啥意思?每天有百万次创建数据库对象的命令?按每天最大增量算,平均每秒钟要执行53次创建命令。

 

4591144/24/60/60=53.13824074

 

这显然不太可能!

 

进一步研究看看,做一把日志挖掘?

 

 

考虑到数据日志产生量太大,没有启用归档模式。

 

所以,无法查询到真实的DDL语句执行情况,也无从较真了。

 

但是,长远来看,从应用层降低数据库对象的drop/create频率是必须的,从数据库维护层监控对象编号也是必须的。

 

解决方案
 
 

 

从短期来看,是否具有临时解决方案(参数、或者补丁,因为应用侧到此已经彻底死掉了)可以绕过这个问题。

 

没有参数,也没有灵丹妙药,但是看起来补丁还不少:

 

 

不过,当前这个数据库版本11.2.0.3支持的平台很少,只有Oracle自家的才被支持:

 

 

而故障数据库的平台不在此列。也就是说,苟延残喘的机会也破灭了!

 

撸起袖子干吧!建新库,逻辑导出,逻辑导入(impdp)!十几个TB的数据要耗时多久呢?

 

原理解释
 
 

 

解释一下,Oracle支持的最大对象编号是多少?

 

下面这段内容来自伟翔同学:

 

“从Oracle 8开始ROWID改成由data_object_id#、 rfile#、 block# 、row#组成,它使用Base64位编码的18个字符显示,其实rowid的存储方式是:10 个字节即80位存储,其中数据对象编号需要32 位,相关文件编号需要10 位,块编号需要22,位行编号需要16 位,由此,我们可以得出,32位的对象编号,支持的最大编号为:”

 

 

报错显示的值是4254950911,与理论最大值相差4000万,也就是说,如果打了补丁,按照这个增速,也就是可以再蹦跶10天而已。

 

事后规避
 
 

 

那怎么办呢?

 

我们对于危机的恐惧不在于到底有多艰难,而在于危机发生的不确定性。

 

所以,通过我们的苦难,写这篇文章,给你们大家一个预警。

 

增加一个监控告警,最高级别,每天最大对象编号增长超过10万,就告警。

 

做运维就是这样,经验和能力是通过一个又一个苦难堆积出来的。

 

数据库运维哪家强?比拼的是团队十年如一日的运维经验总结积累。

 

运维靠的不是花裙秀腿,运维靠的是简单实用,一招制敌!

 

介绍下几个我们常用的数据库配置、检查的建议项,你一定用得着(每项都至少发生过一次生产上血淋淋的故障,但我们相信你可能只做了一两个):

 

  • Oracle RAC环境,禁用DRM;

  • Oracle RAC环境,所有应用sequence缓存默认设置为500(特殊的可以更高,或者是0);

  • 所有数据库,AUDSESS$这个sequence缓存设置为1000;

  • 新应用上线,禁止使用DB Link;

  • 所有新数据库安装,必须部署OSW(RAC库开启PRVNET);

  • 一个表空间最多不要超过1000个数据文件;

  • ……今天是不是应该增加一条应用每天新增的数据库对象不超过10000个??这个数据库总的数据库对象也才20000个哦~

 

关于运维变更和监控的几点规范:

 

关于涉及应用的变更(创建、删除、修改数据库对象结构,新增SQL语句),必须提前2天提交,SQL审核(可以通过人工,我们也做了自动的Oracle SQL审核工具)通过后允许上线,否则必须经过一定级别领导的特批。

 

关于系统级的普通变更,不允许生产时间执行。

 

关于数据库的监控,相信你可能已经设置了不少,每天都烦不胜烦了。但是以下这些,如果你还没有部署,建议尽快实施:

 

  • SCN天花板监控

  • Sequence最大值监控

  • ……

  • 以及我们今天学到的,对象最大编号增量监控

 

如果说大型系统的开发人员无法保证自己不编写有bug的代码,那么专业的运维人员同样无法保证自己不遇到故障(不要奇怪,比如HPUX平台cp命令都是可能引发故障的,比如密集的ping命令也是,等等)。差别只在于专业的运维团队踩过足够多的坑之后,可以帮助后来者规避掉这些坑而已,就像柯洁比聂卫平更年轻成为围棋第一人这样。至于Master轻松战胜柯洁,那是另一个玩法,很重要,也是运维人的新目标。

 

如果你还有补充,欢迎文末评论留言,让还没有Master帮助的更多运维兄弟不走你走过的坑!

 

故障手工重现
 
 

 

看到这里,是不是觉得还是有点意犹未尽?我们也一样,所以我们自己做了些测试。

 

基于12cR1的环境,我们直接把数据库对象的最大编号修改了(声明:我们只是测试,不要在生产上干!干了出问题你自己负责!)。

 

命令:

update obj$ set dataobj#=4254950905where name='_NEXT_OBJECT';

 

然后往数据库里面再创建几个新表,立马就故障重现了。

 

 

相同的ORA-600错误。

 

在这个版本,Oracle是提供了补丁的,赶紧下载下来,打上去。

 

 

再看看,是不是突破限制了。

 

 

非常好, 至少是可以苟延残喘了嘛!

 

我们再看看OBJECT_ID最大可以到多少。

 

 

结论:不打补丁只能4254950910 ,打了补丁可以到4293950910,这个是最大能到的OBJECT_ID了,虽然你的数据库可能永远也用不到这个数。 

 

数据库重建后的跟踪分析
 
 

 

比较幸运的是,发生故障的数据库是一个与历史数据关系不紧密的数据库。所以很快在新的环境里搭建了同版本的数据库,导入对象逻辑结构后,业务就恢复了。

 

导入:

  1. 先做逻辑结构的导入;

  2. 再做数据的导入。

 

使用impdp+network方式,差不多每小时100GB的样子。根据表类型分成不同的通道可以节省一些总时间。

 

新环境的OBJECT_ID变化分析:

 

 

我们可以看到,四天增长了接近18万,平均每天4万左右。

 

图中没有显示得特别好的是,每天的Data_Object_id比Object_id要快,但是新的Object_ID是基于Max(Data_object_id)的。

 

从这里可以简单看出,虽然新库的OBJECT_ID没有像老库临死前几天那样每天几百万的增量,但每天几万仍然是一个不小的数字了。

 

这从另一个侧面来说,频繁Truncate或Drop/Create 表是这类故障发起的诱因,尽管确实罕见。

 

关于神奇的4254950911
 
 

 

这个神奇的数字,我们从MOS文章ID 76746.1:SCRIPT: ForBug:970640 to check if Target Database has been corrupted文章中找到一些信息:

 

LIMIT number:=2147483648; /* Highest sensible object id */

MAXOBJ number:=4294950911;/* Max ever object id */

next_id number;              /* Current NEXT object_id*/

high_id number;             /*Current Highest object_id */

best_id number;             /*Current Highest Object_id below LIMIT */

badcnt number:=0;           /*Number of objects with ID above LIMIT */

dups boolean:=false;        /*True if duplicate dataobj# */

 

*/

 

原文发布时间为:2017-01-18

本文来自云栖社区合作伙伴DBAplus

相关文章
|
1月前
|
SQL 关系型数据库 数据库
【YashanDB知识库】OM仲裁节点故障后手工切换方案和yasom仲裁重新部署后重新纳管数据库集群方案
本文介绍了主备数据库集群的部署、OM仲裁故障切换及重新纳管的全过程。首先通过解压软件包并调整安装参数完成数据库集群部署,接着说明了在OM仲裁故障时的手动切换方案,包括关闭自动切换开关、登录备节点执行切换命令。最后详细描述了搭建新的yasom仲裁节点以重新纳管数据库集群的步骤,如生成配置文件、初始化进程、执行托管命令等,确保新旧系统无缝衔接,保障数据服务稳定性。
|
27天前
|
存储 SQL 数据库
【赵渝强老师】达梦数据库的数据库对象
达梦数据库包含基本与复杂两大类数据库对象。基本对象如表、索引、视图、序列和同义词,通过单一DDL语句创建和管理。表是数据存储核心,支持多种数据类型;索引提升查询速度,常见类型包括聚集、唯一、函数等索引;视图提供虚表功能;序列生成有序整数;同义词简化对象访问。复杂对象包括存储过程、函数和触发器,需用DMSQL语言开发,适用于更复杂的业务逻辑处理。文中通过实例详细介绍了各类对象的创建与使用方法。
|
1月前
|
数据库
|
2月前
|
SQL 关系型数据库 数据库
【YashanDB 知识库】OM 仲裁节点故障后手工切换方案和 yasom 仲裁重新部署后重新纳管数据库集群方案
本文介绍了一主一备数据库集群的部署步骤。首先在OM节点上传并解压软件包至指定路径,随后通过调整安装参数、执行安装和集群部署完成数据库设置。接着,在主备节点分别配置环境变量,并查看数据库状态以确认安装成功。最后,针对OM仲裁故障提供了手动切换方案,包括构造故障场景、关闭自动切换开关及使用SQL命令进行主备切换,确保系统高可用性。
|
4月前
|
存储 Oracle 关系型数据库
数据库数据恢复—ORACLE常见故障的数据恢复方案
Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。
230 11
|
5月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
6月前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
6月前
|
存储 关系型数据库 MySQL
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
156 2
|
7月前
|
存储 数据挖掘 数据库
服务器数据恢复—raid磁盘故障导致数据库数据损坏的数据恢复案例
存储中有一组由3块SAS硬盘组建的raid。上层win server操作系统层面划分了3个分区,数据库存放在D分区,备份存放在E分区。 RAID中一块硬盘的指示灯亮红色,D分区无法识别;E分区可识别,但是拷贝文件报错。管理员重启服务器,导致离线的硬盘上线开始同步数据,同步还没有完成就直接强制关机了,之后就没有动过服务器。
|
7月前
|
SQL 关系型数据库 数据库连接
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别
本文介绍了PHP中PDO(PHP Data Objects)扩展的基本概念和使用方法。内容包括PDO类和PDOStatement类的介绍,PDO的简单使用,预定义占位符的使用方法,以及PDOStatement对象的使用。文章还讨论了绑定预定义占位符参数的不同形式,即bindValue和bindParam的区别。通过具体示例,展示了如何使用PDO进行数据库连接、数据查询、数据插入等操作。
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别

热门文章

最新文章