併發控制技術手段之多版本(三)


<併發控制之多版本>
html

爲了實現可串行化,同時避免鎖機制存在的各類問題,咱們能夠採用基於多版本併發控制(Multiversion concurrency control,MVCC)思想的無鎖併發機制。人們通常把基於鎖的併發控制機稱成爲悲觀機制,而把MVCC等機制稱爲樂觀機制。這是由於鎖機制是一種預防性的,讀會阻塞寫,寫也會阻塞讀,當鎖定粒度較大,時間較長是併發性能就不會太好;而MVCC是一種後驗性的,讀不阻塞寫,寫也不阻塞讀,等到提交的時候才檢驗是否有衝突,因爲沒有鎖,因此讀寫不會相互阻塞,從而大大提高了併發性能。redis

咱們能夠借用源代碼版本控制來理解MVCC,每一個人均可以自由地閱讀和修改本地的代碼,相互之間不會阻塞,只在提交的時候版本控制器會檢查衝突,並提示merge。目前,Oracle、PostgreSQL和MySQL都已支持基於MVCC的併發機制,但具體實現各有不一樣。數據庫

MVCC的一種簡單實現是基於CAS(Compare-and-swap)思想的有條件更新(Conditional Update)。普通的update參數只包含了一個keyValueSet',Conditional Update在此基礎上加上了一組更新條件conditionSet { ... data[keyx]=valuex, ... },即只有在D知足更新條件的狀況下才將數據更新爲keyValueSet';不然,返回錯誤信息。這樣,L就造成了以下圖所示的Try/Conditional Update/(Try again)的處理模式:緩存

雖然對單個L來說不能保證每次都成功更新,但從整個系統來看,老是有任務可以順利進行。這種方案利用Conditional Update避免了大粒度和長時間的鎖定,當各個業務之間資源爭用不大的狀況下,併發性能很好。不過,因爲Conditional Update須要更多的參數,若是condition中value的長度很長,那麼每次網絡傳送的數據量就會比較大,從而致使性能降低。特別是當須要更新的keyValueSet'很小,而condition很大時,就顯得很是不經濟。網絡

爲了不condition太大所帶來的性能問題,能夠爲每條數據項增長一個int型的版本號字段,由D維護該版本號,每次數據有更新就增長版本號;L在進行Conditional Update時,經過版本號取代具體的值。併發

另外一個問題是上面的解決方案假設了D是能夠支持Conditional Update的;那麼,若是D是一個不支持Conditional Update的第三方的key-value存儲怎麼辦呢?這時,咱們能夠在L和D之間增長一個P做爲代理,全部的CRUD操做都必須通過P,讓P來進行條件檢查,而實際的數據操做放在D。這種方式實現了條件檢查和數據操做的分離,但同時下降了性能,須要在P中增長cache,提高性能。因爲P是D的惟一客戶端;因此,P的cache管理是很是簡單的,沒必要像多客戶端情形擔憂緩存的失效。不過,實際上,據我所知redis和Amazon SimpleDB都已經有了Conditional Update的支持。分佈式

鎖機制和MVCC對比

上面介紹了鎖機制和MVCC的基本原理,可是對於它們分別適用於什麼場合,不一樣的場合下兩種機制優劣具體表如今什麼地方還不是很清楚。這裏我就對一些典型的應用場景進行簡單的分析。須要注意的是下面的分析不針對分佈式,鎖機制和MVCC兩種機制在分佈式系統、單數據庫系統、甚至到內存變量各個層次都存在。ide

場景1:對讀的響應速度要求高

有一類系統更新特別頻繁,而且對讀的響應速度要求很高,如股票交易系統。在鎖機制下,寫會阻塞讀,那麼當有寫操做時,讀操做的響應速度就會受到影響;而MVCC不存在讀寫鎖,讀操做是不受任何阻塞的,因此讀的響應速度會更快更穩定。性能

場景2:讀遠多於寫

對於許多系統來說,讀操做的比例每每遠大於寫操做,特別是某些海量併發讀的系統。在鎖機制下,當有寫操做佔用鎖,就會有大量的讀操做被阻塞,影響併發性能;而MVCC能夠保持比較高且穩定的讀併發能力。代理

場景3:寫操做衝突頻繁

若是系統中寫操做的比例很高,且衝突頻繁,這時就須要仔細評估。假設兩個有衝突的業務L1和L2,它們在單獨執行是分別耗時t1,t2。在鎖機制下,它們的總時間大約等於串行執行的時間:

T = t1 + t2

而在MVCC下,假設L1在L2以前更新,L2須要retry一次,它們的總時間大約等於L2執行兩次的時間(這裏假設L2的兩次執行耗時相等,更好的狀況是,若是第1次能緩存下部分有效結果,第二次執行L2耗時是可能減少的):

T’ = 2 * t2

這時關鍵是要評估retry的代價,若是retry的代價很低,好比,對某個計數器遞增,又或者第二次執行能夠比第一次快不少,這時採用MVCC機制就比較適合。反之,若是retry的代價很大,好比,報表統計運算須要算幾小時甚至一天那就應該採用鎖機制避免retry。

從上面的分析,咱們能夠簡單的得出這樣的結論:對讀的響應速度和併發性要求比較高的場景適合MVCC;而retry代價越大的場景越適合鎖機制。

總結

本文介紹了一種基於多版本併發控制(MVCC)思想的Conditional Update解決分佈式系統併發控制問題的方法。和鎖機制相比,該方法避免了大粒度和長時間的鎖定,能更好地適應對讀的響應速度和併發性要求高的場景。


備註:轉載自http://www.kuqin.com/system-analysis/20120319/319108.html

相關文章
相關標籤/搜索