PostgreSQL并發(fā)處理方式——MVCC

PostgreSQL的特色之一是它的并發(fā)控制機(jī)制蹦狂,在維護(hù)一致性和完整性的同時(shí)驻售,盡量避免讀寫的堵塞。

對于傳統(tǒng)數(shù)據(jù)庫库北,為了維護(hù)一致性和完整性,避免一個(gè)事務(wù)看到其它并發(fā)事務(wù)更新而到會不一致的數(shù)據(jù)们陆,通常采用的是LOCK機(jī)制寒瓦。這樣付出的代價(jià)是,當(dāng)鎖請求無法被響應(yīng)時(shí)坪仇,待處理的請求必須進(jìn)入等候隊(duì)列杂腰,甚至等待超時(shí)不被處理。

MVCC通過避開傳統(tǒng)數(shù)據(jù)庫的LOCK機(jī)制椅文,最大限度的減少鎖競爭以允許合理的多用戶環(huán)境中的性能颈墅。

恰當(dāng)?shù)厥褂肕VCC總會提供比LOCK更好的性能。對于那些無法輕松接收MVCC行為的應(yīng)用雾袱,PostgreSQL也提供了表和行級別的LOCK機(jī)制。

PostgreSQL存儲結(jié)構(gòu)

PostgreSQL中官还,一個(gè)表對應(yīng)一個(gè)邏輯文件芹橡,一個(gè)表被分割成若干個(gè)物理段文件(relation segment),除最后一段外默認(rèn)大小40M望伦。

文件頁(磁盤塊)是物理段文件的基本儲存單位林说,也是內(nèi)存和磁盤交換的單位煎殷。文件頁大小限制了表元組的大小并影響磁盤操作效率,缺省大小8192字節(jié)腿箩,最大可設(shè)置為2^15字節(jié)(這是由磁盤塊索引是15位決定的)豪直。

一個(gè)文件頁空間被邏輯分割為三個(gè)部分:

  • PageHeader:頁描述區(qū)
  • 記載頁的使用情況, 如頁分布格式版本,元組數(shù)據(jù)空間和特殊空間的起始位置以及文件頁相關(guān)的事務(wù)日志記載點(diǎn)等信息
  • Tuple Item space:元組數(shù)據(jù)空間
  • 實(shí)際記錄元組數(shù)據(jù)的地方
  • Special space:特殊空間

每個(gè)記錄的元組(Tuple)稱為一項(xiàng)珠移,每項(xiàng)由描述ID和元組數(shù)據(jù)構(gòu)成弓乙。
項(xiàng)描述ID描述了元組存儲位置,大小以及一些狀態(tài)標(biāo)識钧惧。
項(xiàng)描述ID和項(xiàng)數(shù)據(jù)分別在元組數(shù)據(jù)空間的兩頭往中間存放暇韧,最早的項(xiàng)存在最兩側(cè),越晚的數(shù)據(jù)越靠中間浓瞪。

PostgreSQL文件頁分布.PNG

元組的寫過程:先寫到文件頁的內(nèi)存緩沖區(qū)(Buffer)懈玻,再更新到磁盤中

  • 從緩沖頁的元組數(shù)據(jù)存儲區(qū)分配空間
  • 構(gòu)造元組描述ID,寫入低端處
  • 把實(shí)際數(shù)據(jù)寫到高端處乾颁,并設(shè)置緩沖區(qū)的臟標(biāo)記
  • 更新到磁盤
  • 寫元組不會立即更新到磁盤涂乌,而是推遲到所在的緩沖區(qū)被替換(Replace)時(shí)進(jìn)行
  • Replace時(shí),判斷緩沖區(qū)是否臟:
  • 如果臟英岭,啟動實(shí)際磁盤IO進(jìn)行寫湾盒;
  • 如果不臟,直接回收再用該Buffer巴席。

文件頁的寫過程:

  • 先更新該文件頁的事務(wù)日志历涝,事務(wù)日志由頁頭部的頁描述符指出
  • 把文件緩沖頁寫到指定磁盤塊

MVCC

MVCC(Multiversion Concurrency Control),多版本并發(fā)控制漾唉。

舉一個(gè)簡單的例子來理解它的機(jī)制

inset into T1(id,name) values (1,'zhangsan');
updata T1 set name = 'lisi' where id =1;
Paste_Image.png
  • 每個(gè)事務(wù)都會得到一個(gè)XID(稱為事務(wù)ID)荧库,當(dāng)一個(gè)新事務(wù)開始,遞增XID赵刑,然后把它賦予這個(gè)新事務(wù)分衫。
  • 把一個(gè)元組(Tuple)稱作同一邏輯行的一個(gè)行版本,數(shù)據(jù)文件中存放同一邏輯行的多個(gè)行版本
  • 每個(gè)行版本的頭部般此,記錄該行版本的創(chuàng)建和刪除的事務(wù)ID(分別稱為xmin和xmax)
  • 每個(gè)事務(wù)的狀態(tài)(running, abort 或 commit)記錄在pg_clog文件中
  • 運(yùn)用一定的規(guī)則蚪战,使每個(gè)事務(wù)只會看到一個(gè)特定的行版本(快照)

舉個(gè)例子,當(dāng)insert一行記錄時(shí)铐懊,只有那些已提交的邀桑、并且xmin比當(dāng)前事務(wù)XID小(xmin<XID) 的行記錄 對當(dāng)前事務(wù)才是可見的科乎。

這意味著你可以創(chuàng)建一個(gè)新事務(wù)然后插入記錄壁畸,直到commit之前,這些記錄對其他事務(wù)永遠(yuǎn)都是不可見的;commit之后捏萍,其他后創(chuàng)建的新事務(wù)就可看到這行新記錄了(xmin<XID)太抓。

對于deleteupdate,機(jī)制也是類似的令杈,不同的是要用xmax值來判斷數(shù)據(jù)的可見性走敌。

隔離級別

SQL標(biāo)準(zhǔn)定義了四個(gè)級別的事務(wù)隔離。最嚴(yán)格的是可串行化逗噩,是通過標(biāo)準(zhǔn)定義掉丽,即保證并發(fā)執(zhí)行和順序執(zhí)行的結(jié)果相同;其他三個(gè)級別是通過現(xiàn)象定義的给赞。

隔離級別 臟讀 不可重復(fù)讀 幻讀
讀未提交(read uncommitted)
讀已提交(read committed) 避免
可重復(fù)讀(repeatable read) 避免 避免
可串行化(serializable) 避免 避免 避免
  • 幻讀:重新執(zhí)行一個(gè)查詢机打,由于最近另一個(gè)事務(wù)的提交,返回的結(jié)果(一批數(shù)據(jù))和剛才不同片迅;
  • 不可重復(fù)讀: 針對同一個(gè)數(shù)據(jù)残邀,一個(gè)事務(wù)內(nèi)多次查詢,由于期間另一個(gè)事務(wù)的提交柑蛇,導(dǎo)致結(jié)果(同一個(gè)數(shù)據(jù))不同芥挣;
  • 臟讀:一個(gè)事務(wù)讀取了另一個(gè)事務(wù)還未提交的改動。

PostgreSQL中:

  • 默認(rèn)隔離級別是讀已提交(read committed)耻台;
  • 可以請求四中級別的任意一種空免,但對于內(nèi)部其實(shí)只有讀已提交、可重復(fù)讀盆耽、可串行化三種級別蹋砚;
  • 選擇讀未提交時(shí),實(shí)際上用的是讀已提交摄杂;
  • 選擇重復(fù)讀時(shí)坝咐,不會發(fā)生幻讀;

SQL標(biāo)準(zhǔn)只定義了那種現(xiàn)象不能發(fā)生析恢,但是沒定義哪種現(xiàn)象一定發(fā)生墨坚。

  • 讀已提交
  • BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • PostgreSQL里的缺省隔離級別
  • 看到的是當(dāng)前查詢開始時(shí)的快照
  • 當(dāng)有兩個(gè)事務(wù)同時(shí)修改同一行數(shù)據(jù)時(shí),后發(fā)生的事務(wù)在初始事務(wù)提交前就可以進(jìn)行查找映挂,然后不執(zhí)行進(jìn)入等待泽篮,待初始事務(wù)提交后retry,檢驗(yàn)查找條件是否仍然滿足柑船,如果滿足帽撑,后續(xù)操作才會被執(zhí)行;
  • 例如下圖中的例子:
    在事務(wù)1提交之前鞍时,通常LOCK機(jī)制會讓事務(wù)2進(jìn)入等待油狂,到事務(wù)1提交后才可以掃描查找;
    而MVCC允許事務(wù)2在事務(wù)1提交之前就可以進(jìn)行掃描查找工作,當(dāng)事務(wù)1提交之后专筷,事務(wù)2retry,檢驗(yàn)where條件是否仍然滿足蒸苇;
    若不滿足磷蛹,則不會執(zhí)行任何操作(保證了一致性);
    若滿足溪烤,則相比LOCK機(jī)制節(jié)省了掃描查找所消耗的時(shí)間(在LOCK機(jī)制等待commit時(shí)MVCC就開始掃描查找了)味咳。
讀已提交
  • 可重復(fù)讀
  • BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  • 看到的是當(dāng)前事務(wù)開始時(shí)的快照
  • 使用這個(gè)級別需要準(zhǔn)備好重試事務(wù),因?yàn)榇谢赡苁?/li>
  • 在第二張圖的例子中檬嘀,按照一般的LOCK機(jī)制槽驶,在可重復(fù)讀的級別下,在事務(wù)B提交后鸳兽,查詢結(jié)果應(yīng)該不同(即幻讀)掂铐,但是在MVCC機(jī)制中,查詢結(jié)果是相同的(幻讀也被避免了)
可重復(fù)讀
幻讀被避免
  • 可串行化
  • BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • 是嚴(yán)格意義上的可串行化
  • 可重復(fù)讀級別已經(jīng)避免了幻讀揍异,達(dá)到了SQL標(biāo)準(zhǔn)約定的“可串行化標(biāo)準(zhǔn)”全陨,但能避免幻讀并不等于嚴(yán)格意義上的可串行化
  • 在這種策略下,不同事務(wù)同時(shí)修改同一數(shù)據(jù)的行為會直接失敗衷掷,并返回錯(cuò)誤信息
  • 需要準(zhǔn)備好重啟事務(wù)
直接失敗

MVCC實(shí)現(xiàn)方法

MVCC的實(shí)現(xiàn)方法有兩種:

  • 寫新數(shù)據(jù)是辱姨,把舊數(shù)據(jù)移到一個(gè)專門的地方(如回滾段),其他人讀數(shù)據(jù)時(shí)戚嗅,從回滾段中把舊數(shù)據(jù)讀出來
  • 寫數(shù)據(jù)時(shí)雨涛,舊數(shù)據(jù)不刪除,把新數(shù)據(jù)插入

PostgreSQL使用的是第二種方法懦胞,Oracle數(shù)據(jù)庫和MySQL innodb引擎使用一種

比較:

  • 優(yōu)點(diǎn):
  • 回滾可以立刻完成替久,無論進(jìn)行了多少操作
  • 數(shù)據(jù)可以進(jìn)行逆很多更新,不必?fù)?dān)心需要保證回滾段不被用完
  • 缺點(diǎn):
  • 舊版本數(shù)據(jù)需要清理
  • 舊版本數(shù)據(jù)過多導(dǎo)致查詢變慢

存在的問題及解決方法

MVCC實(shí)現(xiàn)了一種期待:讀永遠(yuǎn)不堵塞寫医瘫。但是也帶來了一些問題:

  1. 因?yàn)椴煌氖聞?wù)會看到不同版本的記錄侣肄,所以PostgreSQL連那些可能過期的數(shù)據(jù)也要保留著;
    當(dāng)UPDATA時(shí)醇份,真正地創(chuàng)建了一行新記錄稼锅,而DELETE時(shí),并不會真正地刪除一行舊記錄僚纷;
    最終數(shù)據(jù)庫中會存在一些對有事務(wù)永遠(yuǎn)不可見的記錄矩距,稱作dead rows。
  2. 事務(wù)ID只能增加怖竭,它是個(gè)32bit锥债,支持大約40億個(gè)事務(wù),達(dá)到最大值會從0重新開始;
    這樣帶來一個(gè)邏輯問題:突然所有記錄都變成了發(fā)生在將來的事務(wù)所產(chǎn)生的哮肚,而所有新事物也都沒有辦法訪問這些舊記錄了登夫。
  • 解決方法:VACUUM
    PostgreSQL自帶了auto_vacuum守護(hù)進(jìn)程會在一個(gè)可配置的周期內(nèi)自動執(zhí)行清理,解決了這兩個(gè)問題允趟;
    使用者需要留意這個(gè)auto_vacuum恼策,以免發(fā)生不想要的結(jié)果;
    vacuum命令也可以手動執(zhí)行潮剪。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涣楷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子抗碰,更是在濱河造成了極大的恐慌狮斗,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弧蝇,死亡現(xiàn)場離奇詭異碳褒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)捍壤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門骤视,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鹃觉,你說我怎么就攤上這事专酗。” “怎么了盗扇?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵祷肯,是天一觀的道長。 經(jīng)常有香客問我疗隶,道長佑笋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任斑鼻,我火速辦了婚禮蒋纬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坚弱。我一直安慰自己蜀备,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布荒叶。 她就那樣靜靜地躺著碾阁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪些楣。 梳的紋絲不亂的頭發(fā)上脂凶,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天宪睹,我揣著相機(jī)與錄音,去河邊找鬼蚕钦。 笑死亭病,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嘶居。 我是一名探鬼主播命贴,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼食听!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起污茵,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤樱报,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泞当,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迹蛤,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年襟士,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盗飒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陋桂,死狀恐怖逆趣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嗜历,我是刑警寧澤宣渗,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站梨州,受9級特大地震影響痕囱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜暴匠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一鞍恢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧每窖,春花似錦帮掉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至崇败,卻和暖如春盅称,著一層夾襖步出監(jiān)牢的瞬間肩祥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工缩膝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疾层。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓将饺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親痛黎。 傳聞我的和親對象是個(gè)殘疾皇子予弧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容