資料複製的併發控制

chuanzhongdu1發表於2011-07-22

資料分佈通常應用在高效能運算(HPC)中。資料分佈拓撲主要有兩種:複製和分割槽。

 

在資料複製環境中,一個資料項往往有好幾個副本,但應該保證一定程度的資料一致性,好讓終端使用者看起來全域性只有一份資料。使用資料複製最大的挑戰就是根據業務需求在資料一致性和效能之間做出正確的權衡。

要實現資料一致性,通常會運用一些併發控制方案。本文將解釋Oracle10g高階複製 、Oracle10g真正應用叢集(RAC) 、記憶體資料庫(IMDB)Oracle10g TimesTen 、Gigaspaces記憶體資料網格(IMDG)7.1 裡複製所涉及的併發控制。

討論過程中我們使用一個分散式航空訂票系統為例,後面簡稱為DATS。為了具備高可用性和負載均衡,DATS有兩個資料庫:一個在紐約、一個在洛杉磯。根據複製方案,資料只能在一個地方更新,然後複製到另一個地方;或者兩個地方都更新,然後互相複製。

此外,假設以下動作會按時間順序發生:

  1. 兩個本地資料庫副本此刻已經同步,只剩下一張機票。僅剩的這張票在紐約或洛杉磯都可以預定;
  2. 一位紐約客戶購買了這張票。這個動作會更新紐約本地的資料庫,並且會按照複製方案以某種方式複製到洛杉磯的資料庫裡去;
  3. 根據複製方案,洛杉磯資料庫也許顯示那張票仍然可以購買,也許顯示已經被紐約使用者預定了。要是洛杉磯資料庫仍然顯示這張票在售,那這張票就會被賣給一位洛杉磯顧客。這就會出現超賣的情況。

由於DATS在廣域網環境只適合非同步複製,在同步複製環境裡,DATS應該作如下變化(下稱“DATS改”):我們假設紐約有第二個資料庫,和第一個資料庫在同一個資料中心裡,這個資料庫將取代洛杉磯的資料庫。

我們還假設DATS使用了樂觀併發控制機制。下面是樂觀併發控制在DATS裡的工作原理:

為了具備良好的效能,大部分多層應用都使用樂觀併發控制,這會帶來更新丟失的問題。比如說,如果我們在DATS的兩個資料庫中使用樂觀併發控制,步驟三的應用層有可能先於步驟二讀取洛杉磯的資料庫,卻在步驟二之後才把那張票賣給一位洛杉磯顧客。

應用必須使用“帶有版本檢查的樂觀併發控制”來解決這個問題。版本檢查方案可以只是一個版本號,只要有相應的資料變化,版本號就加一。

假設步驟一的版本是0。步驟二將版本更新為1。步驟三的應用層讀到的版本也是0。但在應用層試圖出售同一張票的時候,步驟三會失敗,因為它會發現版本已經從快取裡的0變成1了。

1.使用分散式鎖和本地事務的同步複製

Oracle RAC在8i及以前的版本中被稱為Oracle並行伺服器(OPS),它允許多個例項站點訪問同一個物理資料庫。為了讓使用者在任何時候、任何例項站點都能讀取、寫入任何資料,Oracle RAC使用“快取融合(Cache Fusion)” 來保證資料的一致性。

“快取融合”主要使用帶有分散式鎖管理器(DLM) 的同步複製。DLM的功能之一是扮演分散式鎖(DL)的協調員,使同一個資源(比如表的一行)一次只能被一個例項站點修改,其它站點必須等待。

DLM還是全域性資源目錄。舉例來說,當例項站點1更新了一行內容,它並不需要主動把新版本的資料推送給其他例項站點。相反,它只需要把其他副本置為無效就可以了。當例項站點2稍後請求同一行內容時,DLM會讓它從例項站點1獲取最新的版本。

此外,由於有DLM,而且仍然只有一個物理資料庫,例項站點1並不需要使用分散式事務。

這樣做的優點是有了高度的資料一致性,讀取和寫入也都有高度的負載均衡(通常來說,同步複製不會對寫入操作進行均衡,因為相同的寫入會在所有站點之間進行復制。但有了RAC輕量級的失效機制,寫入操作也會進行相對的均衡)。

缺點則是寫入效能不能伸縮(即使失效機制很輕量,但太多的失效仍然會阻塞共享互連;所以RAC的寫操作仍然無法伸縮),由於複製同步和分散式鎖,這 種做法也滿足不了高可用和快速互連的需求(分散式鎖的實現通常在每個站點都有很多守護程式和資料結構,在低速的區域網和廣域網上,分散式鎖的協調能力會很 差甚至不可能完成協調。至於Oracle的快取融合,分散式鎖是在叢集環境中用全域性快取服務(GCS)、全域性佇列服務(GES)和全域性資源目錄(GRD) 實現的)。

你應該會注意到,這種方案是RAC獨有的。如果你有不止一個個帶事務的資料來源,使用本地事務有時候會導致資料的不一致。不管怎麼說,同時使用分散式鎖和分散式事務實現同步複製,即便分散式事務能保證資料的原子性,用起來也會非常昂貴。我至今都沒見過使用這種方案的產品。

由於同步複製不太現實,在廣域網甚至不太可能,這種方案只能應用於“DATS改”。步驟三必須等待步驟二釋放分散式鎖。當步驟三獲得分散式鎖之後,會看到那張票在步驟二已經售出。

2.使用本地鎖和分散式事務的同步複製

Oracle的多主複製也稱為peer-to-peer複製或n-way複製,它有兩種資料一致性協議,一是同步複製,另一種在第四節進行闡述。

同步複製在一次分散式事務 中,將待執行的DML修改或複製過程應用到參與複製環境的所有站點(每個站點都有自己的物理資料庫,這是與Oracle RAC的不同之處,RAC只有一個物理資料庫)。如果DML語句或過程在任意一個站點失敗了,那整個事務都會回滾。

分散式事務能實時確保所有站點上的資料一致性。但它並不使用任何分散式鎖。相反,它只在本地事務的參與者中使用本地鎖。

應用對一個被複制的表執行同步更新,就是這種情況。Oracle首先會鎖定本地的那一行,然後用After行觸發器鎖定對應的遠端行。所有站點都提 交事務後,Oracle會釋放鎖。可以想象,如果多個站點要同時修改同一個資源,就會出現死鎖。除此之外,同一個資源每次只能由一個例項站點進行修改,其 它站點則必須等待。

這種方案的優點是避開了分散式鎖,具備高度的資料一致性,實現簡單且易於管理。

這麼做的缺點則是,本地和遠端短暫的鎖定可能會帶來死鎖問題,還有比較差的寫入效能,而且需要高可用性和高速的網路,因為分散式事務需要複製同步性和兩階段提交(2PC)。

高併發情況下死鎖會是很嚴重的問題。發生死鎖的時候,Oracle會回滾非法的那個事務,保持另一個。回滾的事務會給前端應用返回一個錯誤碼。

由於第一節提到的原因,這個方案只適用於“DATS改”。步驟三必須等待步驟二釋放本地和遠端的鎖。步驟三拿到鎖之後,會看到那張票已在步驟二售出。

3.使用本地鎖和本地事務的同步複製

TimesTen的單向Active Standby Pair配置只使用了所謂的“return twosafe複製”。它支援主站點(活動站點)和訂閱站點(備用站點)之間完全同步的複製。

TimesTen不涉及分散式事務或分散式鎖。只使用本地事務和本地鎖。具體來說,主站點的事務提交之前,會先提交訂閱站點的本地事務。如果訂閱站點不能提交,主站點也不會提交。

任何時候都只能更新活動站點,這大大簡化了資料更新的複雜度(否則的話,使用本地鎖和本地事務都還不夠),也確保了在活動站點失效的情況下,能快速失效轉移到備用站點上。

這個方案的優缺點和第二節那個方案的優缺點類似。

不過它的效能要更好一些,因為它規避了分散式事務所需的兩階段提交。由於只允許活動站點進行更新,這個方案也消除了死鎖問題。

雖然備用站點看起來是一種功能浪費,但你可以把備用站點和另一個活動站點放在一起,如圖1所示(尤其是活動站點和相搭配的備用站點有著不同的資料)。

這個方案的資料一致性並不是很高,因為主站點若是提交失敗,即便訂閱站點提交成功了,也會導致不一致性(根本原因是這個方案沒有使用分散式事務。但你也應該知道,兩階段提交的第二次提交或回滾階段要是失敗了,也會導致暫時的資料不一致)。

TimesTen在這個地方的做法,延續了他們在非同步日誌記錄、使用後寫策略的資料快取等方面偏重高效能的配置思路。Gigaspaces IMDB採用了一種非常類似的拓撲結構,叫做主-備份複製。唯一的區別在於,Gigaspaces IMDB使用了分散式事務,而不僅僅是本地事務。所以和TimesTen比起來,Gigaspaces IMDB有更高的資料一致性。

使用Gigaspaces IMDB的另一個好處是,Gigaspaces IMDB的失效轉移對終端使用者來說是透明的,而TimesTen的使用者仍然需要求助於第三方或定製的叢集管理軟體。

由於第一節提到的原因,這個方案只能應用於“DATS改”。位於紐約的兩個站點,其一是活動站點,另一個則是備用站點要連線到活動站點上更新資料。活動站點上的本地鎖會防止超賣的情況發生。

和前面兩個同步方案相比,強烈建議使用這個方案和圖1所示的資料分割槽,原因有:

  • 這個方案大大簡化了資料更新的複雜性,同時還提供了高可用性;
  • 儘管前兩個同步方案允許在任何地方更新資料,但更新同一個資源意味著需要網路上的鎖協調和分散式事務。可伸縮的更新通常通過資料分割槽來實現;
  • 雖然前兩個同步方案允許分散式和可伸縮的讀取操作,但你仍然可以對分割槽進行微調,允許更多的併發讀取。


圖1:Gigaspaces IMDB中的主-備份分割槽

4.隨處更新的非同步複製

Oracle多主複製的另一種資料一致性協議是非同步複製,非同步複製允許使用者在任何參與站點更新資料。這個方案也用在Oracle的可更新物化檢視複製和TimesTen雙向的主-訂閱者複製中,處理一般的分散式工作負載。

使用這個方案,一個站點上的資料變化會在本地提交,並儲存在佇列中,以便傳遞到其他站點。佇列中的變化會在一個獨立事務裡分批傳遞,所以它不需要使用分散式鎖或分散式事務。相反,它只在相應的本地事務中使用所需的本地鎖。

這個方案具備良好的讀寫效能、易於實現、適用於低速的區域網和廣域網,適用於網路斷開的更新。特別是廣域網部署能讓地理分散的資料中心的做到真正災難恢復。

缺點則是資料一致性取決於資料重新整理的頻率,比較有限,而且可能會有資料變更衝突。

由於不涉及分散式鎖或分散式事務,如果不同站點發起的兩個事務差不多同時去更新同一行內容,就會出現複製衝突。(當佇列裡的更改傳播到另一個站點的時候,另一個站點上的資料變更會有兩個版本。在這種情況下,應用需要決定應該用哪一個。)

必須提供解決衝突的方法來處理資料的不一致性。Oracle和TimesTen都預置了一個“最新時間戳”的解決方法,以時間戳最新的修改為準。Oracle還允許你根據業務需求定製解決方法。

要是DATS不允許出現超賣情況,這個方案就不適用於DATS,因為紐約站點和洛杉磯站點的變更可以在兩個不同的事務中單獨提交,這會導致兩名顧客購買同一張票。

如果允許偶爾出現超賣情況,紐約站點和洛杉磯站點可以利用三小時的時差在不同時間出售機票。要真的出現複製衝突,應該根據前端應用採取的措施把相關資訊記錄到資料庫中(現實裡的預訂系統並不會採用這種方案)。

5.只更新主站點的非同步複製

Oracle的只讀物化檢視複製、TimesTen的單向主-訂閱者複製、Gigaspaces IMDB的主-本地複製都使用了這種方案。

籠統地說,當你使用樂觀鎖建立多個資料庫會話的時候,就等於用了這個方案。首先在一個會話裡進行查詢,返回的實際上是資料庫主資料的副本。接著當你要儲存所作的更改,就把它們持久化到後端的資料庫中。

由於只在主站點進行變更,所以分散式鎖和分散式事務根本用不上。這個方案的利弊和第四節介紹的方案類似。不過鑑於只允許在主站點進行更新,這就消除了臭名昭著的複製衝突,在非同步複製環境中,這個設計在大部分情況下都是非常完善的。

我們要是在原始DATS設計裡採用這個方案,並假設紐約站點或有第三個站點充當主站點的話,如果洛杉磯首先獲得了主站點的本地鎖,紐約站點就必須等待。主站點的本地鎖會防止超賣的情況發生。

和第三節結尾處討論的內容類似,推薦採用本方案時同時採用資料分割槽。DATS可以通過分割槽得到增強,例如讓紐約負責東海岸的航班、洛杉磯負責西海岸的航班。

使用圖2所示的Gigaspaces IMDB主-本地拓撲結構能讓事情變得更加簡單,因為這種拓撲能自動把本地快取更新到主站點,主站點則會把同樣的更新再傳播到其他本地快取裡。Gigaspaces IMDB也支援版本化的樂觀鎖。

不論你使用Oracle的只讀物化檢視複製,還是TimesTen的單向主-訂閱者複製,你都要自己處理這些問題。


圖2:Gigaspaces的主-本地拓撲,圖1的內容可以充當主站點

6.結論

資料複製大致可分為同步和非同步。同步複製能確保高度的資料一致性,但需要昂貴的高可用性和高速網路。同步複製通常用來保護關鍵任務的資料,比如金融業的資料。

非同步複製提供了更好的寫入伸縮性,但會降低資料一致性的程度。通常用非同步複製均衡寫入操作、提供災難恢復。

每種複製類別都有好幾種方案,提供不同的併發控制。即便合適的方案取決於特定的業務需求,我們還是建議使用第三節和第五節討論的方案。

最後,讀者朋友應該注意兩點內容:一是還有一些有趣的複製方案這裡並沒有提及。比如用TimesTen的“return receipt複製”和MySQL 5.5 實現的“半同步複製”,還有Gigaspaces資料後寫功能 對同非同步複製的結合採用。

另一個需要注意的是NoSQL 目前的發展趨勢。由於大部分NoSQL產品都自誇有可伸縮的能力,而且都假設失敗必然發生,所以他們依靠資料複製 來保證讀寫操作的負載均衡和高可用性。本文只會提到三個比較典型的NoSQL實現。

CouchDB 構建在Erlang OTP平臺上,藉助雙向的非同步增量複製,CouchDB允許進行分散式、甚至是連線斷開的文件更新。

Cassandra 允許跨資料中心的複製,也提供了不同程度的資料一致性。

最後,Gigaspaces作為IMDB執行,依靠複製實現高可用性和後寫功能,降低了傳統關聯式資料庫的重要性。除了原有的鍵值對映介面,最新的8.0版本還支援一種新的文件介面。

原文地址:http://www.infoq.com/cn/minibooks/architect-july-10-2011

相關文章