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

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

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

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

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

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

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

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

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

這三個(gè)讀異常現(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存入銀行的錢,丟失了,因?yàn)閹け旧现挥浿谝徊绞聞?wù)T1讀取的數(shù)據(jù)值。這就是寫數(shù)據(jù)發(fā)生的數(shù)據(jù)不一致的現(xiàn)象。

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

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

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

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

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

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

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

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

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

?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

?

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

我們介紹了多種主流的并發(fā)控制技術(shù)。接下來看第四個(gè)問題:為什么并發(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ù)不會(huì)被修改,事務(wù)T1第二次讀到的還是沒有被修改的數(shù)據(jù),所以能夠避免不可重復(fù)讀異常,進(jìn)而保證數(shù)據(jù)一致性。

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

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

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

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

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

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

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

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

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

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

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

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

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

首先,我們?cè)诘谝粋€(gè)問題里講述了11種數(shù)據(jù)異?,F(xiàn)象。

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

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

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

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

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

分享到

zhangnn

相關(guān)推薦