再見 NTP,是時候擁抱下一代時間同步服務 Chrony 了

Chrony 是一個多功能的 NTP (Network Time Protocol) 實現,類 Unix 系統上 NTP 客戶端和服務器的替代品。它可以通過 NTP 服務或者類似 GPS 時鐘接收器的硬件級參考時鐘來同步系統時鐘,具有更好的時鐘準確度,並且對於那些間歇性互聯網連接的系統很有幫助。Chrony 是免費開源的,並且支持 GNU/LinuxBSD 衍生版(比如:FreeBSDNetBSD)、macOSSolaris 等。

Chrony 有兩個核心組件:一個是 chronyd 守護進程,主要用於調整內核中運行的系統時間和時間服務器同步。它確定計算機增減時間的比率,並對此進行調整補償。另一個是 chronyc,它提供一個用戶界面,用於監控性能並進行多樣化的配置。chronyc 可以在 chronyd 實例控制的計算機上工作,也可以在一台不同的遠程計算機上工作。

Chrony 和 NTPD 精度對比測試

我們可以從 Chrony 的官方網站上可以看到與 NTPD 各維度詳細對比:

從其測試結果上看似乎是各維度性能都可以吊打 NTPD。因此 Chrony 對自身的整體評價還是比較高的。

Chrony 相較於 NTPD 服務的優勢

  1. 更快的同步只需要數分鐘而非數小時時間,從而最大程度的減少時間和頻率誤差,這對於並非全天運行的台式計算機或系統而言非常有用。
  2. 能夠更好的響應時間頻率的快速變化,這對於具備不穩定時鐘的虛擬機或導致時鐘頻率反覆變化的節能技術而言非常有用。
  3. 在初始同步後,它並不會停止時鐘,以防對需要系統時間保持單調的程序造成影響。
  4. 在應對臨時非對稱延遲時,(例如:大規模下載造成連接飽和時)提供了更好的穩定性。
  5. 無需對服務器進行定期輪詢,因此具備間歇性網絡連接的系統仍然可以快速同步時鐘。

安裝

Centos 7.x 開始的最小發行版中都已經預裝並開啟了 Chrony。如果你的系統上沒有安裝 Chrony,你也可以使用下面的命令輕鬆安裝它。

$ yum -y install chrony    # [On CentOS/RHEL]$ apt install chrony       # [On Debian/Ubuntu]$ dnf -y install chrony    # [On Fedora 22+]

安裝完成後,你可以使用以下命令來檢查 chronyd 的狀態。

$ systemctl status chronyd     # [On SystemD]$ /etc/init.d/chronyd status   # [On Init]

如果要在開機引導時自動啟用 Chrony 的守護程序,你可以使用以下命令來實現。

$ systemctl enable chrony       # [On SystemD]$ chkconfig --add chronyd       # [On Init]

配置 Chrony

Chrony 的默認配置文件為 /etc/chrony.conf,下面將介紹一些常用的配置項。

  1. server hostname [option]

server 指令用於指定要同步的 NTP 服務器。

server 0.centos.pool.ntp.org iburst

其中的 0.centos.pool.ntp.orgNTP 服務器的地址,默認有四組官方的 NTP 服務器。你也可以修改為自定義的時間服務器,例如:ntp1.aliyun.com

iburst 是參數, 一般用此參數即可。該參數的含義是在頭四次 NTP 請求以 2s 或者更短的間隔,而不是以 minpoll x 指定的最小間隔,這樣的設置可以讓 chronyd 啟動時快速進行一次同步。

其他的參數有 minpoll x 默認值是 6,代表 64smaxpoll x 默認值是 9,代表 512s

  1. driftfile file

Chrony 會根據實際時間計算修正值,並將補償參數記錄在該指令指定的文件里,默認為 driftfile /var/lib/chrony/drift

ntpd 或者 ntpdate 最大的區別就是,Chrony 的修正是連續的,通過減慢時鐘或者加快時鐘的方式連續的修正。而 ntpd 或者 ntpdate 搭配 Crontab 的校時工具是直接調整時間,會出現間斷,並且相同時間可能會出現兩次。因此,請放棄使用 ntpdntpdate 來校時。

  1. makestep threshold limit

此指令使 Chrony 根據需要通過加速或減慢時鐘來逐漸校正任何時間偏移。例如:makestep 1.0 3,就表示當頭三次校時,如果時間相差 1.0s, 則跳躍式校時。

  1. rtcsync

啟用內核時間與 RTC 時間同步 (自動寫回硬件)。

  1. logdir

該參數用於指定 Chrony 日誌文件的路徑。

  1. stratumweight

該參數用於設置當 chronyd 從可用源中選擇同步源時,每個層應該添加多少距離到同步距離。默認情況下設置為 0,讓 chronyd 在選擇源時忽略源的層級。

基本上常用的參數就只有這幾個了,通常默認的配置文件就可以直接使用了,下面我們來看一個修改完成後的配置文件內容。

# 這裡只修改了 server 中的 NTP 服務器地址,如果網絡環境良好可以使用默認配置server ntp1.aliyun.com iburstserver ntp2.aliyun.com iburst  driftfile /var/lib/chrony/driftmakestep 1.0 3rtcsynclogdir /var/log/chrony

使用 Chrony 客戶端程序進行管理

  1. 檢查 Chrony 是否實際同步

為了檢查 Chrony 是否實際同步,我們將使用它的命令行程序 chronyc 來驗證。

$ chronyc tracking  Reference ID    : 78197314 (120.25.115.20)Stratum         : 3Ref time (UTC)  : Fri Jun 28 13:58:17 2019System time     : 0.000042858 seconds slow of NTP timeLast offset     : -0.000187823 secondsRMS offset      : 0.001029734 secondsFrequency       : 17.614 ppm slowResidual freq   : +0.008 ppmSkew            : 5.552 ppmRoot delay      : 0.034440458 secondsRoot dispersion : 0.002149768 secondsUpdate interval : 64.1 secondsLeap status     : Normal

這裡主要關注 Update interval 這個參數, 說明最後兩次更新的時間間隔是 64.1s。以上結果中的其它參數的含義分別是:

  • 引用 ID – 計算機當前同步的引用 ID 和名稱。
  • Stratum – 連接參考時鐘的計算機的跳數。
  • 參考時間 – 這是參考源的最後一次測量的 UTC 時間。
  • 系統時間 – 來自同步服務器的系統時鐘延遲。
  • 最後一次偏移 – 上次時鐘更新的估計偏移量。
  • RMS 偏移 – 偏移值的長期平均值。
  • 頻率 – 如果 chronyd 沒有糾正它,那麼系統的時鐘錯誤的速率。它以 ppm (百萬分率)提供。
  • 殘餘頻率 – 殘餘頻率表示參考源的測量值與當前使用的頻率之間的差異。
  • 偏斜 – 估計頻率的誤差界限。
  • 根延遲 – 網絡路徑延遲到計算機正在同步的層計算機的總和。
  • 跳躍狀態 – 這是跳躍狀態,可以具有以下值之一:正常、插入秒、刪除秒或不同步。
  1. 顯示所有 NTP 源服務器的信息

這裡需要注意的是第二個參數,* 代表當前同步的源,- 代表通過組合算法計算後排除的源。

$ chronyc sources -v  210 Number of sources = 2    .-- Source mode  '^' = server, '=' = peer, '#' = local clock. / .- Source state '*' = current synced, '+' = combined , '-' = not combined,| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.||                                                 .- xxxx [ yyyy ] +/- zzzz||      Reachability register (octal) -.           |  xxxx = adjusted offset,||      Log2(Polling interval) --.      |          |  yyyy = measured offset,||                                     |          |  zzzz = estimated error.||                                 |    |           MS Name/IP address         Stratum Poll Reach LastRx Last sample===============================================================================^* 120.25.115.20                 2   6    37    12    +85us[ -960us] +/-   20ms^- 203.107.6.88                  2   6    37    12   +262us[ +262us] +/-   21ms
  1. 查看 NTP 服務器的在線和離線狀態
$ chronyc activity
  1. 查看 Chrony 服務的日誌
$ journalctl -u chronyd
  1. 檢查 NTP 訪問是否對特定主機可用
$ chronyc accheck
  1. 該命令會顯示有多少 NTP 源在線/離線
$ chronyc activity
  1. 手動添加一台新的 NTP 服務器
$ chronyc add server
  1. 在客戶端報告已訪問到服務器
$ chronyc clients
  1. 手動移除 NTP 服務器或對等服務器
$ chronyc delete
  1. 手動設置守護進程時間
$ chronyc settime
  1. 校準時間服務器,顯示系統時間信息
$ chronyc tracking
  1. 檢查 NTP 訪問是否對特定主機可用
$ chronyc accheck
  1. 查看時間同步源
$ chronyc sources -v
  1. 查看時間同步源狀態
$ chronyc sourcestats -v

Chrony 客戶端程序的功能非常強大,遠不止上面介紹這些。不但支持命令行模式,而且還支持交互模式。如果你想了解更多 Chrony 客戶端程序的使用方法,可以使用 man chronyc 命令獲取更多幫助。

使用 Chrony 作為 NTP 服務器

要將 Chrony 作為一個 NTP 服務器,方法很簡單。

首先,你需要修改 /etc/chrony.conf 文件,並添加以下配置即可。

# 對於安全要求比較高的,這裡可以限制誰能訪問本機提供的 NTP 服務。allow 192.168.1.0/24  # 設置 chronyd 監聽在哪個網絡接口bindcmdaddress 0.0.0.0  # 這個地方很重要,如果服務器本身也不能同步時間,那麼就用本地時間替代,層級為 10local stratum 10

其次,重啟 Chronyd 服務,以加載新的配置。

$ systemctl restart chronyd

Chronyd 服務啟動成功後,會監聽以下兩個端口。

  • 端口 123/udp 為標準的 NTP 監聽端口,如果要對外提供 NTP Server 功能,必須開啟防火牆和監聽地址為外部可訪問地址。如需修改,你可以通過配置 port 參數來修改。
  • 端口 323/udp 為默認的管理端口。如需修改,你可以通過配置 cmdport 參數來修改。

最後,修改防火牆設置,以放行對 123/udp 的請求,這裡以 CentOS 7Firewalld 為例。

$ firewall-cmd --zone=public --add-port=123/udp --permanent$ firewall-cmd --reload

延伸閱讀

一些可用的公共 NTP 服務

公共 NTP 服務網上很多,但國內環境下最好用的應該還屬阿里雲的公網 NTP 服務。

一些時間相關的概念介紹

  1. GMT、UTC、CST、DST 時間
  • UTC 整個地球分為二十四時區,每個時區都有自己的本地時間。在國際無線電通信場合,為了統一起見,使用一個統一的時間,稱為通用協調時 (UTC, Universal Time Coordinated)。
  • GMT 格林威治標準時間 (Greenwich Mean Time) 指位於英國倫敦郊區的皇家格林尼治天文台的標準時間,因為本初子午線被定義在通過那裡的經線。( UTCGMT 時間基本相同)
  • CST 中國標準時間 (China Standard Time)
  • GMT + 8 = UTC + 8 = CST
  • DST 夏令時 (Daylight Saving Time) 指在夏天太陽升起的比較早時,將時間撥快一小時,以提早日光的使用。(中國不使用)
  1. 硬件時間和系統時間
  • 硬件時間:RTC (Real-Time Clock)CMOS 時間,一般在主板上靠電池供電,服務器斷電後也會繼續運行。僅保存日期時間數值,無法保存時區和夏令時設置。
  • 系統時間:一般在服務器啟動時複製 RTC 時間,之後獨立運行,保存了時間、時區和夏令時設置。

一些設置時區和時間的命令

  1. 查看當前系統時區
# 直接使用 timedatectl 命令也等同於以下命令$ timedatectl status      Local time: Fri 2018-2-29 13:31:04 CST  Universal time: Fri 2018-2-29 05:31:04 UTC        RTC time: Fri 2018-2-29 08:17:20       Time zone: Asia/Shanghai (CST, +0800)     NTP enabled: yesNTP synchronized: yes RTC in local TZ: no      DST active: n/a
  1. 設置當前系統時區

如果你當前的時區不正確,請按照以下操作設置。

# 查看所有可用的時區$ timedatectl list-timezones  # 查看上海可用時區$ timedatectl list-timezones |  grep  -E "Asia/S.*"Asia/SakhalinAsia/SamarkandAsia/SeoulAsia/ShanghaiAsia/SingaporeAsia/Srednekolymsk  # 設置當前系統為 Asia/Shanghai 上海時區$ timedatectl set-timezone Asia/Shanghai  # 設置完時區後,在強制同步下系統時鐘$ chronyc -a makestep200 OK
  1. 顯示系統的當前時間和日期
$ timedatectl set-time "YYYY-MM-DD HH:MM:SS"$ timedatectl set-time "YYYY-MM-DD"$ timedatectl set-time "HH:MM:SS"
  1. 修改當前日期時間
# 可以只修改其中一個$ timedatectl set-time "2019-10-31 15:50:00"
  1. 設置硬件時間
# 硬件時間默認為 UTC,下面兩條命令效果等同$ timedatectl set-local-rtc 1$ hwclock --systohc --localtime
  1. 啟用或者禁止 NTP 時間同步
# yes 或 no,1 或 0 也可以$ timedatectl set-ntp yes/no$ timedatectl set-ntp true/flase