天天看點

Linux下GDB調試NTP時間同步問題

最近有遇到一例比較有趣的Linux下NTP時間同步問題,嘗試了使用GDB調試的方法解決,在這裡分享一些個人的心得,希望對大家有些幫助。

問題現象:

ECS Linux CentOS執行個體中時間經常出現偏差,客戶已經根據官方文檔配置了NTP時間同步,同步源為文檔中指定的公網NTP伺服器:

<a href="https://help.aliyun.com/knowledge_detail/40583.html">https://help.aliyun.com/knowledge_detail/40583.html</a>

嘗試調整一些同步頻率的參數,并沒有實際效果。其中注意到一個現象,如果我們列出NTP日志中資訊,會發現一旦出現 "no servers reachable" 之後,ntpd就會停止同步。

Linux下GDB調試NTP時間同步問題

而如果重新開機ntpd同步問題就會暫時得到解決,過了一天左右問題又會複現。

調試過程:

由于通過普通的ntpd的調整一些參數無法解決問題,決定采用GDB現場調試的方式來看看問題發生時為什麼ntpd不再同步。

調試之前我們首先要确認ntpd更新系統時間是具體在哪個函數中實作的。是以首先采用閱讀Linux NTP代碼的方式将範圍縮小,确認具體代碼段如下:

void

clock_select(void)

{

...

clock_update(); &lt;----------- 更新系統時間

是以我首先将斷點設在clock_select,結果是可以中到,得到的堆棧如下:

Linux下GDB調試NTP時間同步問題

是以我進一步可以設定斷點到clock_update附近:

Linux下GDB調試NTP時間同步問題

但是這次沒有中,是以可以判定是在之前的邏輯判斷中跳出了。進一步跟蹤後發現:

for (n = 0; n &lt; NTP_HASH_SIZE; n++) {

如上代碼我們對每一個時間同步源會調用peer_unfit來判斷他是否“适合”做時間同步。如果所有同步源都不适合做同步的話,自然就會跳出。是以接下去我們可以考慮設定斷點在peer_unfit,并且檢視其傳回值:

Linux下GDB調試NTP時間同步問題

注意上圖是在本地正常的測試機上截取的,而在使用者機器上傳回值寄存器rax為1,是以可以判斷所有配置的同步源被peer_unfit中的邏輯判斷為不适合做同步。

是以我們接下去就可以使用相同的方法對peer_unfit做進一步跟蹤:

我們發現失敗在如下的檢查:

if (root_distance(peer) &gt;= sys_maxdist + clock_phi *

彙編代碼如下:

Linux下GDB調試NTP時間同步問題

這表明計算下來本地時鐘和遠端NTP伺服器的distance過大。clock_phi 是晶振的頻率為0.000015,而sys_poll是同步的詢問時間,兩者相乘是非常小的。是以主要比較的是目前的distance和sys_maxdist,後者預設為1。

root_distance是一個相對複雜的計算:

dist += max(sys_mindisp, dist + peer-&gt;delay) / 2 +

其中可以發現他和目前時鐘和NTP服務上次成功的時間,兩者的內插補點有關。是以如果時鐘走的比較快,而有一次甚至幾次同步失敗,整個NTP服務就有可能不會再進行同步了。

尋找解決方案:

以上比較的幾個參數中唯一可調的就是sys_maxdist,我們可以繼續閱讀Linux代碼來了解怎麼調整他:

是以我們可以通過在ntp.conf中添加"tos maxdist"可以增大,進而容忍本地時鐘過快。

以上一例是采用GDB調試的方法來解決一些服務産生的問題,希望給大家提供解決問題的另一種思路。

繼續閱讀