1.說明
前面講了幾個隔離級別露戒,有這樣的問題
1.隔離級別很難理解护蝶,并且各db實現(xiàn)方法不一致
2.很難界定自己的應(yīng)用代碼應(yīng)該在哪個隔離級別下才是安全的
3.并發(fā)競爭很難發(fā)現(xiàn)以及復(fù)現(xiàn)
這一節(jié)就講解串行化,顧名思義心墅,就是結(jié)果和串行化執(zhí)行一樣酿矢。
往往通過下面三種方式實現(xiàn)
1.真的是串行執(zhí)行
2.兩階段鎖 2PL(2 phase locking)
3.序列化快照隔離 SSI(Serializable Snapshot Isolation)
下面講解這三種方式
2.真.串行化
最簡單的就是真的串行化,優(yōu)劣如下
有時比支持并發(fā)的系統(tǒng)表現(xiàn)更好,以為不用管理鎖
但是吞吐量會有限制
由于需要最大程度利用單線程嗓化,事務(wù)的組織結(jié)構(gòu)會略有變化棠涮,用到下面的存儲過程
存儲過程
比如一個定機(jī)票的場景,涉及多步操作:1.查找路線價格和坐位 2.選坐位 3.支付以及訂單
這些操作要在一個事務(wù)里面完成刺覆,但是如果每一步都讓用戶選擇严肪,會浪費資源(線程資源限制,在等待)谦屑,且影響了其他事務(wù)的執(zhí)行(因為真串行化一次一個)
為了避免網(wǎng)絡(luò)IO驳糯,延遲以及希望sql能夠事先編譯好,db提出了存儲過程
存儲過程這里就不講了氢橙,參照refer
存儲過程的優(yōu)缺點:
優(yōu)點:
1.使得真串行化變得可行,提高了吞吐酝枢,減少了并發(fā)
缺點:
1.不同db存儲過程語言不一樣,并且發(fā)展慢
2.db跑的代碼難以管理悍手,不像自己的應(yīng)用代碼
3.因為db比業(yè)務(wù)sever更底層帘睦,所以如果存儲過程寫的不好,影響更大
真串行化小結(jié)
雖然真串行化可行坦康,但是有如下限制
1.要求每個事務(wù)短而且快
2.要求數(shù)據(jù)集全部載入內(nèi)存中才行
3.單CPU的話竣付,寫的吞吐量必須低
分區(qū)的話,寫事務(wù)的跨區(qū)操作會有限制
3. 2階段鎖(2PL)
近30年滞欠,2PL是廣泛應(yīng)用于串行化中的方法(備注:2PL不是2PC即2階段提交)
兩階段鎖:
讀鎖會block住寫鎖
寫鎖會block住其他寫操作和讀鎖
注意這個和上一節(jié)的快照隔離是不一樣的古胆,體現(xiàn)在原則上,區(qū)別如下
快照隔離要求寫不影響讀筛璧,讀不影響寫
2PL中逸绎,讀寫互相影響
實現(xiàn)2PL
主要用鎖惹恃,共享鎖和獨占鎖,機(jī)制如下:
1.讀事務(wù)去拿共享鎖
2.寫操作必須拿獨占鎖
3.如果一個事務(wù)先讀后寫,則需要升級共享鎖為獨占鎖
4.事務(wù)拿到鎖之后棺牧,必須一直持有直到提交或者放棄巫糙。
"兩階段鎖"中,"兩階段"的意思就是:第一個階段是上鎖陨帆,第二個階段是釋放鎖
2PL的表現(xiàn)
性能是主要瓶頸,部分原因是鎖多了曲秉,并發(fā)量降低了
由于串行化,前面的事務(wù)占有鎖可能會使得后面的事務(wù)block住
因此疲牵,2PL有不確定性的延遲
并且死鎖的觸發(fā)會比讀提交的隔離級別更頻繁
文中提到了Predicate locks以及Index-range locks,有點晦澀這里就不展開了
3. Serializable Snapshot Isolation (SSI)
前面的兩種方法中榆鼠,
2PL性能不好
真.串行化 拓張興不好
這里提出SSI纲爸,相較于快照隔離,提供了完全的串行化妆够,只有輕微的性能損失
和快照隔離不同的是
快照隔離用悲觀鎖的思想识啦,假定所有事務(wù)都有可能出錯,所以要等到安全再執(zhí)行神妹。
SSI用樂觀鎖的思想颓哮,事務(wù)都會continue,希望every thing will be ok鸵荠,最終提交時再檢測是否需要丟棄
這在競爭少的情況下表現(xiàn)優(yōu)良冕茅,在競爭多的情況下表現(xiàn)相對較差(因為頻繁丟棄事務(wù))
無論如何,只要足夠稀疏蛹找,事務(wù)競爭不會太高姨伤,樂觀思想比悲觀思想表現(xiàn)的更好
3.1 在過時的假定下的決策
結(jié)合上一節(jié)講的幻讀的例子
醫(yī)院值班時,至少要一個醫(yī)生庸疾,此時兩個值班醫(yī)生Alice和Bob都在值班乍楚,但是都想請假,會執(zhí)行事務(wù)邏輯如下
1.當(dāng)前值班醫(yī)生一共有幾個
2.如果大于一個(因為算上自己)届慈,那么自己就可以請假了
這樣兩個事務(wù)同時執(zhí)行徒溪,最終可能導(dǎo)致醫(yī)院沒有值班醫(yī)生。
這種場景金顿,主要體現(xiàn)在一個事務(wù)后續(xù)的寫依賴于前面查詢得到的決策
安全起見臊泌,db假設(shè)前置查詢的結(jié)果如果有變化,后續(xù)的寫操作也會變得invalid.
因此,在快照隔離的基礎(chǔ)上串绩,結(jié)合樂觀鎖的思想缺虐,SSI提供出沖突檢測的算法,來判斷一個事務(wù)提交時礁凡,是否需要丟棄
主要分為兩個case
1.事務(wù)read時高氮,由于MVCC原因忽略了某些寫操作慧妄,等提交時,之前忽略的寫操作已經(jīng)commit了
2.當(dāng)前事務(wù)的讀操作的結(jié)果剪芍,被后續(xù)其他事務(wù)的寫操作影響了
這里可能并不是很好理解塞淹,下面會有demo說明,結(jié)合圖片理解
3.2 檢測舊的MVCC讀
簡單來說罪裹,就是一個事務(wù)讀取時饱普,忽略掉的MVCC的舊版本的數(shù)據(jù),在該事務(wù)提交前提交了状共,最終之前忽略掉的寫卻生效了
還是按照醫(yī)生值班的例子
方框處的記錄在事務(wù)42提交時生效,但是事務(wù)43讀取數(shù)據(jù)時峡继,這個方框記錄由于MVCC原因冯袍,被忽視掉了
解決方式如下
db記錄一個事務(wù)由于MVCC可見性原因而忽略掉其他事務(wù)的寫操作
當(dāng)該事務(wù)準(zhǔn)備提交時,看忽略的寫操作是否已經(jīng)commit
若是碾牌,則該事務(wù)丟棄
為什么要等到commit時采取檢測呢康愤,這樣做避免了不必要的丟棄:
1.如果事務(wù)43是read only的呢,并不用丟棄舶吗。誰能知道后面它會基于此進(jìn)行寫操作呢
2.說不準(zhǔn)事務(wù)42也會被丟棄征冷,因此不會影響事務(wù)43呢
3.3 檢測寫操作影響了之前的讀
和上面的問題類似,直接畫圖
上面的查詢中检激,有index-range鎖在entry 1234上,后面事務(wù)42寫的時候踊赠,獲取了一個類似于寫鎖的東西呵扛,只不過他并不是阻塞其他事務(wù)的提交,而是負(fù)責(zé)通知:通知所有在entry 1234上的事務(wù)筐带,告訴他們讀的數(shù)據(jù)已經(jīng)過時了今穿。因此事務(wù)43最后會被丟棄.
3.4 SSI的表現(xiàn)
許多工程細(xì)節(jié)影響算法在實踐中的工作效果。跟蹤事務(wù)的讀寫的粒度會產(chǎn)生影響伦籍。
如果數(shù)據(jù)庫非常詳細(xì)地跟蹤每一個事務(wù)的活動蓝晒,那么它就可以精確地判斷哪些事務(wù)需要中止,但是這些開銷會變得很大帖鸦。
而不太詳細(xì)的跟蹤事務(wù)會更快速芝薇,但可能導(dǎo)致更多的事務(wù)被中止。
相比與兩階段鎖作儿,可串行化隔離快照是大有好處的:一個事務(wù)不需要阻塞等待另一個事務(wù)持有的鎖洛二。
4.思考
過時假定下的決策
這個部分很重要,結(jié)合上一節(jié)幻讀的例子,理解這個思想
SSI的構(gòu)成
在快照隔離的基礎(chǔ)上晾嘶,結(jié)合樂觀鎖的思想妓雾,檢測兩種case來判斷事務(wù)的提交是否有沖突進(jìn)而被丟棄。
SSI檢測沖突的兩種方法的區(qū)別
結(jié)合上面圖1垒迂,圖2理解
圖1是事務(wù)42 select械姻,update之后,事務(wù)43才執(zhí)行机断,因此有MVCC出現(xiàn)
圖2,是事務(wù)42,43都select之后楷拳,42再進(jìn)行update,所以沒有MVCC而是有事務(wù)42直接的寫的結(jié)果吏奸,影響了事務(wù)43之前的select結(jié)果
5.名詞
2PL
Predicate locks
Index-range locks
SSI
6.refer
http://www.reibang.com/p/a84e4f41a2aa
存儲過程
http://www.cnblogs.com/hoojo/archive/2011/07/19/2110862.html
https://www.w3cschool.cn/sql/sql-storage.html