eygle.com   eygle.com
eygle.com eygle
eygle.com  
 

« 结束IT168《循序渐进Oracle》技术交流会 | Blog首页 | 《循序渐进Oracle》在当当网上 »

497天是一个轮回-记Linux时钟的回转

前几天,同事告诉我一个发现,他说一台数据库的运行时间超过了操作系统的启动时间。
从数据库内部可以查询到数据库实例的启动时间:
SQL> COLUMN STARTED_AT format A25
SQL> COLUMN UPTIME format A50
SQL> SELECT TO_CHAR (startup_time, 'DD-MON-YYYY HH24:MI:SS') started_at,
  2            TRUNC (SYSDATE - (startup_time))
  3        || ' day(s), ' || TRUNC (  24 * ((SYSDATE - startup_time) -
  4        TRUNC (SYSDATE - startup_time)))
  5        || ' hour(s), '|| MOD (TRUNC (  1440 * (  (SYSDATE - startup_time) -
  6        TRUNC (SYSDATE - startup_time))),60)
  7        || ' minute(s), '|| MOD (TRUNC (  86400 * (  (SYSDATE - startup_time) -
  8        TRUNC (SYSDATE - startup_time))),60)
  9        || ' seconds' uptime
10  FROM v$instance;

STARTED_AT                UPTIME
------------------------- --------------------------------------------------
05-JUL-2005 10:36:58      803 day(s), 2 hour(s), 27 minute(s), 55 seconds

从这里看数据库实例启动了803天左右,也就是说自2005-07-05开始这个数据库一直在不间断的运行着。

而从操作系统的uptime来看,系统不过启动了306天:
SQL> ! uptime
13:06:21  up 306 days, 19:00,  1 user,  load average: 0.00, 0.00, 0.00

同事问我原因,首先我们检查alert文件,发现数据库的确是2005年启动的。
如果日志记录的是没有问题的,我当时猜测是否可能是由于系统时钟的更改,使得uptime的显示出现问题。

但是始终觉得这个解释并不充分,今天再研究一下,发现了问题本质。
和以前研究过的问题完全类似,这是又一次时间溢出的问题,
http://www.eygle.com/archives/2004/11/job_can_not_execute_auto.html
http://www.eygle.com/archives/2006/06/time_stop_again.html

由于某些Linux内核使用32位无符号长整型来计算时间,32位的最大值就是0xffffffff,再加1就将溢出变为0
以下一小段C代码可以解释这种溢出:
[root@jumper root]# cat a.c
int main(void){
unsigned int num = 0xffffffff;

printf("num is %d bits long\n", sizeof(num) * 8);
printf("num = 0x%x\n", num);
printf("num + 1 = 0x%x\n", num + 1);

return 0;
}
[root@jumper root]# gcc -o un a.c
[root@jumper root]# ./un
num is 32 bits long
num = 0xffffffff
num + 1 = 0x0

在我的这个Linux发行版本上,这个时间就此溢出:
SQL> ! uname -a
Linux moto 2.4.21-15.ELsmp #1 SMP Thu Apr 22 00:18:24 EDT 2004 i686 i686 i386 GNU/Linux

SQL> ! cat /etc/redhat-release
Red Hat Enterprise Linux AS release 3 (Taroon Update 2)

我们根据497天再来计算一下:
SQL> select 803 - 306 from dual;

  803-306
----------
      497
当前数据库的显示是正确的,803天减去uptime显示时间,得出的正好是497天。

这才是这次异常的本质所在。     
SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
PL/SQL Release 9.2.0.6.0 - Production
CORE    9.2.0.6.0      Production
TNS for Linux: Version 9.2.0.6.0 - Production
NLSRTL Version 9.2.0.6.0 - Production

-The End-

历史上的今天...
    >> 2012-09-17文章:
    >> 2010-09-17文章:
    >> 2009-09-17文章:
    >> 2008-09-17文章:
    >> 2006-09-17文章:

无觅

By eygle on 2007-09-17 12:59 | Comments (6) | Case | Internal | 1620 |

6 Comments

Eygle研究可真深

是不是忒复杂

这个linux还真稳定。

V$TIMERThis view lists the elapsed time in hundredths of seconds. Time is measured since the beginning of the epoch, which is operating system specific, and wraps around to 0 again whenever the value overflows four bytes (roughly 497 days).

to warehouse:
这个案例和v$timer没关系,v$timer的Bug在9.2.0.4之后就解决了。

这个是Linux的问题,后期的版本也已经修正了这个Bug。

这个linux还真是不错哦`


CopyRight © 2004~2020 云和恩墨,成就未来!, All rights reserved.
数据恢复·紧急救援·性能优化 云和恩墨 24x7 热线电话:400-600-8755 业务咨询:010-59007017-7040 or 7037 业务合作: marketing@enmotech.com