程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> 其他數據庫知識 >> PostgreSQL >> 深入理解PostgreSQL的MVCC並發處理方式

深入理解PostgreSQL的MVCC並發處理方式

編輯:PostgreSQL

Postgre數據庫的很大的賣點之一就是它處理並發的方式。我們的期望很簡單:讀永遠不阻塞寫,反之亦然。Postgres通過一個叫做 多版本並發控制(MVCC) 的機制做到了這一點。這個技術並不是Postgres所特有的:還有好幾種數據庫都實現了不同形式的MVCC,包括 Oracle、Berkeley DB、CouchDB 等等 。當你使用PostgreSQL來設計高並發的應用時,理解它的MVCC是怎麼實現的很重要。它事實上是復雜問題的一種非常優雅和簡單的解法。

MVCC如何工作

在Postgres中,每一個事務都會得到一個被稱作為 XID 的事務ID。這裡說的事務不僅僅是被 BEGIN - COMMIT 包裹的一組語句,還包括單條的insert、update或者delete語句。當一個事務開始時,Postgrel遞增XID,然後把它賦給這個事務。Postgres還在系統裡的每一行記錄上都存儲了事務相關的信息,這被用來判斷某一行記錄對於當前事務是否可見。

舉個例子,當你插入一行記錄時,Postgre會把當前事務的XID存儲在這一行中並稱之為 xmin 。只有那些*已提交的而且 xmin` 比當前事務的XID小的記錄對當前事務才是可見的。這意味著,你可以開始一個新事務然後插入一行記錄,直到你提交( COMMIT )之前,你插入的這行記錄對其他事務永遠都是不可見的。等到提交以後,其他後創建的新事務就可以看到這行新記錄了,因為他們滿足了 xmin < XID 條件,而且創建哪一行記錄的事務也已經完成。

對於 DELETE 和 UPDATE 來說,機制也是類似的,但不同的是對於它們Postgres使用叫做 xmax 的值來判斷數據的可見性。這幅圖展示了在兩個並發的插入/讀取數據的事務中,MVCC在事務隔離方面是怎麼起作用的。

在下面的圖中,假設我們先執行了這個建表語句:
復制代碼 代碼如下:CREATE TABLE numbers (value int);

雖然 xmin 和 xmax 的值在日常使用中都是被隱藏的,但是你可以直接請求他們,Postgres會高興的把值給你:
復制代碼 代碼如下:SELECT *, xmin, xmax FROM numbers;
獲取當前事務的XID也很簡單:
復制代碼 代碼如下:SELECT txid_current();

干淨利落!

我知道你現在在想:要是同時有兩個事務修改同一行數據會怎麼樣?這就是事務隔離級別(transaction isolation levels)登場的時候了。Postgres支持兩個基本的模型來讓你控制應該怎麼處理這樣的情況。默認情況下使用 讀已提交(READ COMMITTED) ,等待初始的事務完成後再讀取行記錄然後執行語句。如果在等待的過程中記錄被修改了,它就從頭再來一遍。舉一個例子,當你執行一條帶有 WHERE 子句的 UPDATE 時, WHERE 子句會在最初的事務被提交後返回命中的記錄結果,如果這時 WHERE 子句的條件任然能得到滿足的話, UPDATE 才會被執行。在下面這個例子中,兩個事務同時修改同一行記錄,最初的 UPDATE 語句導致第二個事務的 WHERE 不會返回任何記錄,因此第二個事務根本沒有修改到任何記錄:

如果你需要更好的控制這種行為,你可以把事務隔離級別設置為 可串行化(SERIALIZABLE) 。在這個策略下,上面的場景會直接失敗,因為它遵循這樣的規則:“如果我正在修改的行被其他事務修改過的話,就不再嘗試”,同時 Postgres會返回這樣的錯誤信息: 由於並發修改導致無法進行串行訪問 。捕獲這個錯誤然後重試就是你的應用需要去做的事情了,或者不重試直接放棄也行,如果那樣合理的話。

MVCC的缺點

現在你已經知道MVCC和事務隔離是怎麼工作了吧,你獲得了又一個工具用來解決這類問題: 可串行化事務隔離級別 遲早會派上用場。然而MVCC的優點雖然很明顯但它也存在著一些缺點。

因為不同的事務會看到不同狀態的記錄,Postgres連那些可能過期的數據也需要保留著。這就是為什麼 UPDATE 實際上是創建一行新紀錄而 DELETE 並不真正的刪除記錄(它只是簡單的把記錄標記成已刪除然後設置XID的值)的原因。當事務完成後,數據庫裡會存在一些對以後的事務永遠不可見的記錄。它們被稱作dead rows。MVCC帶來的另外一個問題是,事務的ID只能不斷的增加 - 它是32個bits,只能”支持大約四十億個事務。當XID達到最大值後,它會變回零重新開始。突然間所有的記錄都變成了發生在將來的事務所產生的,所有的新事務都沒有辦法訪問到這些舊記錄了。

上面說到的dead row和事務XID循環問題都是通過執行VACUUM命令(Postgres用來執行清理操作的命令)來解決的。這應該成為一個例行的維護,所以Postgre自帶了auto_vacuum守護進程會在一個可配置的周期內自動執行清理。留意點auto_vacuum很重要,因為在不同的部署環境中需要執行清理的周期也會不同。你可以在Postgres的文檔裡找到關於VACUUM的更多說明。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved