分散式事務?咱先弄明白本地事務再說 - 可用性和速度(鎖和併發)的博弈
在上文《 分散式事務?咱先弄明白本地事務再說 - ACID 》中,我們講解了資料庫的事務及事務的特性ACID,瞭解到一個數據庫要支援事務,就需要實現完備的事務的規範,我們才能說這是一個支援事務的資料庫,例如Mysql、Oracle等。
本文就來討論一下資料庫實現事務的幾個關鍵階段,背後都經歷了哪些曲折的技術變遷。
資料庫的事務,本質上是解決資料庫併發的問題,處理多個數據操作時相互不干擾,都能得到正確的執行結果,這個問題在應用層是無法解決的,因為你完全不知道同時可能有另一個程式(程序)也在操作相同的資料項,所以,這個問題必須由資料庫來解決。
完全順序執行
最簡單的思路,就是完全順序執行所有的資料庫操作,不需要加鎖,簡單的說就是全域性排隊,序列化進行所有的事務單元,資料庫同時只處理一個事務,特點是強一致性,處理效能低。
這種模式適應於早期的C/S開發模式,單機系統,一個系統,一個數據庫(例如Access資料庫),完全本地使用者+本地系統+本地事務。
並行+排他鎖
開始支援並行處理事務,如果事務之間涉及到相同的資料項時,會使用排他鎖,或叫互斥鎖,先進入的事務獨佔資料項以後,其他事務被阻塞,等待前面的事務釋放鎖。

注意,在整個事務1結束之前,鎖是不會被釋放的,所以,事務2必須等到事務1結束之後開始。
並行+讀寫鎖
採用了 並行+排他鎖
以後,大幅提升了資料庫事務處理效率,如果幾個事務之間沒有共享資料項,完全可以並行被處理,但,一些資料庫大牛們顯然對這個效能還不滿足,進一步研究細化發現,所有的事務當中,對資料的操作無非是讀和寫排列組合的幾種結果, 讀讀、寫寫、讀寫、寫讀
這4種情況的不斷重複。
哪些操作之間可以相互相容,或者共享呢?例如,讀的時候為什麼要阻止讀呢?
所以,讀寫鎖就應用而生了,進一步細化鎖的顆粒度,區分讀和寫,讓讀和讀之間不加鎖,這樣下面的倆個事務就可以同時被執行了。

讀寫鎖,可以讓讀和讀並行,而讀和寫、寫和讀、寫和寫這幾種之間還是要加排他鎖。
MVCC
有人可能要說,優化到這個份上,已經差不多了吧,還有空間?
大牛們用行動告訴世人,答案是肯定的。
往往,確定一個模型不是最難的,難的是對這個模型實現的境界,大牛們會把自己的實現往死裡優化, 並行+讀寫鎖
解決了讀和讀的並行,大牛們接下來要解決的是寫和讀、讀和寫,甚至寫和寫是否都可以並行!
這個技術就是現在大部分資料庫在使用的事務處理技術,MVCC(Multi Version Concurrency Control),也就是Copy on Write的思想,對資料項進行多版本控制,一個精妙的想法,用空間換時間,進一步優化鎖,減少鎖。

MVCC
給每條記錄增加版本號和刪除倆個欄位,在事務開始的時候copy一個新的版本,此時事務操作的實際上是一個副本,因此不會影響其他事務對此資料項的讀操作,選擇版本號最大的記錄讀取。
MVCC的好處,
- 除了支援讀和讀並行意外,可用讓讀和寫並行、寫和讀並行,但,為了保證一致性,寫和寫是無法並行的。
- 大事務支援較好,之前的所有方案,因為鎖的普遍存在,如果一個事務執行的時間太長,意味著後面的事務要長期等待,甚至超時,所以在之前,資料庫一直建議不要維持大的資料庫事務。
另外,MVCC支援 讀已提交 和 重複讀
倆種隔離級別,序列和讀未提交都沒有意義,一個必須要求排隊執行,另一個要求必須讀取最新資料。
小結
人類對速度的激情是沒有最快,只有更快。
所以,以上方案的演變,本質是速度上的逐步提升的過程,到目前MVCC為止,在資料庫層面能做的事情已經不多了。
進一步,如何解決寫和寫衝突的問題,這裡提供倆個思路
- 樂觀鎖,適合於資源爭搶不太嚴重的場景,由業務層控制,增加一個欄位記錄讀取時的狀態,更新是判斷是否與讀取時的狀態一致,決定是否進行寫操作,避免發生寫操作衝突;
- BASE理論(Basically Available[基本可用],Soft State[軟狀態]和Eventually Consistent[最終一致]),資料庫完全放開一致性要求,出現衝突,由使用者決定,類似於Git Merge合併衝突的解決機制,我們後面單獨撰文解讀。