• 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个世纪!
  • 相关阅读:
    python 取整的两种方法
    django class-based view 考古
    django缓存基于类的视图
    MySQL参数优化案例
    django后台使用MySQL情况下的事务控制详解
    讲讲python“=”运算符上的优雅语法
    p标签不折行的问题
    django-TDD
    session 和 flask_session 实现原理(源码解析)
    网关地址和网关IP是什么,他们有什么关系?
  • 原文地址:https://www.cnblogs.com/macleanoracle/p/2968300.html
Copyright © 2020-2023  润新知