最近一阵关于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的最根本目的在于:
- 为读一致性所用
- 为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.askmac.cn 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.askmac.cn (((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.askmac.cn 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个世纪!
精彩!
昨天在itpub首页看见盖老师谈SCN消尽的问题,哈哈,今天就看见Mac更加细腻,耐人寻味的大作!
Oracle数据库可运行的仅能运行的时间区间 1988-2121年,这也应该算是一种soft limit。
太精彩了:)。
实施2012 Apr发布的最新psu和scn相关补丁,建议详细测试。
数据库是否有scn产生率过快,也可使用948272.1文档查看calls to kcmgas项,并联系oracle support.
不错!
How to extract the historical values of a statistic from AWR Repository [ID 948272.1] 提供了一个有效的脚本检查 calls to kcmgas统计值, 可以作为scn快速增长的证据!
Cached Commit SCN referenced 128 Useful only for internal debugging purposes
calls to get snapshot scn: kcmgss 32 Number of times a snapshot system change number (SCN) was allocated. The SCN is allocated at the start of a transaction.
calls to kcmgas 128 Number of calls to routine kcmgas to get a new SCN
calls to kcmgcs 128 Number of calls to routine kcmgcs to get a current SCN
calls to kcmgrs 128 Number of calls to routine kcsgrs to get a recent SCN
老熊这篇http://www.laoxiong.net/scn-ora-19706-_external_scn_rejection_threshold_hours-parameter.html 说非常清楚。
哥,你的文章格式可以调整下不?
我客户的数据库还没有安装补丁,我用这个脚本scnhealthcheck.sql检查结果是:
Current Date: 2012/10/08 14:30:19
Current SCN: 13028746153222
Version: 10.2.0.4.0
————————————————————–
Result: C – SCN Headroom is low
If you have not already done so apply
the latest recommended patches right now
, set _external_scn_rejection_threshold_hours=24 after apply
AND contact Oracle support immediately.
For further information review MOS document id 1393363.1
————————————————————–
结果为c,是不是该尽快打补丁了?
我想问一下,我这个检查结果的数据库是10.2.0.4的,那9i的数据库怎么办呢?因为9i有使用db_link,9i升级不太现实,能不能有什么不升级的办法?
建议你把所有与该9i存在DBLINK可能的10g库升级到必要的SCN HEADROOM PSU, 同时尽可能减少9i与10g间的DBLINK操作。
哦 good idea,我怎么没有想到,哈哈。谢谢,我去实施了。
Q1) you’d better patch latest PSU like 10.2.0.5.12, especially those database involved in dblink net. Q2) This parameter controls an SCN threshold below the “Maximum Reasonable SCN” above which the database willreject SCN adjustments, such as those due to attempts to connect to or from a remote database over a databaselink. The default value depends on the version.This may be best illustrated by example. Assume the threshold is set to 10 days = 10*24 hours = 240. If thisdatabase tries to connect to a remote database that has an SCN higher than the local database SCN thennormally the local SCN would “jump” up to match the remote SCN. However if that jump would make the currentheadroom value less than 10 days the connect attempt will fail with an ORA-19706. (a headroom of 10 daysbeing an SCN within 10*24*60*60*SCN Rate SCNs of the current “Maximum Reasonable SCN”).11.1 , 10.2 and 10.1 customers are advised to set the parameter value to 24 (1 day) rather than keeping thedefault (unless a different value has been advised by support).Q4) scn headroom problem is terrible , you’d better monitor the scn headroom by script scnhealthcheck.sql , but also calls to kcmgas