再談時間同步

黃志斌發表於2015-10-22

上一篇文章裡,我談到在 Linux 中至少有以下兩種方法進行時間同步:

  1. Network Time Protocol daemon
  2. systemd-timesyncd

根據有關文件資料,第 1 種方法每隔 11 分鐘同步一次。第 2 種方法是我推薦使用的,但它要多久同步一次呢?

使用 man systemd-timesyncd 命令檢視相關文件:

從上述文件中可以看出,systemd-timesyncd 在每次時間同步後,都會更新 /var/lib/systemd/clock 檔案。

$ ll /var/lib/systemd/clock
-rw-r--r-- 1 systemd-timesync systemd-timesync 0 10月 21 08:27 /var/lib/systemd/clock

嗯,上次時間同步是在 08:27,那麼下次在什麼時候同步呢?讓我們寫個 C# 程式來探查一下吧:

using System;
using System.IO;
using System.Threading;

sealed class TimesyncdMonitor
{
  static void Main()
  {
    var t0 = DateTime.MinValue;
    var watcher = new FileSystemWatcher("/var/lib/systemd", "clock");
    watcher.Changed += (_, e) => {
      var t1 = DateTime.Now; if (t0 == DateTime.MinValue) t0 = t1;
      Console.WriteLine("{0:dd HH:mm:ss}: {1,8:F3}",
        t1, (t1 - t0).TotalSeconds); t0 = t1; };
    watcher.EnableRaisingEvents = true;
    Thread.Sleep(Timeout.Infinite);
  }
}

簡要說明:

  • FileSystemWatcher 類監視指定目錄中特定檔案的變化。
  • 當監視物件發生變化時,引發 Changed 事件。所以我們為該事件註冊一個回撥函式(lambda),顯示本次事件發生時間以及與上次事件的間隔。
  • 設定 EnableRaisingEvents 屬性為 true,開始進行監視。
  • 最後,呼叫 Thread 類的 Sleep 方法進入永久睡眠,等待事件發生。

注意,最後一條語句也可以用以下語句代替:

Console.ReadLine();

但是不要使用以下語句:

while (true) ;

這個程式的執行結果如下:

$ dmcs timesyncdmonitor.cs && mono timesyncdmonitor.exe

21 08:28:41:    0.000
21 08:30:49:  128.514
21 08:32:26:   96.449
21 08:32:58:   32.252
21 08:34:34:   96.499
21 08:38:29:  235.005
21 08:40:38:  128.252
21 08:44:54:  256.248
21 08:53:26:  512.251
21 09:10:30: 1024.251
21 09:44:39: 2048.245
21 10:18:47: 2048.249
21 10:52:55: 2048.250
21 11:27:03: 2048.250
21 12:01:12: 2048.255
21 12:35:20: 2048.298
21 13:09:28: 2048.245
21 13:43:36: 2048.210
21 14:17:45: 2048.249
21 14:51:53: 2048.249
21 15:26:01: 2048.252
21 16:00:09: 2048.261
21 16:34:18: 2048.239
21 17:08:26: 2048.250
^C

這樣看來,systemd-timesyncd 應該是每隔 2048 秒(大約 34 分鐘)同步一次。不過小數點後面的零頭是什麼意思?系統時鐘與實際的物理時鐘的誤差?

哦,這個程式是我剛重啟完電腦後立即執行的,前幾行輸出我猜應該是 systemd-timesyncd 在測試和選擇合適的 NTP 伺服器。

參考資料

  1. MSDN: FileSystemWatcher Class (System.IO)
  2. MSDN: Tread.Sleep Method (Int32) (System.Threading)

相關文章