李海翔,從事數(shù)據(jù)庫研發(fā)、數(shù)據(jù)庫測試與技術(shù)管理等工作10余年,擅長于 PostgreSQL和MySQL等開源數(shù)據(jù)庫的內(nèi)核與架構(gòu),現(xiàn)為騰訊云數(shù)據(jù)庫專家工程師。

并發(fā)控制技術(shù)是數(shù)據(jù)庫的核心技術(shù),在本次主題演講中,李海翔主要對數(shù)據(jù)庫并發(fā)控制技術(shù)進行深入淺出的解析,同時分享騰訊云數(shù)據(jù)庫CDB在金融業(yè)務(wù)方面的一些心得。下面是李海翔演講的摘錄:

今天,我們來一起聊聊數(shù)據(jù)庫的并發(fā)控制技術(shù)??梢哉f,沒有事務(wù)處理,數(shù)據(jù)庫就不能算是數(shù)據(jù)庫;沒有并發(fā)控制技術(shù),事務(wù)處理也只是一個名詞而已。毫不夸張地說,并發(fā)控制技術(shù)是數(shù)據(jù)庫的核心技術(shù)。

數(shù)據(jù)庫的四大特性就是ACID,A是原子性,C是一致性,I是隔離性,D是持久性。

我們今天所講的并發(fā)控制技術(shù),關(guān)聯(lián)著這四個特性中的C和I特性。為什么這么說呢?因為沒有并發(fā)控制,數(shù)據(jù)庫的一致性就會被破壞。沒有并發(fā)控制,也就無從談起隔離性,就會出現(xiàn)數(shù)據(jù)異常。在并發(fā)控制技術(shù)下數(shù)據(jù)的正確得到首先保證,然后通過隔離和其他并發(fā)控制技術(shù)保證性能。

因此,我們今天把并發(fā)控制技術(shù)的前因后果,通過6個小節(jié)和大家聊一聊。

首先,我們來共同看第一個問題:數(shù)據(jù)異?,F(xiàn)象有哪些?PPT中列出了大家都熟悉的三種讀數(shù)據(jù)異常,分別是臟讀、不可重復(fù)讀、幻讀。

以臟讀舉例,第一步,T2事務(wù)修改了數(shù)據(jù)行row;第二步,T1事務(wù)對同一個數(shù)據(jù)行row讀??;第三步,T2事務(wù)回滾。這對于事務(wù)T1而言,讀到的數(shù)據(jù)是將被回滾的數(shù)據(jù),這就是臟讀。

有朋友會問,臟讀,也沒有什么大不了的吧。試想一下,一個騙子T2轉(zhuǎn)帳1000元給事務(wù)T1,事務(wù)T1檢查自己的賬戶,入賬了1000元,然后事務(wù)T1把一件衣服賣給了騙子T2,之后騙子T2拿到衣服后回滾了轉(zhuǎn)賬1000元的操作,然后逃之夭夭了。事務(wù)T1既沒有拿到錢還丟失了衣服,損失很大。越是要求高的業(yè)務(wù),越需要避免這樣的異常發(fā)生。

這三個讀異?,F(xiàn)象,是大家熟知的,也是SQL標(biāo)準(zhǔn)所定義的數(shù)據(jù)異?,F(xiàn)象。那么,除了讀異常,還有其他的數(shù)據(jù)異常嗎?

臟寫和丟失更新,也是常見的寫異常之一。以臟寫舉例。第一步,事務(wù)T1修改數(shù)據(jù)行row;第二步,事務(wù)T2也修改數(shù)據(jù)行row并提交,數(shù)據(jù)修改生效。事務(wù)T2認(rèn)為自己的操作是成功的。但不幸的事情發(fā)生了,第三步,事務(wù)T1回滾了,用舊值替換了被事務(wù)T2寫過的值。這意味著事務(wù)T2存入銀行的錢,丟失了,因為帳本上只記著第一步事務(wù)T1讀取的數(shù)據(jù)值。這就是寫數(shù)據(jù)發(fā)生的數(shù)據(jù)不一致的現(xiàn)象。

那么,除了這些讀和寫異常,還有其他的數(shù)據(jù)異常嗎?

接下來,我們繼續(xù)介紹兩種寫偏序異常:兩個事務(wù)寫偏序和三個事務(wù)寫偏序。

我們來看一下兩個事務(wù)寫偏序。首先,這里有個前提:醫(yī)院向社會承諾,至少有一名醫(yī)生對外提供電話咨詢服務(wù)。但是,如果有多于兩個醫(yī)生在提供電話咨詢,則需要某個正在進行電話咨詢服務(wù)的醫(yī)生停止服務(wù)。

可是,大家看這兩個事務(wù)。事務(wù)T1發(fā)現(xiàn),有兩個以上的醫(yī)生正在提供電話咨詢,就請Alice停止電話服務(wù);事務(wù)T2也發(fā)現(xiàn)有兩個以上的醫(yī)生正在提供電話咨詢,就請Bob停止了電話服務(wù)。這樣,如果執(zhí)行前只有Alice和Bob正在提供電話服務(wù),這兩個事務(wù)執(zhí)行完畢后,沒有一個醫(yī)生在對外提供電話咨詢服務(wù)了。這就違背了“至少有一名醫(yī)生對外提供電話咨詢服務(wù)”的約束前提。這樣也是一種數(shù)據(jù)異?,F(xiàn)象。

因為時間關(guān)系,這里不一一為大家列舉常見的11種數(shù)據(jù)異常。對于數(shù)據(jù)庫系統(tǒng)而言,如果允許異常發(fā)生,那么我們這個依靠數(shù)據(jù)庫做交易的世界就會發(fā)生巨大混亂——數(shù)據(jù)在,賬亂了;人活著,錢沒了。

而并發(fā)控制技術(shù),就能很好的解決上面說的這些問題。

接下來,我們討論第二個問題:為什么會產(chǎn)生剛才所說的那些數(shù)據(jù)異?,F(xiàn)象?這個問題看似簡單,如果能夠精準(zhǔn)地回答出來,說明對ACID這四個特性和相關(guān)的技術(shù)理解地非常深刻。我這里解釋下,在數(shù)據(jù)庫里,數(shù)據(jù)操作會被抽象為兩種,就是讀操作和寫操作。讀寫操作組合在一起,有四種情況,就是這幅圖里面的,讀讀、讀寫、寫讀和寫寫。在數(shù)據(jù)庫里面,只有讀讀操作,不會引發(fā)數(shù)據(jù)異常,而其他三種,都會引發(fā)數(shù)據(jù)異常。

讓我們以剛才所講過的異常為例,一起來分析一下。大家看,剛才講過的三種讀異常,有個一個共同點,就是存在并發(fā)的事務(wù);其次,并發(fā)的事務(wù)操作的是同一個數(shù)據(jù)對象。再次并發(fā)事務(wù)對該數(shù)據(jù)對象,有寫操作。最后,還有一種特殊情況,對于幻讀而言,受謂詞條件的影響,這時不是操作物理上的同一個已經(jīng)存在的對象,而是操作謂詞限定的同一個范圍內(nèi)的邏輯意義上的對象。我們把第四種情況概括為“謂詞的語義”。

這些合起來,造成了三種讀數(shù)據(jù)異常。

?

寫偏序是怎么產(chǎn)生的了?首先,存在并發(fā)的事務(wù)。其次,并發(fā)的事務(wù),操作的不是同一個數(shù)據(jù)對象,這點和剛才的讀異常不同。再次,并發(fā)的事務(wù)對不同的數(shù)據(jù)對象,有寫操作,沒有讀讀并發(fā)。最后,操作結(jié)果,違反了“語義前提”?!斑`反語義”是指操作數(shù)據(jù)時,需要遵守一個語義前提,例如“至少有一名醫(yī)生對外提供電話咨詢服務(wù)”,但是并發(fā)操作打破了這個語義前提,出現(xiàn)了沒有醫(yī)生提供咨詢的異?,F(xiàn)象。

以上概括了數(shù)據(jù)異常出現(xiàn)的原因。而解決這些數(shù)據(jù)異常辦法就是并發(fā)控制技術(shù)。這是此次我們分享的第三點:并發(fā)控制技術(shù)有哪些?

主流的并發(fā)控制技術(shù)主要包括大家熟知的兩階段鎖、基于時間戳的并發(fā)控制技術(shù)、基于有效性檢查的并發(fā)控制技術(shù),以及MVCC、CO等技術(shù)。

我們來分析并發(fā)控制技術(shù)。

并發(fā)控制技術(shù)通常采用兩階段鎖方案,即把事務(wù)劃分為加鎖階段和解鎖階段,兩個階段中間的點,被稱為封鎖點。而光劃分為兩個階段還是不夠的,還需要確定事務(wù)的結(jié)束點位于哪里,這個結(jié)束點和封鎖點的關(guān)系是什么。而并發(fā)控制協(xié)議SS2PL和S2PL的差別在于釋放鎖的時機不同,即事務(wù)的結(jié)束點和封鎖點是否重合。SS2PL是在事務(wù)提交后,才釋放讀鎖和寫鎖。

如果簡單地說數(shù)據(jù)庫使用兩階段鎖技術(shù)解決了并發(fā)訪問造成的數(shù)據(jù)不一致,這樣的理解是不夠深入的。準(zhǔn)確的說,兩階段鎖技術(shù)中的“SS2PL在讀操作上加鎖”才能真正解決數(shù)據(jù)異常。這句話的含義是:使用SS2PL實現(xiàn)了序列化隔離級別,才不會產(chǎn)生第一個問題中所說的各種數(shù)據(jù)異?,F(xiàn)象。就是說通過序列化確保數(shù)據(jù)的一致性。而序列化隔離級別屬于隔離性,我們通過“SS2PL在讀階段加鎖”這樣的并發(fā)控制技術(shù),保證了一致性。

這樣,并發(fā)控制技術(shù)確保了正確性,而其他的隔離級別則在犧牲一定的一致性的情況下,可以提高并發(fā)度,提高數(shù)據(jù)庫的性能,所以SQL標(biāo)準(zhǔn)規(guī)定了多種隔離級別以在正確性和性能之間求取平衡。因此,并發(fā)控制技術(shù)就是一致性和隔離性之間的關(guān)聯(lián)點。

而哪些數(shù)據(jù)庫使用了兩階段鎖技術(shù)了?

MySQL的InnoDB和Informix就是這樣依靠SS2PL實現(xiàn)了序列化隔離級別,然后保證了不產(chǎn)生數(shù)據(jù)異常。

對于數(shù)據(jù)庫系統(tǒng),數(shù)據(jù)的一致性,被對應(yīng)為可串行化調(diào)度以實現(xiàn)序列化效果。所以不同的并發(fā)控制方法規(guī)定了不同的規(guī)則以保證序列化。

接下來我們再來簡略地討論一下MVCC 多版本并發(fā)控制技術(shù)。如PPT所示,MVCC通過元組,版本等來實現(xiàn)控制。

首先,每一個元組,都有一個元組頭,上面有兩個字段,begin表示元組誕生的時間,end表示元組消亡的時間。

其次,每個元組,可以有多個版本,用pointer這個指針指向不同的版本。大家看,對于名字為John的這個元組,就存在3個版本。第一個版本,生命周期在事務(wù)號為10到20之間存活;第二個版本,生命周期在事務(wù)號為20到75之間存活;第三個版本,生命周期在事務(wù)號為75到現(xiàn)在這個時間短內(nèi)存活。事務(wù)號處于不同的階段可以看到的版本是不同的。如一個事務(wù)的事務(wù)號為60,則只能看到第二個版本,不能看到其他版本。

而MVCC技術(shù)和其他的并發(fā)控制技術(shù),經(jīng)常結(jié)合起來使用,比如,這張表里列的兩種MVCC變種,分別是和基于時間戳的、基于封鎖技術(shù)的相結(jié)合的。同樣的,這些技術(shù)當(dāng)中,需要解決讀寫、寫寫等沖突以確保實現(xiàn)了序列化。數(shù)據(jù)庫經(jīng)典教材中對這樣的算法有詳細描述,講述算法如何避免數(shù)據(jù)異常如何保證序列化,我們就不再展開討論。

接下來,需要我們思考和注意的,是這樣一個問題:MVCC + 快照算作上述哪一種技術(shù)?

這樣的問題通常很少被討論,但是卻很容易讓人產(chǎn)生困惑。其實,MVCC和快照結(jié)合,是另外一種技術(shù)變種。MVCC只能表明元組有多個版本,不能保證一個事務(wù)對活動的、并發(fā)的其他事務(wù)的執(zhí)行情況進行了解。而快照正好在事務(wù)啟動時,為事務(wù)留存了一張當(dāng)前活動事務(wù)的照片,從而能夠幫助事務(wù)知道哪些事務(wù)已經(jīng)是完成的事務(wù)、哪些是正在進行的,哪些應(yīng)該是將來發(fā)生的,一張照片把事務(wù)歷史長河劃分為三個階段:過去、現(xiàn)在、未來。然后,遵守先提交者獲勝或者先更新者獲勝等的規(guī)則,可實現(xiàn)讀已提交和可重復(fù)讀隔離級別,但不能實現(xiàn)序列化,不能完全避免數(shù)據(jù)的不一致。PostgreSQL 9.2版本使用SSI技術(shù)才實現(xiàn)了真正的序列化,即完全保證了數(shù)據(jù)的一致性。

?

另外,還有其他的并發(fā)控制技術(shù),比如說,嚴(yán)格提交排序協(xié)議,簡稱為SCO。對于SS2PL,寫操作會被讀操作互斥, 所以寫只能被阻塞,處于等待狀態(tài)。而SCO則不一樣,寫操作可以繼續(xù)進行,只是在提交階段才進行檢查數(shù)據(jù)修改是否會破壞一致性。對于SCO更為詳細的內(nèi)容,大家可以查閱相關(guān)資料。

我們介紹了多種主流的并發(fā)控制技術(shù)。接下來看第四個問題:為什么并發(fā)控制技術(shù)能解決數(shù)據(jù)異?,F(xiàn)象?

首先我們來分析一下 “基于封鎖的并發(fā)控制技術(shù)”。以臟讀為例,并發(fā)事務(wù)T2施加寫鎖成功,事務(wù)T1的讀鎖則不能施加成功,事務(wù)T1和T2不能并發(fā)執(zhí)行,這樣就避免了臟讀。

再以不可重復(fù)讀為例,事務(wù)T1施加的讀鎖,事務(wù)T2的寫鎖則被排斥,只能等待。所以數(shù)據(jù)不會被修改,事務(wù)T1第二次讀到的還是沒有被修改的數(shù)據(jù),所以能夠避免不可重復(fù)讀異常,進而保證數(shù)據(jù)一致性。

封鎖并發(fā)控制技術(shù),可以用這兩張表來概括,第一張表,是并發(fā)的事務(wù)之間,鎖沖突表,表明了并發(fā)事務(wù)之間什么樣的鎖可以申請成功,即被允許并發(fā)執(zhí)行。第二張表,是同一個事務(wù)內(nèi)部,新申請的鎖是否可以升級為其他粒度的鎖。這兩張表,就是封鎖技術(shù)的核心,尤其是第一張表,把讀寫、寫讀、寫寫三種沖突情況用鎖規(guī)則固化,確保了 數(shù)據(jù)的一致性。

對于其他的并發(fā)控制技術(shù),本質(zhì)上都是定義了一些規(guī)則,用來約束并發(fā)的讀寫操作、提交順序、并決定回滾哪些事務(wù)作為犧牲者,許多書籍都有詳細討論,我們就不再進行詳細地探討。概括地說,根據(jù)數(shù)據(jù)異常現(xiàn)象,制定出一定的規(guī)則,可以確保數(shù)據(jù)的一致性,這就是并發(fā)控制技術(shù)的核心。而增加新的規(guī)則,允許部分?jǐn)?shù)據(jù)異常發(fā)生,從而產(chǎn)生了多種隔離級別。

這就是第四個問題。第三和第四個問題,我們討論了并發(fā)控制技術(shù)和這些技術(shù)能夠解決數(shù)據(jù)異?,F(xiàn)象的原因。

接下來,我們從理論回歸到工程實現(xiàn)當(dāng)中,看看主流的數(shù)據(jù)庫的并發(fā)控制技術(shù),這就是今天的第五個問題。

大家可以看這張對比表格,概括了Informix、Oracle、PostgreSQL和MySQL這四個數(shù)據(jù)庫的并發(fā)控制技術(shù)。主流的數(shù)據(jù)庫,幾乎都使用了封鎖技術(shù)和MVCC技術(shù)。只有Infomix單純地使用了封鎖技術(shù)。Oracle盡管語法上提供了序列化隔離級別的設(shè)置,但沒有提供真正的序列化隔離級別。

反倒是開源的兩個數(shù)據(jù)庫系統(tǒng),PostgreSQL和MySQL實現(xiàn)了序列化。只是MySQL是在讀數(shù)據(jù)時加鎖結(jié)合SS2PL技術(shù)實現(xiàn)了序列化,這種方式的并發(fā)度很低,性能不好。而PostgreSQL則使用SSI技術(shù)實現(xiàn)了序列化,性能相對較好。在第一個問題中我們提出了兩種寫偏序的數(shù)據(jù)異常,PostgreSQL使用SSI技術(shù),解決了寫偏序異常。如果從正確性和性能這兩個角度來衡量數(shù)據(jù)庫的并發(fā)控制技術(shù),顯然,PostgreSQL在理論上優(yōu)于MySQL,PostgreSQL采用的SSI技術(shù)復(fù)雜但高效。

接著,我們從系統(tǒng)鎖、事務(wù)鎖、事務(wù)鎖的元數(shù)據(jù)鎖和記錄元組鎖的角度詳細對比PostgreSQL和MySQL的區(qū)別,然后再從隔離級別的角度來看這兩個數(shù)據(jù)庫的并發(fā)控制技術(shù)。

首先,PostgreSQL和MySQL都提供了系統(tǒng)鎖,也都盡量利用了底層的硬件指令如TAS指令實現(xiàn)最基本的spinlock。使用操作系統(tǒng)提供的mutex來控制共享資源的并發(fā)操作。

其次,在事務(wù)鎖方面,PostgreSQL統(tǒng)一管理元數(shù)據(jù)和用戶數(shù)據(jù),而MySQL則明顯把元數(shù)據(jù)和用戶數(shù)據(jù)分開用元數(shù)據(jù)鎖和記錄鎖進行管理,并各自進行了死鎖檢測。

PostgreSQL對于元組上的并發(fā)操作,加元組鎖到元組上,把事務(wù)ID記錄在元組頭上,用快照技術(shù)判斷元組的可見性,操作結(jié)束則釋放鎖。而MySQL則是用內(nèi)存鎖表記錄元組鎖,等到事務(wù)結(jié)束后才釋放。從這點上看,SS2PL技術(shù)的實現(xiàn),在PostgreSQL和MySQL中是不同的。

從隔離級別的角度看,PostgreSQL和MySQL都采用了MVCC技術(shù)來實現(xiàn)可重復(fù)讀和讀已提交。

PostgreSQL和MySQL在并發(fā)控制技術(shù)方面最大的差別,在于對確保數(shù)據(jù)一致性的序列化的實現(xiàn)上,采取的技術(shù)不同,理論上性能不同。這就是兩者在并發(fā)控制技術(shù)方面的最大不同之處。

最后,讓我們一起來總結(jié)一下今天的分享:

首先,我們在第一個問題里講述了11種數(shù)據(jù)異?,F(xiàn)象。

然后,在第二個問題里,分析了產(chǎn)生異?,F(xiàn)象的原因。最大的原因是并發(fā)。

所以,緊下來,我們分享了消除數(shù)據(jù)異常的技術(shù),即抑制并發(fā),所以提出序列化這種可串行化技術(shù),從而帶出了隔離性以及隔離級別,這就是第三個和第四個問題所討論的各種并發(fā)控制技術(shù),本質(zhì)上就是通過定義好的規(guī)則消除并發(fā)帶來的影響。

最后的兩個問題,我們用實例研究了主流數(shù)據(jù)的并發(fā)控制實現(xiàn)技術(shù),重點講述了PostgreSQL和MySQL的并發(fā)控制技術(shù)。這就是今天所分享的六個問題的脈絡(luò)。

當(dāng)然,數(shù)據(jù)庫的并發(fā)訪問控制可以討論的話題還有很多,比如:為什么SQL標(biāo)準(zhǔn)只規(guī)定了三種讀異常?為什么主流數(shù)據(jù)庫都采用了封鎖的SS2PL協(xié)議等等。

而為了提升數(shù)據(jù)庫的性能,并發(fā)控制技術(shù)也是一個重要的點。騰訊云數(shù)據(jù)庫CDB、DCDB等后續(xù)也會在并發(fā)控制等技術(shù)上持續(xù)優(yōu)化,力爭為用戶提供高性能,高一致性數(shù)據(jù)庫服務(wù)。由于時間的關(guān)系,今天的分享就到這里,謝謝大家。也歡迎大家使用騰訊云。

分享到

zhangnn

相關(guān)推薦