致未來的你:當地底分店出現「時空倒置」時,鼴鼠經理如何看破因果關係?

更新 發佈閱讀 10 分鐘
vocus|新世代的創作平台

一、 一封來自未來的蚯蚓快信

歡慶蚯蚓漢堡 100周年,現此時舉辦「限量黃金蚯蚓」的搶購活動,但台北分店的系統出現故障,在系統維修完成後,台北分店的系統時間仍出現異常。此時,台北分店和台中分店都在自己的標準時間 12:00 分別送出最後一條「限量黃金蚯蚓」的訂單到總部,但台北的時間戳記因為系統時鐘異常而快了一分鐘,蓋上時間戳記的是 12:01。神奇的事情發生了——總部在標準時間 12:00 收到台北分店 12:01 送出的訂單 ,難道這是一筆來自未來的訂單?

一般來說,世界各地的電腦在參與網路世界的通訊時,會根據網路時間協定(Network Time Protocol,NTP)來確保不同電腦的時鐘能夠維持同步, 然而,訊號傳送的過程中可能因物理路徑長度、網路通訊中斷、伺服器延遲等原因而發生 時鐘偏移(Clock Skew)。一般情況下,透過 NTP 可以讓誤差維持在毫秒級別內,例如 1-50ms 的誤差範圍,這樣微小的誤差,在高併發的情境下卻可能釀成嚴重後果。舉例來說,總部該如何判斷台北分店及台中分店何者的訂單先送到,並將「限量黃金蚯蚓」移交給較早送出訂單的分店?


二、 邏輯時鐘的現身:蘭波特時鐘 (Lamport Clocks)

  • 蘭波特時鐘 (Lamport Clocks)來自 1978年 的神級論文 Time, Clocks, and the Ordering of Events in a Distributed System,提供了確認訊息的先後關係的絕妙方法:不問「現在幾點」,改問「誰影響了誰」(因果律 Causality)。
  • 鼴鼠對帳規則:每筆交易都讓本地計數器 +1,且寄信時會附上計數器。收信時,取「本地計數器」與「信件上的計數器」的最大值,再 +1 作為新的計數器。

實作範例:

  1. 台北分店 賣出了兩份漢堡,計數器來到 2,在賣出第三份漢堡後變為 3,並將此訊息寄給 台中分店,信封上蓋著數字 3
  2. 台中分店 今天只賣出了一份漢堡,計數器只有 1。收到台北的訊息後,它不會只把自己的數字變 2,而是取最大值:台北說的是 3,自己只有 1,所以以 3 為準,再 +1,得到 4
  3. 透過蘭波特時鐘可以保證「收信」這件事在邏輯上永遠發生在「寄信」之後,不管物理時鐘怎麼偏移,順序都不會亂。
  • 致命缺陷:無法判斷「平行時空(併發)
    • 雖然蘭波特時鐘能維持順序(如果 A 影響了 B,則 T(A) < T(B)),但它的反向推論是不成立的,看到 T(A) < T(B),我們無法確定是 A 影響了 B,或是兩者根本毫無關聯。舉例來說,假設台北分店與台中分店曾經通過訊息,之後因地底隧道崩塌而斷網,各自獨立運作。台北分店 一口氣處理了 5 筆訂單,計數器來到 5台中分店 只處理了 2 筆訂單,計數器來到 2。當隧道修復後,台北分店把計數器 5 同步給台中,台中分店看到這個數字,無法判斷「台北分店的 5 是受到我台中分店影響後累積的」還是「台北分店完全自己跑到 5,跟我無關」。單一整數無法區分「有因果關係」和「各過各的」,這就是為什麼我們需要向量時鐘。

三、 進階時空追蹤術:向量時鐘(Vector Clocks)的運作

  • 從數字到陣列:每一間分店都有自己專屬的進度格子,台北分店(A)、台中分店(B)、高雄分店(C)共同組成一個向量 [A, B, C],初始值為 [0, 0, 0]
實作範例:

1. 台北分店 (A) 完成了兩件訂單,將自己的格子 +2,向量更新為[2, 0, 0]
2. 台中分店 (B) 收到台北分店的消息後,先對每個格子取 最大值 ,並在 台中分店 的格子 +1[2, 1, 0](表示「收到這筆通訊」本身也算是完成了一件任務)。
3. 高雄分店 (C) 的獨立行動: 就在台北與台中忙著對帳時,遠在南部的 高雄分店 也沒閒著——它獨立完成了三件訂單([0, 0, 3]),但此時地底隧道發生崩塌,高雄分店 還沒收到台北與台中的任何消息。
4. 資訊的匯流(台中傳給高雄):隧道通了!台中分店 將它手上的向量 [2, 1, 0] 寄給了 高雄分店。高雄分店 收到後,根據規則進行更新:
4-1. 先將所有的格子取 最大值: 台北格取 max(0, 2)=2,台中格取 max(0, 1)=1,高雄格 max(3, 0)=3,得到[2, 1, 3]
4-2. 再將高雄分店自己的格子 +1(代表確認接收到這筆通訊): 3 + 1 = 4
4-3. 高雄分店 的最終向量為 [2, 1, 4]
5. 平行時空的碰撞(衝突發生): 此時,台北分店 又賣出了一份漢堡 (+1),向量更新為 [3, 0, 0]。 現在,總部同時收到了兩本帳:帳本 A (台北) [3, 0, 0] vs. 帳本 B (高雄) [2, 1, 4]

四、 核心技術分析:如何一眼看穿「併發衝突」?

總部收到兩本帳本後(台北分店的帳本 [3, 0, 0]高雄分店的帳本 [2, 1, 4]),開始逐格比對:

  • 台北的 A 格是 3,高雄的 A 格是 2:台北比較大
  • 台北的 B 格是 0,高雄的 B 格是 1:高雄比較大
  • 台北的 C 格是 0,高雄的 C 格是 4:高雄比較大

最終裁決: 總部會發現,因為兩邊沒有任何一方的每個格子都大於等於另一方,這表示這兩家店在互不知情的狀況下都動了帳本,也就是併發衝突(Concurrent)

結案處理:當發生併發衝突時,系統不會隨便覆蓋資料,而是會把這兩份帳本同時交給總部的鼴鼠經理,並標註:「偵測到衝突,請人工確認庫存!」,待鼴鼠經理確認後將兩者合併,以每格的最大值得到 [3, 1, 4],作為下一個世代的起始點。

鼴鼠經理的判別邏輯如下:

  • 祖孫關係(繼承):如果 台北帳本 的每個數字都 小於等於 高雄帳本,代表 台北帳本 是舊資料。
  • 平行時空(衝突):如果兩者「互有勝負」(如 [3, 0, 0] vs. [2, 1, 4]),則表示台北分店和高雄分店在互不知情的狀況下同時修改了庫存,向量時鐘將發出警報,通知鼴鼠經理進行手動合併。

五、 全球等級的因果關係判別挑戰(進階篇)

當蚯蚓漢堡的版圖不斷擴張,系統的複雜度也會隨之飆升。身為資深的鼴鼠經理,必須面對以下兩個「魔王級」的實務挑戰:

挑戰一、因果交貨(Causal Delivery):不能讓回覆比問題更早到!

台北分店寄出一封訊息 M1(我要調貨 10 條蚯蚓),台中分店收到後,立刻回覆了訊息 M2(沒問題,我已經發貨了)。

  • 意外發生: 由於地底隧道的複雜路徑,M2 竟然繞遠路先抵達了高雄分店,而 M1 還卡在半路上。
  • 因果斷層: 此時,高雄分店的向量時鐘還是 [0, 0, 0],它收到來自台中分店的 M2 時發現向量寫著 [1, 1, 0]。 高雄分店的鼴鼠經理會敏銳地察覺:「不對!這封訊息(M2)說它看過台北的第 1 次更新,但我這裡根本還沒收到台北的任何消息——這封回覆不能先處理!」
  • 解決方案: 高雄分店的鼴鼠經理會啟動緩存機制(Buffer),將 M2 放在架子上暫時不處理,直到 M1 終於抵達後才在本地依序處理 M1M2,以確保「因果不倒置」。

挑戰二、剪枝(Pruning):節省空間的代價

當蚯蚓漢堡持續擴張,在鼴鼠王國開了一萬家分店,每一個向量就會變成一萬個數字的超長陣列。每寄一封訊息都要背著這麼多的數字,隧道系統早晚會被壓垮。

  • 解決方案: 為了節省空間,系統有時會進行「剪枝(Pruning)」,強行刪除太久沒更新的分店格子,或是只保留最近動過的那幾個。
  • 隱藏風險: 剪枝雖然減輕了重量,卻會導致「虛假衝突(False Conflict)」。當你刪除了部分歷史紀錄,兩份原本有「祖孫關係」的紀錄相遇時,系統會因為「不認識對方的祖先」而誤以為兩者是平行時空的併發衝突,被迫交給鼴鼠經理人工處理,可能大幅增加鼴鼠經理的工作負擔。

這是鼴鼠經理的終極選擇題:要保留完整的向量歷史以追求絕對精確,還是承擔「虛假衝突」的風險,透過剪枝減少每封訊息的體積來換取系統效能?這沒有標準答案,鼴鼠經理只能根據場景做出取捨。


六、 結語:尊重歷史,守護因果

從蘭波特時鐘的初步嘗試,再到向量時鐘的精密比對,我們在地底世界學到最重要的一課就是:「在沒有物理時鐘的網路世界中,只有因果關係(Causality)能夠是唯一的真理。」

物理時間是幻覺——在分散式系統中,我們不相信信封上郵戳時間,只相信訊息傳遞的先後順序。而向量是偵測器而非解決器,向量時鐘的本質不是為了「解決」衝突,而是為了「誠實地發現衝突」,以確保當資料發生異常時,鼴鼠經理們能第一時間察覺,而不是任由系統自動化地覆蓋掉某人的努力。

什麼時候用蘭波特時鐘就夠了?當你只需要知道「誰先誰後」,不需要偵測併發時。什麼時候需要向量時鐘?當你的系統裡有多個節點可能同時修改同一份資料,而你不能承受靜默的資料覆蓋時,這就是鼴鼠經理的時空追蹤哲學。

「最終小測驗」:

「如果現在有一筆向量是 [2, 5, 1],另一筆是 [1, 6, 1],此時鼴鼠經理會被叫出來進行手動合併,還是系統直接覆蓋?為什麼?」

留言
avatar-img
dizzydog的沙龍
4會員
18內容數
親愛的訪客您好!我是 dizzydog,一位熱衷於前端技術的工程師。這個部落格是我的數位筆記本,記錄著我在程式開發路上的各種發現、挑戰與突破。我相信「輸出」是最有效的學習方式,透過清晰地表達所學,不僅能加深自己的理解,也能幫助其他走在相同道路上的開發者。 歡迎您在這裡探索以及交流。
dizzydog的沙龍的其他內容
2026/03/30
分散式系統在分區 (Partition) 發生時,如何確保資料的最終一致性?本文以「限量黃金蚯蚓」庫存為例,探討了最後寫入者勝 (LWW) 機制的優缺點,並深入介紹了無衝突複製資料類型 (CRDTs) 在數值、內容型資料處理上的應用,並提出了預防勝於治療的最佳解方。
Thumbnail
2026/03/30
分散式系統在分區 (Partition) 發生時,如何確保資料的最終一致性?本文以「限量黃金蚯蚓」庫存為例,探討了最後寫入者勝 (LWW) 機制的優缺點,並深入介紹了無衝突複製資料類型 (CRDTs) 在數值、內容型資料處理上的應用,並提出了預防勝於治療的最佳解方。
Thumbnail
2026/03/25
在分佈式系統設計中,PACELC 定理是 CAP 定理的延伸,探討系統在網路正常(Else)與異常(Partition)兩種情況下,需要在延遲(Latency)或一致性(Consistency)之間做出權衡。本文透過漢堡店的比喻,探討在不同情境下(如普通漢堡 vs. 限量黃金蚯蚓)如何應用此定理。
Thumbnail
2026/03/25
在分佈式系統設計中,PACELC 定理是 CAP 定理的延伸,探討系統在網路正常(Else)與異常(Partition)兩種情況下,需要在延遲(Latency)或一致性(Consistency)之間做出權衡。本文透過漢堡店的比喻,探討在不同情境下(如普通漢堡 vs. 限量黃金蚯蚓)如何應用此定理。
Thumbnail
2026/03/17
本文以「蚯蚓漢堡」連鎖店為例,透過故事說明 CAP 定理的三大核心:一致性(C)、可用性(A)與分區容錯性(P)。當網路中斷時,系統必須在 C 與 A 之間取捨,形成 CP 與 AP 兩種設計策略。文章並結合實務案例,說明不同業務場景下的選擇原則。
Thumbnail
2026/03/17
本文以「蚯蚓漢堡」連鎖店為例,透過故事說明 CAP 定理的三大核心:一致性(C)、可用性(A)與分區容錯性(P)。當網路中斷時,系統必須在 C 與 A 之間取捨,形成 CP 與 AP 兩種設計策略。文章並結合實務案例,說明不同業務場景下的選擇原則。
Thumbnail
看更多
你可能也想看
Thumbnail
※ 功能: 刪除表格中的資料。 ※ 語法: DELETE ON DELETE CASCADE DELETE JOIN ※ DELETE • 語法 : DELETE FROM table_name WHERE condition FROM 後面接上表格的名字:這是想要刪除資料的表
Thumbnail
※ 功能: 刪除表格中的資料。 ※ 語法: DELETE ON DELETE CASCADE DELETE JOIN ※ DELETE • 語法 : DELETE FROM table_name WHERE condition FROM 後面接上表格的名字:這是想要刪除資料的表
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
※ 為什麼我們需要 Transaction? 當我們談到 Transaction(交易)時,指的是一組不可分割的 SQL 操作。這些操作結果只能成功或失敗,以確保資料庫的一致性和完整性。Transaction 是資料庫操作中的一個「邏輯單位」,包含多個操作步驟。如果其中任何一個步驟失敗,整個 Tr
Thumbnail
※ 為什麼我們需要 Transaction? 當我們談到 Transaction(交易)時,指的是一組不可分割的 SQL 操作。這些操作結果只能成功或失敗,以確保資料庫的一致性和完整性。Transaction 是資料庫操作中的一個「邏輯單位」,包含多個操作步驟。如果其中任何一個步驟失敗,整個 Tr
Thumbnail
多條件查詢 AND運算子 SELECT *​ FROM your_table_name WHERE column1 LIKE '_value1%' AND column2 = number​2 OR運算子 SELECT *​ FROM your_table_name WHERE colu
Thumbnail
多條件查詢 AND運算子 SELECT *​ FROM your_table_name WHERE column1 LIKE '_value1%' AND column2 = number​2 OR運算子 SELECT *​ FROM your_table_name WHERE colu
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
※ 把record加到table有兩種方式: VALUES • SELECT ※ 語法 INSERT INTO VALUES 語法: Record 代表一組值的集合,每個值對應到表格中的一個欄位(column)。 INSERT INTO 語法用來指定要插入資料的表格。 需要提供一個
Thumbnail
※ 把record加到table有兩種方式: VALUES • SELECT ※ 語法 INSERT INTO VALUES 語法: Record 代表一組值的集合,每個值對應到表格中的一個欄位(column)。 INSERT INTO 語法用來指定要插入資料的表格。 需要提供一個
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
本文彙整了一些關於 SQL 效能優化的技巧,提供讀者更快的資料處理方案。包括如何清空資料表、獲取最新資料、總和資料時的可能問題以及評估 SQL 語句效能的方法。通過合理的指令使用,能夠大幅提升查詢效率並降低錯誤發生的機率。適合資料庫管理者和程式開發者作為參考。
Thumbnail
本文彙整了一些關於 SQL 效能優化的技巧,提供讀者更快的資料處理方案。包括如何清空資料表、獲取最新資料、總和資料時的可能問題以及評估 SQL 語句效能的方法。通過合理的指令使用,能夠大幅提升查詢效率並降低錯誤發生的機率。適合資料庫管理者和程式開發者作為參考。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
已經存在在table裡面的那些record做更新。 ※ 語法 UPDATE [LOW_PRIORITY] [IGNORE] table_name SET column_name1 = expr1, column_name2 = expr2, … [WHERE
Thumbnail
已經存在在table裡面的那些record做更新。 ※ 語法 UPDATE [LOW_PRIORITY] [IGNORE] table_name SET column_name1 = expr1, column_name2 = expr2, … [WHERE
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News