互聯(lián)網(wǎng)上的設(shè)備要保持正常運行需要內(nèi)置時鐘運行精準(zhǔn),像Facebook這種規(guī)模體量的互聯(lián)網(wǎng)公司對設(shè)備時鐘的精準(zhǔn)度要求會更高。本文介紹了Facebook在搭建自己的精確時間服務(wù)方面的探索實踐,最終給我們提供了測量系統(tǒng)時間誤差的方法以及對chrony的應(yīng)用實踐。
數(shù)十億連接到互聯(lián)網(wǎng)的設(shè)備幾乎都有內(nèi)置時鐘,為了保證設(shè)備的正常運行,這些時鐘必須保持精確。因為許多時鐘的內(nèi)部振蕩器并不精準(zhǔn),所以可能會導(dǎo)致每天數(shù)秒的誤差,這就需要定期校正。因為不準(zhǔn)確的時間會導(dǎo)致一些問題,比如錯過重要的提醒時間,甚至導(dǎo)致宇宙飛船發(fā)射失敗。全世界的設(shè)備都依賴網(wǎng)絡(luò)時間協(xié)議(NTP),通過包交換、可變延遲的數(shù)據(jù)網(wǎng)絡(luò)來保持與更精確時鐘的同步。
隨著Facebook基礎(chǔ)設(shè)施的增長,系統(tǒng)中的時間精度變得越來越重要。我們需要知道數(shù)據(jù)中心中兩個隨機服務(wù)器之間的準(zhǔn)確時間差,以便數(shù)據(jù)存儲寫入數(shù)據(jù)時不會打亂事務(wù)順序。我們需要以亞毫秒級的精度同步多個數(shù)據(jù)中心的所有服務(wù)器。為此,我們測試了chrony,這是一個功能豐富的現(xiàn)代NTP服務(wù)器實現(xiàn)。在測試期間,我們發(fā)現(xiàn)與以前使用的服務(wù)ntpd相比,chrony具有更高的精確性和可伸縮性,這就讓我們很安心的用chrony替換了基礎(chǔ)設(shè)施中的ntpd。Chrony也是Facebook公共NTP服務(wù)time.facebook.com的基礎(chǔ)。在這篇文章中,我們將分享將時間精度從10毫秒提高到100微秒所做的工作,以及我們?nèi)绾卧谟嫊r實驗室驗證這些結(jié)果的。
閏秒
在深入了解NTP服務(wù)細(xì)節(jié)之前,我們需要了解一種稱為閏秒的現(xiàn)象。由于地球不規(guī)律的自轉(zhuǎn),我們有時需要增加或減少一秒,或一閏秒。對于人類來說,增加或減少一秒在看鐘表的時候幾乎察覺不到。然而,這種事情發(fā)生在服務(wù)器上,就可能導(dǎo)致大量事務(wù)或事件丟失,甚至發(fā)生嚴(yán)重的軟件故障。解決這一問題最通常的做法是“抹去”閏秒,也就是說每過幾個小時稍微修改一下時間。
規(guī)模建設(shè)NTP服務(wù)
Facebook的NTP服務(wù)分為四個層次:
·第0層是一層擁有極其精確原子鐘的衛(wèi)星,這些原子鐘來自全球?qū)Ш叫l(wèi)星系統(tǒng)(GNSS),如GPS、GLONASS和Galileo。
·第1層是Facebook的原子鐘,與GNSS同步。
·第2層是一個與層1設(shè)備同步的NTP服務(wù)器池。在這一層,閏秒開始出現(xiàn)。
·第3層是更大規(guī)模配置的服務(wù)器層。他們接收被處理過的時間,這一層就感知不到閏秒了。
在某些系統(tǒng)中,可能有多達(dá)16個層來分配工作,對層數(shù)的需求取決于系統(tǒng)規(guī)模和精度要求。
當(dāng)我們開始構(gòu)建NTP服務(wù)時,我們測試了以下后臺程序使用的時間:
1.Ntpd:一個通用的后臺程序,Ntpd過去常常應(yīng)用在大多數(shù)類Unix操作系統(tǒng)中。多年來,它一直是穩(wěn)定的解決方案,現(xiàn)在的大多數(shù)計算機上依舊運行著Ntpd。
2.Chrony:一個比較新的后臺程序,它具有豐富的特性,并且可以為NTP提供精確的時間同步。Chrony還提供了可擴(kuò)展控制協(xié)議,理論上可以將精度降低到納秒。從資源消耗的角度來看,我們發(fā)現(xiàn)ntpd和chrony非常相似,chrony消耗的內(nèi)存甚至稍微少一些(大約有1 MiB的差異)。
評估后臺程序
無論系統(tǒng)是使用ntpd還是chrony,每個系統(tǒng)都提供了一些評估的度量方法。通過使用這些后臺程序的命令行工具可以進(jìn)行評估。這些評估是基于一定的假設(shè)為前提的,例如:
·客戶機和服務(wù)器之間的網(wǎng)絡(luò)路徑要有對稱性。
·當(dāng)時間戳被添加到NTP包并調(diào)用send()時,操作系統(tǒng)會立即發(fā)送它。
·振蕩器的溫度和輸入電壓是恒定的。
Ntpd包含ntpq命令行工具,可以顯示時間沒有同步的狀態(tài):
[user@client ~]# ntpq -p
remote refid st t when poll reach delay offset jitter
=========================================================================
+server1 .FB. 2 u 406 1024 377 0.029 0.149 0.035
+server2 .FB. 2 u 548 1024 377 0.078 0.035 0.083
*server3 .FB. 2 u 460 1024 377 0.049 -0.185 0.114
然而,這些數(shù)據(jù)可信么?如果ntpd報告時間差了0.185 ms,是否準(zhǔn)確?答案是否定的。服務(wù)器根據(jù)包中的多個時間戳估計偏移量,而實際值應(yīng)該在一個10倍大的窗口內(nèi)。換句話說,差0.185毫秒的結(jié)果意味著偏差可能在+/-2毫秒內(nèi)(總共4毫秒)。我們的測試表明,ntpd的準(zhǔn)確性一般在10毫秒以內(nèi)。
我們有更高精度的技術(shù)要求。例如,多主數(shù)據(jù)庫將微秒甚至納秒的精度直接轉(zhuǎn)換為理論吞吐量。另一個需要中等精度的示例是日志記錄,為了在分布式系統(tǒng)的節(jié)點之間匹配日志,通常需要毫秒級的精度。
下面讓我們看看如果用chrony替換ntpd,效果會怎樣:
[user@client ~]# chronyc sources -v
210 Number of sources = 19
.-- 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
===============================================================================
^+ server1 2 6 377 2 +10us[ +10us] +/- 481us
^- server2 2 6 377 0 -4804us[-4804us] +/- 77ms
^* server3 2 6 377 59 -42us[ -46us] +/- 312us
^+ server4 3 6 377 60 +11ns[-3913ns] +/- 193us
注意最后三個數(shù)字。在最后,從右向左看:
·最后一個數(shù)字是估計誤差。它的前綴是+/-。它表示chrony的最大誤差范圍。有時是10毫秒,有時是100微秒(100倍的差異)。這是因為當(dāng)chrony與另一個chrony同步時,使用擴(kuò)展的NTP協(xié)議,這極大地提高了精度。效果還不錯。
·下一個是方括號中的數(shù)字。它顯示了測量的偏移量。除了server4(我們稍后將討論這個),其它的我們看到也大約有100倍的差異。
·方括號左邊的數(shù)字顯示的是最初的測量值,經(jīng)過調(diào)整后,允許自第一次測量以來的任何slews應(yīng)用于本地時鐘。同樣,我們可以看到ntpd和chrony之間的差異也是100倍。
請看下圖:
藍(lán)色豎線表示ntpd被chrony替換的時間點。對于ntpd,其范圍是+/-1.5 ms。用了chrony后,變動范圍在微秒內(nèi)。更重要的是,估計誤差(窗口)下降到了100微秒的范圍,這些是可以通過實驗室測量來確認(rèn)的(下面會有更多的介紹)。但是,這些值是用后臺程序估算的。實際上,實際時間可能完全不同。我們?nèi)绾悟炞C這些數(shù)字的準(zhǔn)確性呢?
每秒脈沖數(shù)(1PPS)
我們可以從原子鐘中提取模擬信號(實際上是來自層1設(shè)備的內(nèi)部計時電路)。這個信號叫做1PPS,意思是每秒1個脈沖;它在每一秒的開始都會在同軸電纜上產(chǎn)生一個脈沖。這是一種主流的、精確的同步方法。我們可以在NTP服務(wù)器上生成相同的脈沖,然后比較各個階段的差異。這里有個困難點就是,并非所有服務(wù)器都支持1PPS,因此需要專門的網(wǎng)絡(luò)擴(kuò)展卡。
我們第一次測試是手動完成的,使用了一臺顯示相移的示波器。
通過10分鐘的測量,我們估算出ntpd的偏移約為3.5毫秒,有時會跳到10毫秒。
這個測試在Facebook大規(guī)模服務(wù)器上實現(xiàn)起來是極其困難并且也不切實際。更好的測試方法是將測試服務(wù)器的1PPS輸出連接到層1設(shè)備本身的1PPS輸入,并監(jiān)控其差異。
這種方法可以實現(xiàn)上一個測試方法中所有優(yōu)點,同時也不需要在數(shù)據(jù)中心使用示波器。如果使用該方法,我們能夠在任何時間點進(jìn)行測量并驗證真實的NTP偏移量。
通過這兩個測量結(jié)果,我們對實際的NTP偏移有了很好的了解,使用1PPS誤差估計在納秒內(nèi),這主要是由電纜長度導(dǎo)致的。
這些方法的不足之處是:
·電纜鋪設(shè):做這樣的測試需要同軸電纜。在不同的數(shù)據(jù)中心進(jìn)行測試需要更改數(shù)據(jù)中心的布局設(shè)計,這是比較困難的。
·定制硬件:不是所有網(wǎng)卡都有1PPS輸出。這樣的測試需要特殊的網(wǎng)卡和服務(wù)器。
·層1設(shè)備需要1PPS輸入。
·服務(wù)器上需要安裝1PPS軟件:為了運行測試,我們必須在我們的測試服務(wù)器上安裝ntpd。這個后臺程序可能會導(dǎo)致意外錯誤,因為它在用戶空間中工作,并會被Linux調(diào)度。
專用測試設(shè)備
市場上有一些設(shè)備可以進(jìn)行準(zhǔn)確性測試。它們包含GNSS接收器,一個原子鐘,多個1PPS和網(wǎng)絡(luò)接口,還可以充當(dāng)NTP客戶端。這就讓我們可以直接使用NTP協(xié)議執(zhí)行相同的測試。接收到的NTP包由原子鐘或GNSS接收器以非常精確的時間戳記錄。
以下就是常見的裝備:
上面的照片是我們最初臨時用的測試設(shè)備。使用該設(shè)備進(jìn)行測量有以下幾個優(yōu)點:
·它不需要額外的1PPS電纜。我們雖然仍然需要約束原子鐘,但這可以通過使用GNSS或?qū)?設(shè)備本身和一根短電纜來實現(xiàn)。
·它使用原子鐘的數(shù)據(jù)來標(biāo)記傳輸和接收的網(wǎng)絡(luò)數(shù)據(jù)包。這使得操作系統(tǒng)的影響可以忽略不計,誤差率只有幾納秒。
·它同時支持NTP和PTP(精確時間協(xié)議)。
·該設(shè)備是便攜式的,我們可以在不同地點之間移動它來執(zhí)行測試。
·設(shè)備使用自己的數(shù)據(jù)點集格式,但它可以將數(shù)據(jù)導(dǎo)出到CSV,也就是說我們可以按我們的數(shù)據(jù)標(biāo)準(zhǔn)導(dǎo)出數(shù)據(jù)。
NTPD測量
結(jié)果與我們在后臺程序評估和1PPS測量中看到的非常相似。首先,我們發(fā)現(xiàn)有一個10毫秒的下降,然后慢慢地修正為+/-1毫秒。有趣的是,這個10毫秒的下降是相當(dāng)穩(wěn)定的,并且在每次重啟后都會出現(xiàn)。
Chrony測量
這看起來與chrony后臺程序的估算非常相似,它比ntpd好10到100倍。
Chrony的硬件時間戳
Chrony極大地改善了偏移量,這可以從1PPS的估算結(jié)果和實驗室設(shè)備值中看出。不過Chrony還支持硬件時間戳。根據(jù)文檔,Chrony聲稱可以將精度提高到幾百納秒以內(nèi)。
讓我們來看看網(wǎng)絡(luò)上NTP客戶機-服務(wù)器通信中的NTP包結(jié)構(gòu)。初始客戶端的NTP包包含傳輸時間戳字段。
服務(wù)器填充其余的字段(例如,接收時間戳),將客戶機的傳輸時間戳保存為原始時間戳,并將其發(fā)送回客戶機。
可以使用tcpdump驗證此行為:
08:37:31.489921 IP6 (hlim 127, next-header UDP (17) payload length: 56) client.36915 > time1.facebook.com.ntp: [bad udp cksum 0xf5d2 -> 0x595e!] NTPv4, length 48
Client, Leap indicator: clock unsynchronized (192), Stratum 0 (unspecified), poll 3 (8s), precision -6
Root Delay: 1.000000, Root dispersion: 1.000000, Reference-ID: (unspec)
Reference Timestamp: 0.000000000
Originator Timestamp: 0.000000000
Receive Timestamp: 0.000000000
Transmit Timestamp: 3783170251.489887309 (2019/11/19 08:37:31)
Originator - Receive Timestamp: 0.000000000
Originator - Transmit Timestamp: 3783170251.489887309 (2019/11/19 08:37:31)
...
08:37:31.490923 IP6 (hlim 52, next-header UDP (17) payload length: 56) time1.facebook.com.ntp > server.36915: [udp sum ok] NTPv4, length 48
Server, Leap indicator: (0), Stratum 1 (primary reference), poll 3 (8s), precision -32
Root Delay: 0.000000, Root dispersion: 0.000152, Reference-ID: FB
Reference Timestamp: 3783169800.000000000 (2019/11/19 08:30:00)
Originator Timestamp: 3783170251.489887309 (2019/11/19 08:37:31)
Receive Timestamp: 3783170251.490613035 (2019/11/19 08:37:31)
Transmit Timestamp: 3783170251.490631213 (2019/11/19 08:37:31)
Originator - Receive Timestamp: +0.000725725
Originator - Transmit Timestamp: +0.000743903
...
客戶端會獲得數(shù)據(jù)包,附加另一個接收時間戳,并使用下面這個NTP RFC#958中的公式計算偏移量:
c=(t2-t1+t3-t4)/2
然而,Linux不是一個實時操作系統(tǒng),它要運行的進(jìn)程不止一個。因此,當(dāng)傳輸時間戳被填滿并調(diào)用Write()時,并不能保證立即通過網(wǎng)絡(luò)發(fā)送數(shù)據(jù):
另外,如果機器沒有足夠的流量,在發(fā)送NTP包之前可能需要一個ARP請求,ARP請求是不可靠的,這會導(dǎo)致估算錯誤。但chrony支持硬件時間戳,使用這些方法,另一端的chrony可以高精度地確定數(shù)據(jù)包何時被網(wǎng)絡(luò)接口處理。雖然從網(wǎng)卡戳記數(shù)據(jù)包到它實際離開數(shù)據(jù)包之間仍然有一個延遲,但小于10ns。
還記得之前這個chronyc sources的輸出形式嗎?
^+server4 2 6 377 60+11ns[-3913ns]+/-193us
Chrony報告偏移量為11 ns。這是因為啟用了硬件時間戳的結(jié)果。然而,估計誤差在幾百微秒的范圍內(nèi)。雖然不是所有的網(wǎng)卡都支持硬件時間戳,但是隨著它越來越受歡迎,網(wǎng)卡會慢慢支持這個特性。要驗證對硬件時間戳的支持,只需運行ethtool檢查,然后就可以看到硬件傳輸和硬件接收功能。
ethtool-T eth0
Time stamping parameters for eth0:
Capabilities:
hardware-transmit(SOF_TIMESTAMPING_TX_HARDWARE)
hardware-receive(SOF_TIMESTAMPING_RX_HARDWARE)
hardware-raw-clock(SOF_TIMESTAMPING_RAW_HARDWARE)
通過使用實驗室設(shè)備測試相同的硬件,我們就可以得到不同的結(jié)果了,ntpd誤差顯示在-10毫秒和3毫秒之間(13毫秒的差異),chrony誤差顯示在-200微秒和200微秒之間,而且啟用硬件時間戳后,在大多數(shù)情況下chrony誤差都顯示在-100微秒和100微秒之間。這也證實了之前后臺程序的估算可能是不準(zhǔn)確的。
公共服務(wù)
現(xiàn)在,所有測量都在我們內(nèi)部控制的數(shù)據(jù)中心網(wǎng)絡(luò)中進(jìn)行。下面,我們看看當(dāng)我們在公共NTP服務(wù)或者其他一些著名的公共NTP服務(wù)提供商上測試時,情況是什么樣的:
測量的結(jié)果好壞在很大程度上取決于網(wǎng)絡(luò)路徑以及網(wǎng)絡(luò)連接的速度和質(zhì)量。這些測量并沒有受到Facebook網(wǎng)絡(luò)的影響,針對的是來自不同地點、不同Wi-Fi和LAN網(wǎng)絡(luò)的服務(wù)進(jìn)行的多次測試。我們可以看到,我們的公共NTP服務(wù)不僅與其他主流的供應(yīng)相比有競爭優(yōu)勢,而且在某些情況下,它的性能也更優(yōu)。
公共NTP設(shè)計方案
在我們成功地將內(nèi)部精度提升到亞毫秒級別之后,我們就啟動了一個公共NTP服務(wù),它可以通過設(shè)置time.facebook.com作為NTP服務(wù)器來使用。我們在我們的網(wǎng)絡(luò)入網(wǎng)點(PoP)上運行這個公共NTP服務(wù)。為保障私隱,我們不會按IP地址為設(shè)備設(shè)定指紋。為了在即使請求網(wǎng)絡(luò)路徑失敗的情況下也能提供更好的服務(wù),我們在五個不同的地理位置都設(shè)置了端點。我們的五個端點如下:
·time1.facebook.com
·time2.facebook.com
·time3.facebook.com
·time4.facebook.com
·time5.facebook.com
每個端點都在不同的地理位置上,這對可靠性和時間精度都有積極的影響。
time2.facebook.com的網(wǎng)絡(luò)路徑如下:
time3.facebook.com的網(wǎng)絡(luò)路徑如下:
抹掉閏秒
Ntpd一直使用一種預(yù)發(fā)布的閏秒列表文件。有了這個文件,Ntpd就可以提前進(jìn)行時間修正,當(dāng)閏秒實際發(fā)生時,也能保證時間是正確的。
Chrony依賴于GNSS提前幾小時發(fā)布的閏秒指示器。當(dāng)閏秒事件在UTC 00:00實際發(fā)生時,在指定的時間段內(nèi)它就會被抹去。有了Facebook公共NTP服務(wù),我們決定采用更精確的方法,在事件結(jié)束后的大約18個小時內(nèi)抹去閏秒。
因為涂抹操作要在層2的許多服務(wù)器上同時進(jìn)行,所以保持操作盡可能的相似是很重要的。按照平滑的正弦曲線規(guī)則進(jìn)行操作對應(yīng)用程序來說是安全的選擇。
經(jīng)驗總結(jié)
測量時間是非常具有挑戰(zhàn)性的。ntpd和chrony提供的估算方法在一定程度上都是正確的。一般來說,如果您想要監(jiān)控真實的偏移量,我們建議使用1PPS或帶有GNSS接收器和原子鐘的外部設(shè)備。
在比較ntpd和chrony時,我們的測量結(jié)果表明chrony要精確得多,這就是我們將基礎(chǔ)設(shè)施遷移到chrony并啟動公共NTP服務(wù)的原因。結(jié)果證明,將精度從幾十毫秒提高到幾百微秒是值得的。
使用硬件時間戳可以進(jìn)一步將精度提高兩個數(shù)量級。盡管NTP已經(jīng)有所改善,但它也有自己的局限性,因此對PTP的研究使用才有可能將您的精度提升到下一個級別。
英文原文:
https://engineering.fb.com/production-engineering/ntp-service/