delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

28 Aug 2010

RTC 与 NTP

早期版本的 FreeBSD 有一个问题是,如果使用 ntpd 来校准系统时钟的话,如果长期开机,则在重启之后,时间会差很远,之前一直没仔细研究这个问题。最近突然发现 FreeBSD 8.1-RELEASE 里面没有这个问题了,于是翻看了一下代码和之前的一些邮件才明白是怎么回事,总结一下:

一般来说操作系统在引导以后会自行维护时钟,简单地说,就是操作系统根据某个时钟源,例如单CPU系统中的TSC,或多CPU系统中比较常用的高精度事件计时器HPET等等,计算出时间的流逝并修改系统时间。只有在系统刚刚引导的时候,才会直接取 RTC 时间(在关机时,主板上的电池仍可维持 RTC 电路的计时功能)。

我们知道,任何测量工具都是有误差的,普通的 PC 系统上配置的计时装置肯定不会做的非常精密,这也是我们为什么要运行 ntpd 的主要原因。在系统运行的过程中,这些误差不断地积累,使用 ntpd 时,系统可以计算出所采用的时钟源与实际的时间之间的误差,并逐步调整时间源的计数周期与实际时间的比例,从而维持系统时钟的精确性。

在重启时,在内存中维护的系统时刻数据便随之丢弃了,操作系统再次启动时读取的是先前未经修正过的、继续在积累误差的 RTC 时间数据(注意:RTC是不依赖于OS运行的;OS可以修改其时刻数据,但无论开机还是关机,只要维持其需要的电流即可确保 RTC 继续自行更新,而无需 OS 干预)。

FreeBSD先前的实现中,只有非常少的地方调用了 resettodr(9) 来修正 RTC 时间,这些地方主要是settimeofday()之类的直接设置内核时刻数据的点,而对于 ntp 的情况,则没有相应的处理。

新的实现 (以r207360为主体,包含r207359, r207362)则增加了一个callout,每半小时将系统时钟刷回RTC一次,从而解决了这个问题。

关于为什么不应该使用 ntpdate 来对时(ntpdate会使用settimeofday()),请参考 A core这篇 介绍 NTP 的文章,以及我的 这篇 文章。


Archived: 5 Comments

Wenfeng CAI | September 5, 2010 2:10 AM

我只记得正常关机时好像会把系统时间写会到RTC

sk | September 14, 2010 7:38 AM

linux下有个刷新时间到cmos,不晓得freebsd下有没有这样类似的工具

我想同步了最新的时间后,让主板的cmos时间同步写入。下次启动的时候就是最新的了

Howard | October 2, 2010 3:19 AM

从前,有三个人,A跑得快,B和C跑得一样慢;

一天,上帝要求A和B同时到达某处。当A到达时,上帝发现B还在半路上,于是上帝用它的上帝之手帮了B一把。这事儿正好被C看见了,C看到了B的消失,而A看到了B的出现。

后来,因为这事儿,C成了电波系,而B开始信上帝了…

再后来,上帝还写了个软件叫ntpdate…

其实,在没有上帝的世界里,B会主动加速追上A的。

Marcus | October 31, 2010 6:26 PM

FreeBSD 8.1中若使用openntpd-4.6_1,2
好像没有“每半小时将系统时钟刷回RTC一次”的机制
重新启动计算机,就会出现系统时间和GMT标准时间相差甚远的可能。

之前我用拙劣的英语发邮件向FreeBSD中openntpd的维护者naddy@FreeBSD.org 和ports@freebsd.org
得到某人回复是Have you tried the -s flag?
-s Set the time immediately at startup.
Add this to /etc/rc.conf:
openntpd_flags="-s"
根据字面上的理解,-s参数仅仅相当于开机时候用了ntpdate同步远程ntp服务器时间
另外,拜读过https://blog.delphij.net/2007/03/asiabsdconopenb.html

有以下疑问,
FreeBSD 8.1 中openntpd-4.6_1,2的启动参数是openntpd_flags="-s"
若启动计算机后刚好网络不通,此时-s参数等于无效,RTC时间还是与GMT相差甚远
之后网络即使通了,系统时间要慢慢走几天才会与GMT同步,无法达到与FreeBSD 8.1中自带ntp的效果。


所以,能否请您促成openntpd在FreeBSD中也有类似“每半小时将系统时钟刷回RTC一次”的机制?

Xin LI | December 27, 2010 9:58 PM

我不太了解openntpd,头一次使用openntpd的时候它甚至不支持adjfreq(OpenBSD到2006年左右才开始支持这个功能),而且其作者在当时发表的很多对 NTP 的理解都是不对的,所以就放弃了。

FreeBSD的刷回机制和使用哪个ntp服务没有关系。不管你是不是用内置的 ntpd,它都会每半个小时回刷一次。

我个人认为你遇到的问题非常有可能是硬件故障,或是 CMOS 时区设置不对(例如没有将 CMOS 设置为 UTC 时间)。

关于启动时网络刚好不通的问题,如果硬件没有问题,其影响会非常有限(我用的硬件即使关机一天其偏差也不会超过正负两秒的范围,也就是说即使没有-s,开机一个半小时之内就可以追平)。个人不认为硬件故障不是软件应该解决的问题。