不少時候咱們都不用特別的關心服務器時間的問題,好比後臺管理系統,若是服務器時間出錯頂多會在頁面獲取錯誤的時間而已,影響不大。但有些程序對時間很是敏感,不能出一丁點錯誤,今天要講的是去年發生在本身身邊的事:因爲時間同步問題引起了部門級故障,形成很是嚴重的後果。由於事件發生還不到一年,而且就在本身身邊,因此記憶猶新。老規矩,在講故事以前先了解一下背景,故事中 X 系統後臺的簡化架構以下: 程序員
它包括 Client->Connector->Heartbeat 三個模塊(固然實際有不少模塊,這裏省去其餘模塊簡化架構,不影響問題的描述)上圖中 Client 模塊機器數量 > 萬臺,Connector 模塊機器數量 > 百臺,而 Heartbeat 模塊機器卻只有一臺,這是引起慘案的根本緣由。事情通過:服務器
int g_lastReportTime = sometime;
void report() {
int currentTime = getCurrentTime();
if (somevalue / (currentTime - g_lastReportTime ) > threshold) {
reportSomething();
g_lastReportTime = currentTime;
}
}
複製代碼
從上面代碼能夠看出 currentTime - g_lastReportTime 在理論上是不會等於零的,可是因爲新啓的機器時間並未與 X 系統內部保持一致。致使 Client 時間回退,也就出現了 currentTime - g_lastReportTime = 0 的狀況。架構
以上過程花了將近 40多分鐘,形成了很是大的影響。後來部門對事故相關責任人進行了問責和所有門通報。此次事故看似偶然,其實必然,從心跳機器單點那一刻。器宕機形成的事故遠不及 Client core 形成的嚴重,能夠看出本次事故的主要緣由是因爲時間不一樣步形成的,但它也不是孤立的,是衆多因素的統一做用結果。本標題服務器時間同步引起的「慘案」並不誇張,但願能引發讀者這塊的注意和思考。併發
在事故發生的時候我也沒有想太多,畢竟當時做爲萌新也想不出來個因此然來。可是隨着工做經驗積累,慢慢的從此次事故中有了一些總結。此次事故主要引出如下四個問題:運維
心跳機器宕機,心跳數據上不來竟然在次日上班的時候才被發現,整整超過 8 小時了。幸好該系統只是一個內部系統,若是是相似淘寶、天貓這種的,那形成的經濟損失和口碑影響可想而知了。據說在半夜監控已經報出異常,可是一個新來的同事定位並未發現問題,才致使了最後的蝴蝶效應。不過好像即便當場發現,若是在切換新機器時沒作好時間同步也會出現 core 事故。對於系統監控我有如下幾點建議:分佈式
這是一個老生常談的話題,網上有一堆的解決方案,這裏不講普適性的只介紹下針對 X 系統的。因爲該系統的特殊性,Heartbeat 模塊並不能進行多機器部署。因此只能單點,那咱們只能祈禱單點機器不會發生故障了嗎?根據墨菲定律:若是你擔憂某種狀況發生,那麼它就更有可能發生。因此不要有僥倖心理,對於 X 系統 Heartbeat 的單點,雖然不能在短期內重構,但咱們仍是能夠作一些事情而不至於須要運維手動切換機器的。一種方案以下:學習
在服務註冊中心對 Heartbeat 模塊機器進行監控,若是發現服務註冊中心沒有了心跳模塊超過必定時間。則啓動備用機器上的 Heartbeat 併發出告警。這樣就能及時的切換到備用 Heartbeat 不至於太匆忙忘這忘那。簡單結構圖以下:測試
事故中的錯誤代碼是我簡化後的,通常不會出現出現這種低級錯誤,應該是一段邏輯處理後產生了相似的代碼,只是不夠直接沒被發現。這種狀況咱們怎麼保證代碼質量問題?我以爲能夠從三個方面考慮:spa
分佈式或者集羣的時間同步也是分佈式系統下須要解決的問題之一,拋開 X 系統事故中的場景不說。有不少場景是須要保持分佈式系統中各個節點(機器)上的時間一致的的,好比銀行交易系統,不能讓後一筆交易的時間比前一筆交易的時間早,不然會給用戶形成困擾。不一樣的分佈式系統有不一樣的解決方案,有的簡單有的複雜。簡單的像 X 系統同樣直接用 ntpdate 就能夠實現,複雜的參考博客園這篇文章《分佈式系統----時鐘同步》實現本身的同步系統。code
固然,以上只是泛泛而談,權當拋磚引玉。不知道你所維護的系統中是否也存在相似的問題呢?早一點把已知的問題暴露出來,比藏着掖着要好的多。在出事故以前發現問題能贏得老闆對你好感,說不定還能升職加薪,而若是在出事以後再來解決問題那就只能背鍋咯。記得關注公衆號哦,記錄着一個 C++ 程序員轉 Java 的學習之路。