不可靠的時鐘 (Unreliable Clocks)

★★★★Draft

FromDDIA

📚 From the Books

不可靠的時鐘 (Unreliable Clocks)Distributed Troubles

每台機器都有自己的石英鐘,各自漂移、還可能被 NTP 悄悄回撥。於是「現在幾點」在分散式系統裡不是一個事實,而是一個帶誤差的估計。把這個估計當成精確時間去排序事件,換來的往往不是崩潰,而是更可怕的東西——靜默的資料遺失

🧠 Intuition

TIP

先分清兩種時鐘,混用是萬惡之源:日曆時鐘 (time-of-day) 回答「現在是幾月幾號幾點」——但它會跳、會被 NTP 回撥;單調時鐘 (monotonic) 只保證「只增不減」——適合量「過了多久」,但它的絕對值毫無意義、跨機器不能比。量間隔用單調鐘,別用日曆鐘。

⚖️ Tradeoffs

NTP 同步遠不如你以為的可靠
  • 本地偏差過大時 NTP 會強制重設、造成時間跳躍;防火牆可能悄悄擋掉 NTP 流量;有些 NTP 伺服器本身就報錯時間。
  • 閏秒讓一分鐘變 59 或 61 秒,曾弄垮許多大型系統;VM 時鐘在 CPU 共享時看似瞬間跳前;使用者的裝置更可能故意設錯。
  • 最危險的不是崩潰,而是靜默偏離:大部分功能看起來正常,時鐘卻悄悄漂離現實——所以必須主動監控機器間的時鐘偏移
用時間戳排序事件的陷阱:LWW 丟資料
  • 多主複製想用日曆時鐘的時間戳來排序寫入,很誘人卻危險
  • 經典反例:A 在 node 1 寫 x=1(戳記 42.004),B 隨後在 node 3 把它 x=2(戳記 42.003,因為 node 3 時鐘慢)。複製到 node 2 時,它看戳記大小、誤以為 x=1 較新而丟掉 x=2——B 的操作靜默消失
  • 這正是 Last Write Wins (LWW) 的病(Cassandra、Riak 廣用):時鐘落後的節點寫的值永遠贏不過時鐘超前的;更根本地,它無法區分真正並行有因果先後的寫入。
  • 更安全的替代是邏輯時鐘 (logical clock):用遞增計數器追蹤事件相對順序,而非量實際時間。
把時鐘讀數當成區間:TrueTime 與 commit-wait
  • 時鐘讀數不該被當成一個時間點,而是一個信賴區間 (confidence interval):例如「有 95% 把握現在落在 10.3–10.5 秒之間」。若不確定度是 ±100 ms,時間戳寫到微秒位純屬自欺。
  • Google TrueTime(用於 Spanner)是少數明確回報區間 [earliest, latest] 的 API。
  • Spanner 用它做跨資料中心的一致性:兩交易區間不重疊就能定先後;重疊刻意等一個區間長度再提交(commit-wait),確保因果順序。為縮短這個等待,Google 在每個機房裝 GPS 接收器或原子鐘,把不確定度壓到約 7 ms

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading