先來(lái)回顧下,之前的幾個(gè)一致性的概念。
首先是STRICT CONSISTENCY,就是要求所有的操作都嚴(yán)格的按照機(jī)器上的WALL CLOCK來(lái)排序。那么所有并行的進(jìn)程的操作都會(huì)有序。這在分布式的情況下是做不到的。
和這個(gè)最接近的是SEQUENCE CONSISTENCY。它的經(jīng)典實(shí)現(xiàn)是IVY,用自定義的TOTAL ORDER來(lái)取代WALL LOCK。我們只要認(rèn)為所有機(jī)器看到的這個(gè)順序是一樣的,就是符合SEQUENCE CONSISTENCY。
下一級(jí)是 RELEASE CONSISTENCY,他確保的是鎖的釋放和獲取之間是被SEQUENCE CONSISTENCY 保護(hù)的。而沒(méi)有鎖的地方順序是可以不一樣的。
EVENTUAL CONSISTENCY, 是為了性能考慮,而引入。它所保證的是你可能看到的結(jié)果可能是舊的,但未來(lái)某個(gè)時(shí)刻會(huì)得到新的。
下面我們就來(lái)討論如果一臺(tái)機(jī)器掛了怎么辦?
機(jī)器掛了的最大問(wèn)題是狀態(tài)會(huì)丟失,所以我們要做的是保證重啟之后狀態(tài)和原來(lái)一樣并且掛的這個(gè)事使得整個(gè)執(zhí)行進(jìn)入一個(gè)不合理的狀態(tài)。
不合理的狀態(tài)就是個(gè)中間狀態(tài),不是ALL OR NOTHING。 是操作了一半留個(gè)爛攤子的狀態(tài)。這個(gè)中間的狀態(tài)是非法的。

下面舉個(gè)1000塊的轉(zhuǎn)賬的例子。為了性能考慮,一開(kāi)始都是緩存在內(nèi)存里,最后寫入磁盤。

這個(gè)例子會(huì)發(fā)生A的錢被減掉,B卻沒(méi)拿到。
第一種思路是用備份的頁(yè)再上面改完,然后用一個(gè)指針轉(zhuǎn)移(這個(gè)操作為原子)來(lái)實(shí)現(xiàn)原子效果。

這種思路有2個(gè)問(wèn)題。
1.可能原子操作點(diǎn)不是很好找
2.TX可能不是由一個(gè)人完成的。

解決思路是LOG

這個(gè)LOG 可以在舊狀態(tài)時(shí)用來(lái)REDO,恢復(fù)出新?tīng)顟B(tài)。
也可以在新?tīng)顟B(tài)時(shí)UNDO,恢復(fù)成舊的。
第一種設(shè)計(jì),使用一個(gè)LOG文件來(lái)記入所有TX。LOG是用APPEND的方式追加在最后。

為什么要使用一個(gè)文件,而不是每個(gè)TX一個(gè)LOG 呢?
好處是順序?qū)懕容^快。如果是多個(gè)文件,幾個(gè)TX并行,就變成了隨機(jī)寫會(huì)慢很多。

TX COMMIT之后怎么實(shí)現(xiàn)的?
WAL:寫內(nèi)存前先保證LOG在DISK上寫完了。
在一系列操作完成后,要做COMMIT ACTION,寫COMMIT標(biāo)志進(jìn)LOG

發(fā)生問(wèn)題,如何RECOVER。
MEMORY全丟失,可以去看LOG。
從后向前掃。首先判斷TX提交還是沒(méi)提交。有標(biāo)記的做REDO記號(hào),沒(méi)標(biāo)記的丟棄。
隨后根據(jù)有標(biāo)記的REDO,從前向后重做。
這樣全部重做,很慢,所以我們需要CHECK POINT??梢员苊釲ONG TRANSACTION FLOW。
當(dāng)一個(gè)時(shí)間點(diǎn),沒(méi)有TX在做了。我可以加入一個(gè)CHECK POINT標(biāo)志。代表之前的都OK了,那我下次REDO的時(shí)候,可以直接從CHECK POINT 開(kāi)始。
但是這個(gè)時(shí)間點(diǎn)很難找,怎么辦?
用當(dāng)前沒(méi)有正在執(zhí)行的ACTION。

下面看個(gè)例子。

現(xiàn)在CHECK POINT 開(kāi)始RECOVERY, 會(huì)記錄INPROGESS TX LOG 的位置。
會(huì)有T2 和 T4的LOG。
因?yàn)?是完成的TX。 2和4 是IN PROGESS的。
這個(gè)CASE是一些操作先放內(nèi)存,每次CHECKPOINT 的時(shí)候去寫DISK。
紅色框是需要REDO, 綠色框是需要UNDO

還有一種策略,是在完成TX的時(shí)候,才去把一些結(jié)果寫進(jìn)CHECK POINT。沒(méi)有完成就什么都不寫。這樣的好處是不需要UNDO LOG。這種策略是REDO ONLY 的策略。
我們看下轉(zhuǎn)賬的例子,底層的LOG在寫什么?
這個(gè)轉(zhuǎn)賬是A 有3000塊,B有2000塊,A向B 轉(zhuǎn)1000
C有10塊,D有0塊, C向D轉(zhuǎn)10 塊。


然后找到CHECK POINT 開(kāi)始做RECOVERY

因?yàn)锳B的轉(zhuǎn)賬,已經(jīng)COMMIT了。所以在CHECK POINT的結(jié)果都寫進(jìn)DISK了。但是C 和D都是0.
首先要把沒(méi)完成的TX UNDO。所以根據(jù)CHECK POINT,找到C = C-10,來(lái)做UNDO。 C = C +10;
就UNDO好了。 隨后把T1 COMMIT 的log 在CHECK POINT之后做REDO。

為啥要同時(shí)做UNDO REDO LOG?
如果一個(gè)TX很長(zhǎng),如果只有REDO,那么TX的操作都去不了DISK,需要很多內(nèi)存去緩存。然后恢復(fù)需要全部REDO很費(fèi)時(shí)間。
如果只有UNDO,那就每個(gè)操作都要寫進(jìn)去,就更慢了。
如果沒(méi)有LONG TX,是可以用其中一種LOG的。REDO + CHECKPOINT。

這邊就是A 會(huì)被FLUSH,因?yàn)門X1 COMMIT了。B 會(huì)被REDO。 C 不會(huì)被FLUSH。
