了解Maclean Liu|向Maclean Liu提问 Oracle ALLSTARS 全明星(群内有多位Oracle高级售后support,N位OCM和ACE) QQ群 # QQ群号:23549328 # 已经升级到 2000人群,空位多多。欢迎有一定基础的Oracle骨友加入,现在入群需要经过Maclean的技术面试,欢迎面试,请加QQ号:47079569 为好友参加面试 2群基础群 适合刚入门的同学,会共享最佳入门实践和资料 QQ群 # QQ群号:171092051 # 已经升级到 500人的超级群,空位多多,无需面试

SCN Headroom与时光倒流到1988年的Oracle数据库

最近一阵关于scn headroom的讨论很热,  这是由于在最新的2012 Apr的PSU中例如10.2.0.5上的PSU 13632743和 patch  13916709: SCN: HIGH CALLS TO KCMGAS AFTER APPLYING SCN PATCHES 中引入了对scn增长过快的FIX修复。 Oracle SCN(System Change Number)也叫做系统变更号,Oracle中的Commit操作与SCN紧密相关。 引入SCN的最根本目的在于:
  1. 为读一致性所用
  2. 为redolog中的记录排序,以及恢复
    SCN由SCN Base和Scn Wrap组成,是一种6个字节的结构(structure)。其中SCN Base占用4个字节,而SCN wrap占用2个字节。但在实际存储时SCN-like的stucture常会占用8个字节。  
ub4 kscnbas
ub2 kscnwrp

struct kcvfhcrs, 8 bytes                 @100                              Creation Checkpointed at scn
ub4 kscnbas                        @100      0x000a8849              www.oracledatabase12g.com
ub2 kscnwrp                        @104      0x0000
    当事务提交COMMIT时,需要完成第一个操作就是得到一个SCN值。   SCN是Oracle数据库内部的一种逻辑时间戳,通过SCN将数据库内的事件理清次序, 这是保证事务属性ACID的必要信息。   数据库使用SCN来帮助实现查询和跟踪变化。举例来说,当一个事务更新一行数据,那么数据库就需要将该update发生时的SCN记录下来,该事务(transaction)中的其他修改操作通常都会使用同样的SCN。当一个事务commit提交,数据库又会相应地记录提交时的SCN。 多个事务同事commit可能会共享同一个SCN。   SCN总是单调递增的序列, Oracle数据库最大可以使用到的SCN上限值是一个天文数字,目前该上限是281万亿,即281,474,976,710,656(2的48次方)。这是对SCN的硬限制,理论上一个数据库的SCN总是不能超过281万亿, 以每秒16K的增速计算,花费557年SCN上限才会被耗尽,作为一个hard limit ,我们很少有机会触及。   除了281万亿的hard limit外, Oracle数据库还存在一种 soft limit 即SCN headroom, 为了保证SCN的增长速度不要过于离谱,Oracle使用了一种基于时间的限量供应SCN的系统。   关于headroom ,字典翻译头上空间, 实际你可以理解为 在一个房间内 天花板和 头部之间的空间, 数据库的Current SCN就是你头部的高度,那么(房间高度-头部高度)=headroom, 在任何时间点上,Oracle数据库均会计算一个当前时间点DB 不能超过的SCN LIMIT上限, 注意这里提到了时间点 ,通俗点说这个SCN LIMIT是随着时间流逝在增加的。 Oracle计算的算法基于从1988年到当前时间点的秒数,再乘上16,384(16k),用SQL表达就如以下语句:    
select
(((to_number(to_char(sysdate,'YYYY'))-1988)*12*31*24*60*60) +
((to_number(to_char(sysdate,'MM'))-1)*31*24*60*60) +
--www.oracledatabase12g.com
(((to_number(to_char(sysdate,'DD'))-1))*24*60*60) +
(to_number(to_char(sysdate,'HH24'))*60*60) +
(to_number(to_char(sysdate,'MI'))*60) +
(to_number(to_char(sysdate,'SS'))))*16384 from dual;
      变化下公式就是    (current_time-1988)       *    16384 - (current_scn) = headroom。 1988到当前时间的秒数   *    16384 -  当前SCN 即SCN headroom是 当前SCN 和(1988年到当前时间的秒数*    16384)之间的差距。   通过将SCN的增长率和时间流逝关联起来,确保SCN的限量增长,保证Oracle数据库理论上可以处理500年的数据。     通过以上公式我们可以发现SCN每秒的合理增长量为16,384,然而Oracle公司在近年发现某些软件层面的BUG会导致数据库试图超过或接近这个当前时间点的SCN 最大值。 常规情况下,若数据库尝试超过当前的SCN最大值,数据库将会cancel取消掉引发该超越事件的事务, 在应用程序层面将看到一个错误。在接下来的一秒钟,上限值会随着时间而增长16k,因此通常应用程序会在短暂停顿后继续工作。 但是在极少数情况下,数据库可能需要为了保护自身的完整性而shutdown关闭,理论上不会造成数据丢失或corrupted。   类似于计算机网络中的时钟同步,当2个数据库通过DBLINK相互交流访问时,他们会选用2者中当前Current SCN最大的一个来同步SCN, 譬如说数据库A 的SCN 是10000,而数据库B是20000,当2者发生DBLINK联系时,将会用最大的SCN (20000)来同步,数据库A的SCN将jump跳跃到20000。 在一些环境中,往往不是本地数据库触发了SCN快速增长的bug,而是众多数据库中的某一个存在活跃的SCN BUG,而其他数据库与该问题数据库发生DBLINK联系后,就会因为SCN同步而经历 SCN headroom的的极速减少; 换句话说就是一只老鼠坏了一锅汤,异常高的SCN会通过DBLINK传播给正常的数据库,这种传播往往呈爆炸式发展。 由于数据库总是会拒绝SCN超过当前的SCN上限,所以Oracle官方宣称Oracle数据库理论运行500年的SCN预备量不会受以上问题的影响。 但是受到传播的数据库仍可能由于自我保护的原因而宕机。   Oracle官方宣布所有与SCN headroom相关的bug均已在January 2012 CPU 和相关的PSU中修复了, 同样的修复补丁也被包含在DB Patchset Update (PSU) 以及最新的Exadata和Windows的Bundle Patch上。     有一些客户纠结于他们的SCN接近于当前SCN最大值,且SCN的增长量远大于他们处理数据库的合理值。在所有这些cases中Oracle 发现均是January 2012 CPU 中已经修复bug的现象,在客户实施这些修复后SCN headroom 开始有效增长了。   为了保证系统不出现潜在的问题,用户可以运行Metalink Note"Installing, Executing and Interpreting output from the "scnhealthcheck.sql" script [ID 1393363.1]"中包含的脚本scnhealthcheck.sql来检查特定数据库的当前SCN距离当前SCN 最大值有多少差距。该脚本会警告用户该数据库接近于当前SCN的最大上限,在这种情况下建议立即对受影响数据库实施CPU/PSU补丁。实施以上补丁后的预期结果是SCN headroom有效增长,官方宣称在所有case中都如预期一样。   Oracle推荐尽可能客户尽可能快地APPLY CPU补丁以处理最新发现的安全问题。   从长远来看Oracle会在今后的版本或补丁中将SCN的hard limit从281万亿 提高到一个更高数字。   你肯定好奇于为什么这里要使用 1988年到当前时间的秒数,1988这个年份有什么意义?     我们来看看Oracle数据库中的1988:  
[oracle@vrh8 ~]$ strings $ORACLE_HOME/bin/oracle > oracle.log
[oracle@vrh8 ~]$ grep 1988  oracle.log
1988
xsaggr.c:1988
Version: %d {0 = 1988 }

SQL>
SQL> select  * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE    10.2.0.5.0      Production
TNS for Linux: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production

SQL> select * from global_name;

GLOBAL_NAME
--------------------------------------------------------------------------------
www.oracledatabase12g.com

SQL> oradebug setmypid;
Statement processed.
SQL> oradebug dump controlf 4
Statement processed.
SQL> oradebug tracefile_name;
/s01/admin/G10R25/udump/g10r25_ora_9823.trc

THREAD #1 - status:0x2 flags:0x0 dirty:252
low cache rba:(0xe.7742.0) on disk rba:(0xe.7b44.0)
on disk scn: 0x0000.002d4ac2 06/03/2012 10:03:34
resetlogs scn: 0x0000.00294b33 05/22/2012 11:33:28
heartbeat: 784994177 mount id: 2670678794
THREAD #2 - status:0x0 flags:0x0 dirty:0
low cache rba:(0x0.0.0) on disk rba:(0x0.0.0)
on disk scn: 0x0000.00000000 01/01/1988 00:00:00
resetlogs scn: 0x0000.00000000 01/01/1988 00:00:00
heartbeat: 0 mount id: 0
THREAD #3 - status:0x0 flags:0x0 dirty:0
low cache rba:(0x0.0.0) on disk rba:(0x0.0.0)
on disk scn: 0x0000.00000000 01/01/1988 00:00:00
resetlogs scn: 0x0000.00000000 01/01/1988 00:00:00
heartbeat: 0 mount id: 0
THREAD #4 - status:0x0 flags:0x0 dirty:0
low cache rba:(0x0.0.0) on disk rba:(0x0.0.0)
on disk scn: 0x0000.00000000 01/01/1988 00:00:00
resetlogs scn: 0x0000.00000000 01/01/1988 00:00:00
heartbeat: 0 mount id: 0
THREAD #5 - status:0x0 flags:0x0 dirty:0
low cache rba:(0x0.0.0) on disk rba:(0x0.0.0)
on disk scn: 0x0000.00000000 01/01/1988 00:00:00
resetlogs scn: 0x0000.00000000 01/01/1988 00:00:00
heartbeat: 0 mount id: 0
THREAD #6 - status:0x0 flags:0x0 dirty:0
low cache rba:(0x0.0.0) on disk rba:(0x0.0.0)
on disk scn: 0x0000.00000000 01/01/1988 00:00:00
resetlogs scn: 0x0000.00000000 01/01/1988 00:00:00

***************************************************************************
DATA FILE RECORDS
***************************************************************************
(size = 428, compat size = 428, section max = 100, section in-use = 8,
last-recid= 421, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 11, numrecs = 100)
DATA FILE #1:
(name #10) /s01/oradata/G10R25/datafile/o1_mf_system_7ch7d4mn_.dbf
creation size=0 block size=8192 status=0xe head=10 tail=10 dup=1
tablespace 0, index=1 krfil=1 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:418 scn: 0x0000.002d2072 06/03/2012 03:41:16
Stop scn: 0xffff.ffffffff 05/24/2012 09:51:21
Creation Checkpointed at scn:  0x0000.00000007 04/20/2010 08:24:26
  1988年为什么如此重要?   在1988年发布了Oracle V6,首次实现了行级锁定,首次实现了数据库热备份,Oracle公司从Belmont移到加利福尼亚的redwood  shores,并引入了PL/SQL。   我相信目前使用版本7-11g  仍沿用了大量的V6的代码,V6的代码中做了大量DEFINE的工作,这大概是一切的开始。 这就好像是"And God said, Let there be light"!     Technical Data and Computer Software (October 1988) 这个所有权著名,你可以在很多Oracle的早起文档上找到。   你肯定又要问 , 我们可以在1988年之前运行Oracle V6以后的程序吗? 假设我们获得了时光机,拿着Oracle 10.2.0.5回到1988年前  
[root@vrh8 ~]# date -s "1985-07-25 00:00:00"
Thu Jul 25 00:00:00 EDT 1985

SQL> startup;
ORA-01513: invalid current time returned by operating system

[oracle@vrh8 ~]$ strace -o startup.log  -p 9935
Process 9935 attached - interrupt to quit

SQL> startup;
ORA-01513: invalid current time returned by operating system

[oracle@vrh8 ~]$ oerr ora 01513
01513, 00000, "invalid current time returned by operating system"
// *Cause:  The operating system returned a time that was not between
//          1988 and 2121.
// *Action: Correct the time kept by the operating system.
    可以看到 Oracle数据库可运行的时间区间其实是 1988-2121年,500年的SCN headroom其实没什么用处, 没有哪个凡人或者DBA等得起5个世纪!

posted on 2013-03-19 00:51  Oracle和MySQL  阅读(394)  评论(0编辑  收藏  举报

导航