平行 EVM 的討論裡反覆出現同一套動詞:先平行執行,再檢查衝突,不行就回滾重跑。這聽起來像鏈上原創,骨架卻來自資料庫。1981 年,H. T. Kung 與 John T. Robinson 在 ACM TODS 發表《On Optimistic Methods for Concurrency Control》,把「樂觀」寫成可分析的並行控制方法。讀懂那套邏輯,再看 Block-STM 或平行 EVM 引擎,會少很多神秘感。
本稿用資料庫視角講清 OCC 的假設與三階段,把它和悲觀鎖、MVCC 分開,然後說明區塊鏈借用這套骨架時多了哪些約束。這是理解「為什麼樂觀平行適合 EVM 相容路線」的前置課,而不是任何具體產品的參數手冊。
樂觀在賭什麼
傳統並行控制大量依賴鎖:存取前先加鎖,防止別人同時改你正在讀的資料。鎖能保證正確,但維護鎖表、偵測死鎖、長事務佔鎖拖垮佇列,都會在高並行下變成明顯開銷。OCC 的反直覺提議是:若大多數事務的讀寫集合其實並不重疊,不如先讓它們跑,把衝突檢查推遲到提交前夕,避免為「可能永遠不會發生的衝突」支付鎖成本。論文把回退(backup)當作主要控制手段——「樂觀」指的是寄望於衝突稀疏。
這不是否認衝突存在,而是轉移處理時機:從執行前預防,改為執行後(或臨近提交時)驗證。時機一變,系統設計的主要矛盾就從「如何精細加鎖」變成「如何便宜地偵測衝突、如何縮小重做的範圍」。
讀、驗證、寫:三階段骨架
經典 OCC 把事務拆成三個階段。
讀階段:事務自由讀取資料庫,寫入只落在私有工作區,不立即污染共享狀態。對觀察者而言,尚未驗證事務的副作用還不可見,或僅以隔離方式存在。
驗證階段:事務取得時間戳或序號,系統檢查其讀集是否仍然有效——是否在讀取之後被「按順序應排在前面」的其他事務改寫。若讀集過期,驗證失敗,事務中止並重來。驗證要回答的問題本質是可序列化:平行執行的交錯,能否等價於某個串列順序。
寫階段:驗證通過後,把私有寫集合併進共享資料庫。論文還區分串列驗證與平行驗證:前者把驗證與寫入綁成更強的原子步驟,實作簡單;後者允許更多並行,但需要額外機制保證不會寫出互相矛盾的提交。
把這三個階段映射到區塊鏈平行執行,幾乎是一一對應:交易在推測狀態下執行並收集讀寫集;按區塊內既定順序驗證;通過者提交狀態,失敗者依依賴關係重新執行。名稱可以叫 STM、Block-STM 或「樂觀平行 EVM」,骨架仍是 OCC。
悲觀鎖為何顯得重
兩階段鎖(2PL)是關聯式資料庫裡最經典的悲觀方案:事務持鎖只增不減直到結束。正確性好講,代價也好懂——鎖記憶體、死鎖、佇列頭阻塞。競爭低時,2PL 的「預防稅」可能高於 OCC 偶發的重做;競爭高時,OCC 的重做風暴可能反超鎖的成本。因此 OCC 從一開始就被標成「低爭用更划算」。鏈上的翻譯是:當區塊內交易的讀寫集重疊少,樂觀平行賺得多;當大家都打同一個 AMM 池,樂觀平行必須靠工程把重新執行限制住,否則數字會很難看。
這也解釋了為何效能披露必須標明負載類型與測試條件。實驗室裡大量無關的轉帳,與主網高峰期的 DEX 路由交易,衝突結構完全不同;同一套 OCC 引擎可以給出差一個數量級的觀感。
MVCC:相關,但不是同一個旋鈕
多版本並行控制(MVCC)常與 OCC 並列出現,卻回答不同的問題。MVCC 讓讀者看到一致性快照,讀者不阻塞寫者;核心是版本儲存與可見性規則。OCC 的核心則是驗證失敗時該怎麼辦。二者可以疊加:用多版本降低讀寫互相踩踏,再用樂觀驗證決定寫寫衝突時由誰提交。Hekaton、Silo、TicToc 等系統展示了時間戳、去中心化驗證、延遲分配序號等變體,共同點是承認「純悲觀鎖在多核上太貴」,用版本與延遲驗證換取吞吐量。
對鏈上工程師而言,這層澄清有助於閱讀論文與專案文件:有人說「我們用了 MVCC」,可能只是在描述狀態表示;真正決定平行 EVM 行為的,往往是驗證規則與重新執行的排程——那是 OCC 家族的問題。
區塊鏈多出來的規則
資料庫 OCC 通常假設失敗可以本地重試,客戶端能感知中止。區塊鏈多了兩條硬約束。
第一,全網確定性重放。所有誠實節點對同一區塊必須得到同一最終狀態。樂觀執行可以在節點內部平行,但提交結果必須收斂到與規範順序等價的狀態;不能出現「這台機器因為排程運氣不同而提交了另一套寫集」。這迫使實作把「預設順序」或「規範序號」寫進協議,而不是讓執行緒排程成為語意的一部分。
第二,拜占庭環境。不能假設單一執行者誠實。節點可能說謊、省略、故意製造衝突以拖慢對手。因此平行執行引擎通常嵌在更大的共識與驗證流程裡:順序先由共識確定,執行層負責高效且確定地算出狀態根;輕客戶端與全節點依賴的是可驗證的最終狀態,而不是某次樂觀路徑的中間猜測。
Aptos 團隊在 Block-STM 相關論文中,把引擎明確放在 STM 與 OCC 的傳統上,並強調把「排序」從詛咒變成可利用的效能條件:順序給定後,平行只是加速收斂到該順序的手段。這個說法對平行 EVM 同樣適用——EVM 交易本就活在「區塊內有序」的世界裡,OCC 是在服從該順序的前提下搶多核,而不是取消順序。
讀寫集:抽象簡單,工程不簡單
教科書裡的讀集、寫集,在 EVM 裡對應到帳戶餘額、nonce、儲存槽、偶發的日誌與退款副作用等。粒度太粗(把整個合約當成一個鍵)會製造假衝突,平行度被白白吃掉;粒度太細會讓追蹤與驗證成本上升。動態跳轉、外部呼叫、代理模式讓靜態預先分析不完整,這正是 EVM 難以採用確定性預先宣告的原因,也是為什麼在執行環境中收集讀寫集成為預設策略。
衝突後是重跑單筆、重跑依賴閉包,還是整批作廢,決定尾端延遲。優秀的 OCC 實作把「驗證失敗」當成可預期的熱路徑來最佳化,而不是異常分支。這些細節屬於具體引擎設計;對這篇入門文而言,只需要建立判斷力:看到平行 EVM 宣稱高吞吐量,先問衝突率假設與重新執行策略,再問測試網或基準條件。
從直覺到下一篇定位
用資料庫 OCC 來讀區塊鏈執行,是為了把討論從口號拉回可檢驗的機制:假設是什麼、驗證查什麼、失敗成本由誰承擔。Bitroot 以及其他樂觀平行 EVM 專案,差異往往不在「是否採用 OCC」——而在讀寫集如何擷取、衝突如何分層偵測、共識是否與執行流水線解耦。下一篇會把鏡頭對準 Bitroot:在擴容地圖與三條平行路線上,它選了哪一格、邊界在哪裡,以及哪些承諾仍應標成測試條件下的工程目標。
