分佈式事務?咱先弄明白本地事務再說 - 可用性和速度(鎖和併發)的博弈

 

在上文《分佈式事務?咱先弄明白本地事務再說 - ACID》中,咱們講解了數據庫的事務及事務的特性ACID,瞭解到一個數據庫要支持事務,就須要實現完備的事務的規範,咱們才能說這是一個支持事務的數據庫,例如Mysql、Oracle等。
本文就來討論一下數據庫實現事務的幾個關鍵階段,背後都經歷了哪些曲折的技術變遷。html

數據庫的事務,本質上是解決數據庫併發的問題,處理多個數據操做時相互不干擾,都能獲得正確的執行結果,這個問題在應用層是沒法解決的,由於你徹底不知道同時可能有另外一個程序(進程)也在操做相同的數據項,因此,這個問題必須由數據庫來解決。sql

徹底順序執行

最簡單的思路,就是徹底順序執行全部的數據庫操做,不須要加鎖,簡單的說就是全局排隊,序列化進行全部的事務單元,數據庫同時只處理一個事務,特色是強一致性,處理性能低。
這種模式適應於早期的C/S開發模式,單機系統,一個系統,一個數據庫(例如Access數據庫),徹底本地用戶+本地系統+本地事務。數據庫

 

 

 

 

並行+排他鎖

開始支持並行處理事務,若是事務之間涉及到相同的數據項時,會使用排他鎖,或叫互斥鎖,先進入的事務獨佔數據項之後,其餘事務被阻塞,等待前面的事務釋放鎖。併發

 

 

 

注意,在整個事務1結束以前,鎖是不會被釋放的,因此,事務2必須等到事務1結束以後開始。分佈式

並行+讀寫鎖

採用了 並行+排他鎖 之後,大幅提高了數據庫事務處理效率,若是幾個事務之間沒有共享數據項,徹底能夠並行被處理,但,一些數據庫大牛們顯然對這個性能還不知足,進一步研究細化發現,全部的事務當中,對數據的操做無非是讀和寫排列組合的幾種結果, 讀讀、寫寫、讀寫、寫讀 這4種狀況的不斷重複。性能

哪些操做之間能夠相互兼容,或者共享呢?例如,讀的時候爲何要阻止讀呢?優化

因此,讀寫鎖就應用而生了,進一步細化鎖的顆粒度,區分讀和寫,讓讀和讀之間不加鎖,這樣下面的倆個事務就能夠同時被執行了。版本控制

 

 

 

讀寫鎖,可讓讀和讀並行,而讀和寫、寫和讀、寫和寫這幾種之間仍是要加排他鎖。code

MVCC

有人可能要說,優化到這個份上,已經差很少了吧,還有空間?
大牛們用行動告訴世人,答案是確定的。
每每,肯定一個模型不是最難的,難的是對這個模型實現的境界,大牛們會把本身的實現往死裏優化,並行+讀寫鎖 解決了讀和讀的並行,大牛們接下來要解決的是寫和讀、讀和寫,甚至寫和寫是否均可以並行!htm

這個技術就是如今大部分數據庫在使用的事務處理技術,MVCC(Multi Version Concurrency Control),也就是Copy on Write的思想,對數據項進行多版本控制,一個精妙的想法,用空間換時間,進一步優化鎖,減小鎖。

 

 

MVCC

給每條記錄增長版本號和刪除倆個字段,在事務開始的時候copy一個新的版本,此時事務操做的其實是一個副本,所以不會影響其餘事務對此數據項的讀操做,選擇版本號最大的記錄讀取。

MVCC的好處,

  1. 除了支持讀和讀並行意外,可用讓讀和寫並行、寫和讀並行,但,爲了保證一致性,寫和寫是沒法並行的。
  2. 大事務支持較好,以前的全部方案,由於鎖的廣泛存在,若是一個事務執行的時間太長,意味着後面的事務要長期等待,甚至超時,因此在以前,數據庫一直建議不要維持大的數據庫事務。

另外,MVCC支持讀已提交 和 重複讀倆種隔離級別,串行和讀未提交都沒有意義,一個必需要求排隊執行,另外一個要求必須讀取最新數據。

小結

人類對速度的激情是沒有最快,只有更快。
因此,以上方案的演變,本質是速度上的逐步提高的過程,到目前MVCC爲止,在數據庫層面能作的事情已經很少了。

進一步,如何解決寫和寫衝突的問題,這裏提供倆個思路

  1. 樂觀鎖,適合於資源爭搶不太嚴重的場景,由業務層控制,增長一個字段記錄讀取時的狀態,更新是判斷是否與讀取時的狀態一致,決定是否進行寫操做,避免發生寫操做衝突;
  2. BASE理論(Basically Available[基本可用],Soft State[軟狀態]和Eventually Consistent[最終一致]),數據庫徹底放開一致性要求,出現衝突,由用戶決定,相似於Git Merge合併衝突的解決機制,咱們後面單獨撰文解讀。
相關文章
相關標籤/搜索