Dynamo模式支持并發寫入同一個鍵,這可能會導致寫沖突的發生。在多主架構中,寫沖突一般在寫操作同步的時候;在無主架構中則是在讀修復或者是數據回傳的時候。
問題主要在于,對于不同的節點,由于網絡等原因,經常看到不同的事件發生順序。
不同節點看到不同的事件發生順序
如果每個節點都采用簡單的最后寫入獲勝的策略,就有可能出現上面圖示的情況:不同節點對于事件發生的順序無法達成一致。對此,有以下應對策略:
最后寫入原則
對于節點本身,保留最后寫入的數據去覆蓋相對比較舊的數據,關鍵點在于對于可能沖突的寫入操作,如何確定他們的發生順序。事件順序有時真的很難確定,甚至在很多情況下是并發的請求。這時需要一些機制來確定事件順序,比如為每次寫操作加上時間戳,對于沖突操作只保留最大時間戳的數據(這就是最后寫入原則)。
由于在讀修復或者數據回傳的時候,沖突操作才能被檢測到,這會出現一種情況:寫操作時返回操作成功,過一段時間(發生了讀修復或者數據回傳)這個寫操作被覆蓋了。
happens-before和并發
如何確定兩個時間是否是并發的?
有些場景下兩個請求必然存在先后順序,比如創建和更新,創建和刪除等等。有些場景則沒有邏輯上的先后順序,比如不同客戶端對于同一個鍵的修改。前者中,有happens-before關系,邏輯上的依賴;后者則沒有邏輯上的先后順序,叫做并發請求。
下面以一個購物車為例來說明并發與happens-before請求的確定:
購物車
對于這個圖示,下圖說明了happens-before和并發的關系:
購物車請求關系
- 數據庫保留版本號概念,為每次寫入操作進行版本號遞增。
- 讀操作時返回所有沒有被覆蓋的數據和版本號,規定寫操作進行之前必須先進行讀操作,并針對最新的版本數據進行寫操作。
- 寫操作進行時必須說明是基于某一版本的數據進行更新寫入。
這里有沖突自動解決策略的介紹。
Vector clock
Happens-before