暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

原创 eygle 2007-09-16
602
前几天,同事告诉我一个发现,他说一台数据库的运行时间超过了操作系统的启动时间。

从数据库内部可以查询到数据库实例的启动时间:

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\
", sizeof(num) * 8);

printf("num = 0x%x\
", num);

printf("num + 1 = 0x%x\
", 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-
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论