Ⅰ 分布式存儲中,怎樣使用paxos演算法保證數據的一致性
在分布式系統中,我們經常遇到多數據副本保持一致的問題,在我們所能找到的資料中該問題講的很籠統,模模糊糊的,把多個問題或分類糅合在一起,難以理解。在思考和翻閱資料後,通俗地把一致性的問題可分解為2個問題:
1、任何一次修改保證數據一致性。
2、多次數據修改的一致性。
在弱一致性的演算法,不要求每次修改的內容在修改後多副本的內容是一致的,對問題1的解決比較寬松,更多解決問題2,該類演算法追求每次修改的高度並發性,減少多副本之間修改的關聯性,以獲得更好的並發性能。例如最終一致性,無所謂每次用戶修改後的多副本的一致性及格過,只要求在單調的時間方向上,數據最終保持一致,如此獲得了修改極大的並發性能。
在強一致性的演算法中,強調單次修改後結果的一致,需要保證了對問題1和問題2要求的實現,犧牲了並發性能。本文是討論對解決問題1實現演算法,這些演算法往往在強一致性要求的應用中使用。
解決問題1的方法,通常有兩階段提交演算法、採用分布式鎖服務和採用樂觀鎖原理實現的同步方式,下面分別介紹這幾種演算法的實現原理。
兩階段提交演算法
在兩階段提交協議中,系統一般包含兩類機器(或節點):一類為協調者(coordinator),通常一個系統中只有一個;另一類為事務參與者(participants,cohorts或workers),一般包含多個,在數據存儲系統中可以理解為數據副本的個數。兩階段提交協議由兩個階段組成,在正常的執行下,這兩個階段的執行過程如下所述:
階段1:請求階段(commit-request phase,或稱表決階段,voting phase)。
在請求階段,協調者將通知事務參與者准備提交或取消事務,然後進入表決過程。在表決過程中,參與者將告知協調者自己的決策:同意(事務參與者本地作業執行成功)或取消(本地作業執行故障)。
階段2:提交階段(commit phase)。
在該階段,協調者將基於第一個階段的投票結果進行決策:提交或取消。當且僅當所有的參與者同意提交事務協調者才通知所有的參與者提交事務,否則協調者將通知所有的參與者取消事務。參與者在接收到協調者發來的消息後將執行響應的操作。
舉個例子:A組織B、C和D三個人去爬長城:如果所有人都同意去爬長城,那麼活動將舉行;如果有一人不同意去爬長城,那麼活動將取消。用2PC演算法解決該問題的過程如下:
首先A將成為該活動的協調者,B、C和D將成為該活動的參與者。
階段1:A發郵件給B、C和D,提出下周三去爬山,問是否同意。那麼此時A需要等待B、C和D的郵件。B、C和D分別查看自己的日程安排表。B、C發現自己在當日沒有活動安排,則發郵件告訴A它們同意下周三去爬長城。由於某種原因,D白天沒有查看郵件。那麼此時A、B和C均需要等待。到晚上的時候,D發現了A的郵件,然後查看日程安排,發現周三當天已經有別的安排,那麼D回復A說活動取消吧。
階段2:此時A收到了所有活動參與者的郵件,並且A發現D下周三不能去爬山。那麼A將發郵件通知B、C和D,下周三爬長城活動取消。此時B、C回復A「太可惜了」,D回復A「不好意思」。至此該事務終止。
兩階段提交演算法在分布式系統結合,可實現單用戶對文件(對象)多個副本的修改,多副本數據的同步。其結合的原理如下:
1、客戶端(協調者)向所有的數據副本的存儲主機(參與者)發送:修改具體的文件名、偏移量、數據和長度信息,請求修改數據,該消息是1階段的請求消息。
2、存儲主機接收到請求後,備份修改前的數據以備回滾,修改文件數據後,向客戶端回應修改成功的消息。 如果存儲主機由於某些原因(磁碟損壞、空間不足等)不能修改數據,回應修改失敗的消息。
3、客戶端接收發送出去的每一個消息回應,如果存儲主機全部回應都修改成功,向每存儲主機發送確認修改的提交消息;如果存在存儲主機回應修改失敗,或者超時未回應,客戶端向所有存儲主機發送取消修改的提交消息。該消息是2階段的提交消息。
4、存儲主機接收到客戶端的提交消息,如果是確認修改,則直接回應該提交OK消息;如果是取消修改,則將修改數據還原為修改前,然後回應取消修改OK的消息。
5、 客戶端接收全部存儲主機的回應,整個操作成功。
在該過程中可能存在通信失敗,例如網路中斷、主機宕機等諸多的原因,對於未在演算法中定義的其它異常,都認為是提交失敗,都需要回滾,這是該演算法基於確定的通信回復實現的,在參與者的確定回復(無論是回復失敗還是回復成功)之上執行邏輯處理,符合確定性的條件當然能夠獲得確定性的結果哲學原理。
分布式鎖服務
分布式鎖是對數據被外界修改持保守態度,在整個數據處理過程中將數據處於鎖定狀態,在用戶修改數據的同時,其它用戶不允許修改。
採用分布式鎖服務實現數據一致性,是在操作目標之前先獲取操作許可,然後再執行操作,如果其他用戶同時嘗試操作該目標將被阻止,直到前一個用戶釋放許可後,其他用戶才能夠操作目標。分析這個過程,如果只有一個用戶操作目標,沒有多個用戶並發沖突,也申請了操作許可,造成了由於申請操作許可所帶來的資源使用消耗,浪費網路通信和增加了延時。
採用分布式鎖實現多副本內容修改的一致性問題, 選擇控制內容顆粒度實現申請鎖服務。例如我們要保證一個文件的多個副本修改一致, 可以對整個文件修改設置一把鎖,修改時申請鎖,修改這個文件的多個副本,確保多個副本修改的一致,修改完成後釋放鎖;也可以對文件分段,或者是文件中的單個位元組設置鎖, 實現更細顆粒度的鎖操作,減少沖突。
常用的鎖實現演算法有Lamport bakery algorithm (俗稱麵包店演算法), 還有Paxos演算法。下面對其原理做簡單概述。
Lamport麵包店演算法
是解決多個線程並發訪問一個共享的單用戶資源的互斥問題的演算法。 由Leslie Lamport(英語:Leslie Lamport)發明。
Lamport把這個並發控制演算法可以非常直觀地類比為顧客去麵包店采購。麵包店只能接待一位顧客的采購。已知有n位顧客要進入麵包店采購,安排他們按照次序在前台登記一個簽到號碼。該簽到號碼逐次加1。根據簽到號碼的由小到大的順序依次入店購貨。完成購買的顧客在前台把其簽到號碼歸0. 如果完成購買的顧客要再次進店購買,就必須重新排隊。
這個類比中的顧客就相當於線程,而入店購貨就是進入臨界區獨占訪問該共享資源。由於計算機實現的特點,存在兩個線程獲得相同的簽到號碼的情況,這是因為兩個線程幾乎同時申請排隊的簽到號碼,讀取已經發出去的簽到號碼情況,這兩個線程讀到的數據是完全一樣的,然後各自在讀到的數據上找到最大值,再加1作為自己的排隊簽到號碼。為此,該演算法規定如果兩個線程的排隊簽到號碼相等,則線程id號較小的具有優先權。
把該演算法原理與分布式系統相結合,即可實現分步鎖。
Paxos演算法
該演算法比較熱門,參見WIKI,http://zh.wikipedia.org/wiki/Paxos%E7%AE%97%E6%B3%95
Paxos演算法解決的問題是一個分布式系統如何就某個值(決議)達成一致。一個典型的場景是,在一個分布式資料庫系統中,如果各節點的初始狀態一致,每個節點都執行相同的操作序列,那麼他們最後能得到一個一致的狀態。為保證每個節點執行相同的命令序列,需要在每一條指令上執行一個「一致性演算法」以保證每個節點看到的指令一致。一個通用的一致性演算法可以應用在許多場景中,是分布式計算中的重要問題。節點通信存在兩種模型:共享內存(Shared memory)和消息傳遞(Messages passing)。Paxos演算法就是一種基於消息傳遞模型的一致性演算法。BigTable使用一個分布式數據鎖服務Chubby,而Chubby使用Paxos演算法來保證備份的一致性。
採用樂觀鎖原理實現的同步
我們舉個例子說明該演算法的實現原理。如一個金融系統,當某個操作員讀取用戶的數據,並在讀出的用戶數據的基礎上進行修改時(如更改用戶帳戶余額),如果採用前面的分布式鎖服務機制,也就意味著整個操作過程中(從操作員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操作員中途去煮咖啡的時間),資料庫記錄始終處於加鎖狀態,可以想見,如果面對幾百上千個並發,這樣的情況將導致怎樣的後果。
樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於數據版本( Version)記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加一個 「version」 欄位來實現。讀取出數據時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交數據的版本數據與資料庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大於資料庫表當前版本號,則予以更新,否則認為是過期數據。
對於上面修改用戶帳戶信息的例子而言,假設資料庫中帳戶信息表中有一個 version 欄位,當前值為 1 ;而當前帳戶余額欄位( balance )為 $100 。
操作員 A 此時將其讀出(version=1 ),並從其帳戶余額中扣除 $50($100-$50 )。
在操作員 A 操作的過程中,操作員B也讀入此用戶信息( version=1 ),並從其帳戶余額中扣除 $20 ( $100-$20 )。
操作員 A 完成了修改工作,將數據版本號加一( version=2 ),連同帳戶扣除後余額( balance=$50 ),提交至資料庫更新,此時由於提交數據版本大於資料庫記錄當前版本,數據被更新,資料庫記錄 version 更新為 2 。
操作員 B 完成了操作,也將版本號加一( version=2 )試圖向資料庫提交數據( balance=$80 ),但此時比對資料庫記錄版本時發現,操作員 B 提交的數據版本號為 2 ,資料庫記錄當前版本也為 2 ,不滿足 「 提交版本必須大於記錄當前版本才能執行更新 「 的樂觀鎖策略,因此,操作員 B 的提交被駁回。這樣,就避免了操作員 B 用基於 version=1 的舊數據修改的結果覆蓋操作員A 的操作結果的可能。
樂觀鎖機制與分布式系統相結合上, 我整理了偽代碼如下:
obj 操作的目標
vlaue 修改的值
atom_update_ver 每個目標上的版本,每次修改該值遞增
set( obj, value)
{
//從每個節點上取出修改前的對象版本
get original_ver = obj.atom_update_ver from each node;
//將值賦到每個節點的obj目標
set obj = value from each node;
//條件修改每個節點的obj版本,目標版本加一
//比較和修改操作是原子操作
result = (set obj.atom_update_ver = original_ver + 1
where original_ver + 1 > obj.atom_update_ver
for each node);
if(result == ok)
return set_ok;
else
return set(obj, value);//不成功遞歸修改
該演算法未考慮節點下線、失效等問題,在後續我將分析採用樂觀鎖原理實現一致性演算法,解決問題2、節點失效、通信失敗等問題。
Ⅱ 分布式資料庫數據一致性
CAP定理是2000年,由 Eric Brewer 提出來的。Brewer認為在分布式的環境下設計和部署系統時,有3個核心的需求,以一種特殊的關系存在。這里的分布式系統說的是在物理上分布的系統,比如我們常見的web系統。
高可用、數據一致是很多系統設計的目標,但是分區又是不可避免的事情:
CAP原理的關系與相關的產品如下圖所示
下面是對於P的一點討論,在Seth Gilbert and Professor Nancy Lynch 論文中,Partition Tolerance的定義如下所示
1. Quorum系統NRW策略
這個協議有三個關鍵字N、R、W。
R 和 W 比例關系
2. 兩階提交演算法
Ⅲ 資料庫的一致性是什麼有什麼作用
資料庫一致性(Database Consistency)是指事務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。保證資料庫一致性是指當事務完成時,必須使所有數據都具有一致的狀態。在關系型資料庫中,所有的規則必須應用到事務的修改上,以便維護所有數據的完整性。
保證資料庫的一致性是資料庫管理系統的一項功能.比如有兩個表(員工職位),員工表中有員工代碼、姓名、職位代碼等屬性,職位表中有職位代碼、職位名稱、職位等級等屬性。你在其中員工表中進行了插入操作,你插入了一個新員工的信息,而這個新員工的職位是公司新創建的一個職位。如果沒有一致性的保證,就會出現有這么一個員工,但是不知道他到底擔當什麼職責!這個只是它的一個小小方面。
讀一致性也是資料庫一致性的一個重要方面,在實際中,我們會遇到這種情況:我們對一個表中的某些數據進行了更新操作,,但是還沒有進行提交,這時另外一個用戶讀取表中數據.這個時候就出現了讀一致性的問題:到底是讀什麼時候的數據呢?是更新前的還是更新後的?在DBMS中設有臨時表,它用來保存修改前的值,在沒有進行提交前讀取數據,會讀取臨時表中的數據,這樣一來就保證了數據是一致的.(當前用戶看到的是更新後的值)
但是還有一種情況:用戶user1對表進行了更新操作,用戶user2在user1還沒有進行提交前讀表中數據,而且是大批量的讀取(打個比方:耗時3分鍾)而在這3分鍾內user1進行了提交操作,那又會產生什麼影響呢?這個時候怎麼保證讀寫一致性呢?這個時候DBMS就要保證有足夠大的臨時表來存放修改前的數值,以保證user2讀取的數據是修改前的一致數據.然後下次再讀取時候就是更新後的數據了。
Ⅳ 如何解決分布式系統數據事務一致性問題
文探討了在分布式系統中,如何基於業務方面的考量、將RESTful與MQ(消息中間件)結合、解決事務完整性/數據一致性問題的架構設計。
一、面向業務考量的最終一致性方案考慮
這里先舉兩個例子。
1、支付寶的「WS Transaction標准」嘗試:
支付寶在他們的分布式系統中為解決事務完整性的問題,曾經嘗試過WS Transaction標准,但是經過實際做測試,最後發現成本實在是太高了。完成一個事務,為確保事務完整性,20多條的消息的交互,其中只有1條是業務消息,其他都是系統之間的協議消息。這就會導致客戶端響應太慢,客戶無法承受這樣的性能。
2、Ebay架構師的最終一致性方案:
來自Ebay的架構師根據他們的最佳實踐給出過解決方案。就是關於數據一致性的,比如他們的分布式存儲如何保持數據一致性。其中探討了「實時一致」與「嚴格事務」之間的悖論,他們採用了局部實時一致、全局最終一致的解決方案。在這里就需要從業務上辨別哪些操作是可以放寬的(允許不在一個事務中),哪些操作必須是原子性的。現在Ebay的整個架構就是基於「最終一致性」的,支付寶也從中受到啟發,沿用該設計思路解決了「客戶端迅速響應」和「服務端數據一致」的矛盾。
故考慮系統架構設計的時候,不僅僅考慮技術,也把業務因素考慮進來,面向業務考量進行系統設計,會讓我們在技術上做出更合理的抉擇。基於業務考慮,有利於得出事務的優先順序別,也有利於作出架構設計上的最佳取捨。通常來說銀行、證券系統的事務完整性(或者說數據一致性)具有絕對優先順序,也就要求絕對嚴格的實時保證。而通訊系統在事務完整性(或者說數據一致性上)的優先順序別上甚至沒有支付寶和Ebay高,這兩者都有復雜的帳務交易。如果他們也認為局部實時一致、全局最終一致就能夠滿足業務的要求,那麼自然在通訊系統中也有其可行性。
二、Restful與MQ技術適用場景分析
一般而言Restful技術架構為對客戶端開放的一組資源服務。在分布式系統中既有客戶端與伺服器之間的交互,又有伺服器與伺服器之間的交互。比如說XCAP協議就是標準的Restful風格的介面,提供客戶端遠程操作XML文檔的服務,而「運營管理系統」調用其他業務系統介面,用以管理用戶可被分配的服務以及許可權等,則是伺服器之間的信息交互。前者當然適合Restful風格的技術介面,後者個人更傾向於非同步的、基於消息的通信方式。因為客戶端與伺服器通常是跨越互聯網的,而伺服器與伺服器之間可能位於一個區域網內,甚至可能被安放在同一個機房。
我們知道Restful風格的技術架構通常是通過JSON或者XML等進行信息的傳遞,總之都是通過「字元串格式」的封裝進行信息傳遞。通過字元格式交互信息在使用上帶來簡便的同時,因為封裝、解析、轉換等過程使其在性能自然要付出一些代價,如果是伺服器之間在更底層同類協議之間的數據交互性能就要高的多。這里順便提到信息交互在不同場景下的性能順序,按照從快到慢排序:
1、同一進程之間的信息交互;
2、同一機器兩個進程之間的信息交互;
3、兩個分布機器之間的信息交互。
因為HTTP是在TCP/IP協議之上的包裝,WebService是在HTTP協議之上的包裝,根據越低層協議之間的信息交互越高效的特徵,從協議級由快到慢排序:
1、基於TCP/IP協議的信息交互;
2、基於HTTP協議的信息交互;
3、基於WebService協議的信息交互。
另外,因為「運營管理系統」與其他系統之間是直接交互的,比如運營要給某個用戶開通某些特定服務,那就要分別調用提供這幾個服務的業務系統的「細粒度」介面。一旦增加新的服務,也勢必影響到運營管理系統的修改。我們說在分布式系統中有個原則,盡可能設計「粗粒度」介面,以減少系統之間的網路交互。如果在運營管理系統與其他業務系統之間由「消息中間件」來進行信息交互,那麼:
1、運營管理系統可以設計面向服務的「粗粒度」介面,開通幾個服務只需要把幾種類型的數據封裝在一起,一次性傳遞給MQ。增加服務也只不過增加一種數據類型而已;
2、MQ可以保證消息最終一定會被接收、處理。因為MQ可以實現基於「訂閱-通知」的Event-Driven機制,業務系統只要在MQ中注冊自己,就可以實時收到來自MQ的消息。即使出現系統或者網路異常,消息也會被MQ中間件持久化,一旦業務系統恢復,消息馬上會被發往業務系統,這顯然比目前採用的每隔一段時間掃描一次資料庫要高效的多。
三、MQ與最終一致性
MQ消息隊列技術是分布式應用間交換信息的一種技術。消息隊列可駐留在內存或磁碟上,隊列存儲消息直到它們被應用程序讀走。通過消息隊列,應用程序可獨立地執行——它們不需要知道彼此的位置、或在繼續執行前不需要等待接收程序接收此消息。它為構造非同步方式實現的分布式應用提供了松耦合方法,在應用中以執行多種功能,比如要求服務、交換信息或非同步處理等。
在分布式系統中,尤其是不同語言的分布式系統中,如果沒有消息中間件完成信息交換,應用開發者為了高效傳輸數據,就要編寫相應語言的應用程序來發送和接收信息,且交換信息沒有標准方法,每個應用必須進行特定的編程從而和多平台、不同環境下的一個或多個應用通信。
假如系統可以採用數據「局部實時一致、全局最終一致」的方案,就可以選擇不需要支持事務的MQ中間件,因為其可以保證:即使在系統異常、網路異常等特殊情況下,消息也會被持久化,當系統恢復,消息馬上會被處理,也即最終一定會被接受處理,也就是最終一致。而不需要支持事務的MQ性能及吞吐率都會很高。
總之,個人傾向於用 Restful對客戶端提供服務,伺服器之間引入MQ服務,建立非同步的、基於消息的信息交互方式,並基於數據局部實時一致、全局最終一致的原則,來解決事務問題。
Ⅳ 分布式資料庫的特徵
分布式資料庫的特徵:
1、獨立透明性
數據獨立性是資料庫方法追求的主要目標之一,分布透明性指用戶不必關心數據的邏輯分區,不必關心數據物理位置分布的細節,也不必關心重復副本(冗餘數據)的一致性問題,同時也不必關心局部場地上資料庫支持哪種數據模型。
分布透明性的優點是很明顯的。有了分布透明性,用戶的應用程序書寫起來就如同數據沒有分布一樣。當數據從一個場地移到另一個場地時不必改寫應用程序。
當增加某些數據的重復副本時也不必改寫應用程序。數據分布的信息由系統存儲在數據字典中。用戶對非本地數據的訪問請求由系統根據數據字典予以解釋、轉換、傳送。
2、復制透明性
用戶不用關心資料庫在網路中各個節點的復制情況,被復制的數據的更新都由系統自動完成。在分布式資料庫系統中,可以把一個場地的數據復制到其他場地存放,應用程序可以使用復制到本地的數據在本地完成分布式操作,避免通過網路傳輸數據,提高了系統的運行和查詢效率。
但是對於復制數據的更新操作,就要涉及到對所有復制數據的更新。
3、易於擴展性
在大多數網路環境中,單個資料庫伺服器最終會不滿足使用。如果伺服器軟體支持透明的水平擴展,那麼就可以增加多個伺服器來進一步分布數據和分擔處理任務。
主要優點:
(1)具有靈活的體系結構。
(2)適應分布式的管理和控制機構。
(3)經濟性能優越。
(4)系統的可靠性高、可用性好。
(5)局部應用的響應速度快。
(6)可擴展性好,易於集成現有系統。
Ⅵ 如何解決分布式系統數據事務一致性問題
用戶在京東上下了一個訂單,發現自己在京東的賬戶裡面有餘額,然後使用余額支付,支付成功之後,訂單狀態修改為支付成功,然後通知倉庫發貨。假設訂單系統,支付系統,倉庫系統是三個獨立的應用,是獨立部署的,系統之間通過遠程服務調用。 訂單的有三個狀態:I:初始 P:已支付 W:已出庫,訂單金額100, 會員帳戶余額200 如果整個流程比較順利,正常情況下,訂單的狀態會變為I->P->W,會員帳戶余額100,訂單出庫。 但是如果流程不順利了?考慮以下幾種情況 1:訂單系統調用支付系統支付訂單,支付成功,但是返回給訂單系統數據超時,訂單還是I(初始狀態),但是此時會員帳戶余額100,會員肯定會馬上找京東罵京東,為啥不給老子發貨,我都付錢了 2:訂單系統調用支付系統成功,狀態也已經更新成功,但是通知倉庫發貨失敗,這個時候訂單是P(已支付)狀態,此時會員帳戶余額是100,但是倉庫不會發貨。會員也要罵京東。 3:訂單系統調用支付系統成功,狀態也已經更新成功,然後通知倉庫發貨,倉庫告訴訂單系統,沒有貨了。這個時候數據狀態和第二種情況一樣。 對於問題一,我們來分析一下解決方案,能想到的解決方案如下 1 假設調用支付系統支付訂單的時候先不扣錢,訂單狀態更新完成之後,在通知支付系統你扣錢 如果採用這種設計方案,那麼在同一時刻,這個用戶,又支付了另外一筆訂單,訂單價格200,順利完成了整個訂單支付流程,由於當前訂單的狀態已經變成了支付成功,但是實際用戶已經沒有錢支付了,這筆訂單的狀態就不一致了。即使用戶在同一個時刻沒有進行另外的訂單支付行為,通知支付系統扣錢這個動作也有可能完不成,因為也有可能失敗,反而增加了系統的復雜性。 2 訂單系統自動發起重試,多重試幾次,例如三次,直到扣款成功為止。 這個看起來也是不錯的考慮,但是和解決方案一樣,解決不了問題,還會帶來新的問題,假設訂單系統第一次調用支付系統成功,但是沒有辦法收到應答,訂單系統又發起調用,完了,重復支付,一次訂單支付了200。 假設支付系統正在發布,你重試多少次都一樣,都會失敗。這個時候用戶在等待,你怎麼處理? 3 在第二種方案的基礎上,我們先解決訂單的重復支付行為,我們需要在支付系統上對訂單號進行控制,一筆訂單如果已經支付成功,不能在進行支付。返回重復支付標識。那麼訂單系統根據返回的標識,更新訂單狀態。 接下來解決重試問題,我們假設應用上重試三次,如果三次都失敗,先返回給用戶提示支付結果未知。假設這個時候用戶重新發起支付,訂單系統調用支付系統,發現訂單已經支付,那麼繼續下面的流程。如果會員沒有發起支付,系統定時(一分鍾一次)去核對訂單狀態,如果發現已經被支付,則繼續後續的流程。 這種方案,用戶體驗非常差,告訴用戶支付結果未知,用戶一定會罵你,你丫咋回事情,我明明支付了,你告訴我未知。假設告訴用戶支付失敗,萬一實際是成功的咋辦。你告訴用戶支付成功,萬一支付失敗咋辦。 4 第三種方案能夠解決訂單和支付數據的一致性問題,但是用戶體驗非常差。當然這種情況比較可能是少數,可以犧牲這一部分的用戶體驗,我們還有沒有更好的解決方案,既能照顧用戶體驗,又能夠保證資金的安全性。 我們再回來看看第一種方案,我們先不扣錢,但是有木有辦法讓這一部分錢不讓用戶使用,對了,我們先把這一部分錢凍結起來,訂單系統先調用支付系統成功的時候,支付系統先不扣錢,而是先把錢凍結起來,不讓用戶給其他訂單支付,然後等訂單系統把訂單狀態更新為支付成功的時候,再通知支付系統,你扣錢吧,這個時候支付系統扣錢,完成後續的操作。 看起來這個方案不錯,我們仔細在分析一下流程,這個方案還存在什麼問題,假設訂單系統在調用支付系統凍結的時候,支付系統凍結成功,但是訂單系統超時,這個時候返回給用戶,告知用戶支付失敗,如果用戶再次支付這筆訂單,那麼由於支付系統進行控制,告訴訂單系統凍結成功,訂單系統更新狀態,然後通知支付系統,扣錢吧。如果這個時候通知失敗,木有問題,反正錢都已經是凍結的了,用戶不能用,我只要定時掃描訂單和支付狀態,進行扣錢而已。 那麼如果變態的用戶重新拍下來一筆訂單,100塊錢,對新的訂單進行支付,這個時候由於先前那一筆訂單的錢被凍結了,這個時候用戶余額剩餘100,凍結100,發現可用的余額足夠,那就直接在對用戶扣錢。這個時候余額剩餘0,凍結100。先前那一筆怎麼辦,一個辦法就是定時掃描,發現訂單狀態是初始的話,就對用戶的支付余額進行解凍處理。這個時候用戶的余額變成100,訂單數據和支付數據又一致了。假設原先用戶余額只有100,被凍結了,用戶重新下單,支付的時候就失敗了啊,的確會發生這一種情況,所以要盡可能的保證在第一次訂單結果不明確的情況,盡早解凍用戶余額,比如10秒之內。但是不管如何快速,總有數據不一致的時刻,這個是沒有辦法避免的。 第二種情況和第三種情況如何處理,下次在分析吧。 由於互聯網目前越來越強調分布式架構,如果是交易類系統,面臨的將會是分布式事務上的挑戰。當然目前有很多開源的分布式事務產品,例如java JPA,但是這種解決方案的成本是非常高的,而且實現起來非常復雜,效率也比較低下。對於極端的情況:例如發布,故障的時候都是沒有辦法保證強一致性的。
Ⅶ 什麼是分布式環境中數據的強一致性
一致性又可以分為強一致性與弱一致性。 強一致性可以理解為在任意時刻,所有節點中的數據是一樣的。同一時間點,你在節點A中獲取到key1的值與在節點B中獲取到key1的值應該都是一樣的。 弱一致性包含很多種不同的實現,目前分布式系統中廣泛實現
Ⅷ 雙十一是怎麼保證高並發,分布式系統中,數據一致性
前言 在系統開發過程中,經常遇到數據重復插入、重復更新、消息重發發送等等問題,因為應用系統的復雜邏輯以及網路交互存在的不確定性,會導致這一重復現象,但是有些邏輯是需要有冪等特性的,否則造成的後果會比較嚴重,例如訂單重復創建,這時候帶來的問題可是非同一般啊。 什麼是系統的冪等性 冪等是數據中得一個概念,表示N次變換和1次變換的結果相同。 高並發的系統如何保證冪等性? 1.查詢 查詢的API,可以說是天然的冪等性,因為你查詢一次和查詢兩次,對於系統來講,沒有任何數據的變更,所以,查詢一次和查詢多次一樣的。 2.MVCC方案 多版本並發控制,update with condition,更新帶條件,這也是在系統設計的時候,合理的選擇樂觀鎖,通過version或者其他條件,來做樂觀鎖,這樣保證更新及時在並發的情況下,也不會有太大的問題。 例如:update table_xxx set name=#name#,version=version+1 where version=#version# ,或者是 update table_xxx set quality=quality-#subQuality# where quality-#subQuality# >= 0 。 3.單獨的去重表 如果涉及到的去重的地方特別多,例如ERP系統中有各種各樣的業務單據,每一種業務單據都需要去重,這時候,可以單獨搞一張去重表,在插入數據的時候,插入去重表,利用資料庫的唯一索引特性,保證唯一的邏輯。 4.分布式鎖 還是拿插入數據的例子,如果是分布是系統,構建唯一索引比較困難,例如唯一性的欄位沒法確定,這時候可以引入分布式鎖,通過第三方的系統,在業務系統插入數據或者更新數據,獲取分布式鎖,然後做操作,之後釋放鎖,這樣其實是把多線程並發的鎖的思路,引入多多個系統,也就是分布式系統中得解決思路。 5.刪除數據 刪除數據,僅僅第一次刪除是真正的操作數據,第二次甚至第三次刪除,直接返回成功,這樣保證了冪等。 6.插入數據的唯一索引 插入數據的唯一性,可以通過業務主鍵來進行約束,例如一個特定的業務場景,三個欄位肯定確定唯一性,那麼,可以在資料庫表添加唯一索引來進行標示。 這里有一個場景,API層面的冪等,例如提交數據,如何控制重復提交,這里可以在提交數據的form表單或者客戶端軟體,增加一個唯一標示,然後服務端,根據這個UUID來進行去重,這樣就能比較好的做到API層面的唯一標識。 7.狀態機冪等 在設計單據相關的業務,或者是任務相關的業務,肯定會涉及到狀態機,就是業務單據上面有個狀態,狀態在不同的情況下會發生變更,一般情況下存在有限狀態機,這時候,如果狀態機已經處於下一個狀態,這時候來了一個上一個狀態的變更,理論上是不能夠變更的,這樣的話,保證了有限狀態機的冪等。 以上就是高並發系統數據冪等的解決方案的資料整理,後續繼續補充相關知識,謝謝大家對本站的支持!
Ⅸ 在分布式存儲系統中,一致性問題的產生原因是什麼
現在先拋出問題,假設有一個主數據中心在北京M,然後有成都A,上海B兩個地方數據中心,現在的問題是,假設成都上海各自的數據中心有記錄變更,需要先同步到主數據中心,主數據中心更新完成之後,在把最新的數據分發到上海,成都的地方數據中心A,地方數據中心更新數據,保持和主數據中心一致性(資料庫結構完全一致)。數據更新的消息是通過一台中心的MQ進行轉發。
先把問題簡單化處理,假設A增加一條記錄Message_A,發送到M,B增加一條記錄 MESSAGE_B發送到M,都是通過MQ伺服器進行轉發,那麼M系統接收到條消息,增加兩條數據,那麼M在把增加的消息群發給A,B,A和B找到自己缺失的數據,更新資料庫。這樣就完成了一個數據的同步。
Ⅹ 保證分布式系統數據一致性的6種方案
編者按 :本文由「高可用架構後花園」群討論整理而成。
有人的地方,就有江湖
有江湖的地方,就有紛爭
在電商等業務中,系統一般由多個獨立的服務組成,如何解決分布式調用時候數據的一致性?
具體業務場景如下,比如一個業務操作,如果同時調用服務 A、B、C,需要滿足要麼同時成功;要麼同時失敗。A、B、C 可能是多個不同部門開發、部署在不同伺服器上的遠程服務。
在分布式系統來說,如果不想犧牲一致性,CAP 理論告訴我們只能放棄可用性,這顯然不能接受。為了便於討論問題,先簡單介紹下數據一致性的基礎理論。
強一致
弱一致性
最終一致性
在工程實踐上,為了保障系統的可用性,互聯網系統大多將強一致性需求轉換成最終一致性的需求,並通過系統執行冪等性的保證,保證數據的最終一致性。但在電商等場景中,對於數據一致性的解決方法和常見的互聯網系統(如 MySQL 主從同步)又有一定區別,群友的討論分成以下 6 種解決方案。
業務整合方案主要採用將介面整合到本地執行的方法。拿問題場景來說,則可以將服務 A、B、C 整合為一個服務 D 給業務,這個服務 D 再通過轉換為本地事務的方式,比如服務 D 包含本地服務和服務 E,而服務 E 是本地服務 A ~ C 的整合。
優點: 解決(規避)了分布式事務。
缺點: 顯而易見,把本來規劃拆分好的業務,又耦合到了一起,業務職責不清晰,不利於維護。
由於這個方法存在明顯缺點,通常不建議使用。
此方案的核心是將需要分布式處理的任務通過消息日誌的方式來非同步執行。消息日誌可以存儲到本地文本、資料庫或消息隊列,再通過業務規則自動或人工發起重試。人工重試更多的是應用於支付場景,通過對賬系統對事後問題的處理。
消息日誌方案的核心是保證服務介面的冪等性。
考慮到網路通訊失敗、數據丟包等原因,如果介面不能保證冪等性,數據的唯一性將很難保證。
eBay 方式的主要思路如下。
Base:一種 Acid 的替代方案
此方案是 eBay 的架構師 Dan Pritchett 在 2008 年發表給 ACM 的文章,是一篇解釋 BASE 原則,或者說最終一致性的經典文章。文中討論了 BASE 與 ACID 原則在保證數據一致性的基本差異。
如果 ACID 為分區的資料庫提供一致性的選擇,那麼如何實現可用性呢?答案是
BASE (basically available, soft state, eventually consistent)
BASE 的可用性是通過 支持局部故障 而不是系統全局故障來實現的。下面是一個簡單的例子:如果將用戶分區在 5 個資料庫伺服器上,BASE 設計鼓勵類似的處理方式,一個用戶資料庫的故障隻影響這台特定主機那 20% 的用戶。這里不涉及任何魔法,不過它確實可以帶來更高的可感知的系統可用性。
文章中描述了一個最常見的場景,如果產生了一筆交易,需要在交易表增加記錄,同時還要修改用戶表的金額。這兩個表屬於不同的遠程服務,所以就涉及到分布式事務一致性的問題。
文中提出了一個經典的解決方法,將主要修改操作以及更新用戶表的消息 放在一個本地事務 來完成。同時為了避免重復消費用戶表消息帶來的問題,達到多次重試的冪等性, 增加一個更新記錄表 updates_applied 來記錄已經處理過的消息。
系統的執行偽代碼如下
(點擊可全屏縮放圖片)
基於以上方法,在第一階段,通過本地的資料庫的事務保障,增加了 transaction 表及消息隊列 。
在第二階段,分別讀出消息隊列(但不刪除),通過判斷更新記錄表 updates_applied 來檢測相關記錄是否被執行,未被執行的記錄會修改 user 表,然後增加一條操作記錄到 updates_applied,事務執行成功之後再刪除隊列。
通過以上方法,達到了分布式系統的最終一致性。進一步了解 eBay 的方案可以參考文末鏈接。
隨著業務規模不斷地擴大,電商網站一般都要面臨拆分之路。就是將原來一個單體應用拆分成多個不同職責的子系統。比如以前可能將面向用戶、客戶和運營的功能都放在一個系統里,現在拆分為訂單中心、代理商管理、運營系統、報價中心、庫存管理等多個子系統。
拆分首先要面臨的是什麼呢?
最開始的單體應用所有功能都在一起,存儲也在一起。比如運營要取消某個訂單,那直接去更新訂單表狀態,然後更新庫存表就 ok 了。因為是單體應用,庫在一起,這些都可以在一個事務里,由關系資料庫來保證一致性。
但拆分之後就不同了,不同的子系統都有自己的存儲。比如訂單中心就只管理自己的訂單庫,而庫存管理也有自己的庫。那麼運營系統取消訂單的時候就是通過介面調用等方式來調用訂單中心和庫存管理的服務了,而不是直接去操作庫。這就涉及一個『 分布式事務 』的問題。
分布式事務有兩種解決方式
1. 優先使用非同步消息。
上文已經說過,使用非同步消息 Consumer 端需要實現冪等。
冪等有兩種方式, 一種方式是業務邏輯保證冪等 。比如接到支付成功的消息訂單狀態變成支付完成,如果當前狀態是支付完成,則再收到一個支付成功的消息則說明消息重復了,直接作為消息成功處理。
另外一種方式如果業務邏輯無法保證冪等,則要增加一個去重表或者類似的實現 。對於 procer 端在業務資料庫的同實例上放一個消息庫,發消息和業務操作在同一個本地事務里。發消息的時候消息並不立即發出,而是向消息庫插入一條消息記錄,然後在事務提交的時候再非同步將消息發出,發送消息如果成功則將消息庫里的消息刪除,如果遇到消息隊列服務異常或網路問題,消息沒有成功發出那麼消息就留在這里了,會有另外一個服務不斷地將這些消息掃出重新發送。
2. 有的業務不適合非同步消息的方式,事務的各個參與方都需要同步的得到結果。 這種情況的實現方式其實和上面類似,每個參與方的本地業務庫的同實例上面放一個事務記錄庫。
比如 A 同步調用 B,C。A 本地事務成功的時候更新本地事務記錄狀態,B 和 C 同樣。如果有一次 A 調用 B 失敗了,這個失敗可能是 B 真的失敗了,也可能是調用超時,實際 B 成功。則由一個中心服務對比三方的事務記錄表,做一個最終決定。假設現在三方的事務記錄是 A 成功,B 失敗,C 成功。那麼最終決定有兩種方式,根據具體場景:
對 b 場景做一個特殊說明:比如 B 是扣庫存服務,在第一次調用的時候因為某種原因失敗了,但是重試的時候庫存已經變為 0,無法重試成功,這個時候只有回滾 A 和 C 了。
那麼可能有人覺得在業務庫的同實例里放消息庫或事務記錄庫,會對業務侵入,業務還要關心這個庫,是否一個合理的設計?
實際上可以依靠運維的手段來簡化開發的侵入,我們的方法是讓 DBA 在公司所有 MySQL 實例上預初始化這個庫,通過框架層(消息的客戶端或事務 RPC 框架)透明的在背後操作這個庫,業務開發人員只需要關心自己的業務邏輯,不需要直接訪問這個庫。
總結起來,其實兩種方式的根本原理是類似的,也就是 將分布式事務轉換為多個本地事務,然後依靠重試等方式達到最終一致性 。
交易創建的一般性流程
我們把交易創建流程抽象出一系列可擴展的功能點,每個功能點都可以有多個實現(具體的實現之間有組合/互斥關系)。把各個功能點按照一定流程串起來,就完成了交易創建的過程。
面臨的問題
每個功能點的實現都可能會依賴外部服務。那麼如何保證各個服務之間的數據是一致的呢?比如鎖定優惠券服務調用超時了,不能確定到底有沒有鎖券成功,該如何處理?再比如鎖券成功了,但是扣減庫存失敗了,該如何處理?
方案選型
服務依賴過多,會帶來管理復雜性增加和穩定性風險增大的問題。試想如果我們強依賴 10 個服務,9 個都執行成功了,最後一個執行失敗了,那麼是不是前面 9 個都要回滾掉?這個成本還是非常高的。
所以在拆分大的流程為多個小的本地事務的前提下,對於非實時、非強一致性的關聯業務寫入,在本地事務執行成功後,我們選擇發消息通知、關聯事務非同步化執行的方案。
消息通知往往不能保證 100% 成功;且消息通知後,接收方業務是否能執行成功還是未知數。前者問題可以通過重試解決;後者可以選用事務消息來保證。
所以目前只剩下需要實時同步做、有強一致性要求的業務場景了。在交易創建過程中,鎖券和扣減庫存是這樣的兩個典型場景。
要保證多個系統間數據一致,乍一看,必須要引入分布式事務框架才能解決。但引入非常重的類似二階段提交分布式事務框架會帶來復雜性的急劇上升;在電商領域,絕對的強一致是過於理想化的,我們可以選擇准實時的最終一致性。
我們在交易創建流程中, 首先創建一個不可見訂單 ,然後在同步調用鎖券和扣減庫存時,針對調用異常(失敗或者超時),發出廢單消息到MQ。如果消息發送失敗,本地會做時間階梯式的非同步重試;優惠券系統和庫存系統收到消息後,會進行判斷是否需要做業務回滾,這樣就准實時地保證了多個本地事務的最終一致性。
業界常用的還有支付寶的一種 xts 方案,由支付寶在 2PC 的基礎上改進而來。主要思路如下,大部分信息引用自官方網站。
分布式事務服務簡介
分布式事務服務 (Distributed Transaction Service, DTS) 是一個分布式事務框架,用來保障在大規模分布式環境下事務的最終一致性。DTS 從架構上分為 xts-client 和 xts-server 兩部分,前者是一個嵌入客戶端應用的 JAR 包,主要負責事務數據的寫入和處理;後者是一個獨立的系統,主要負責異常事務的恢復。
核心特性
傳統關系型資料庫的事務模型必須遵守 ACID 原則。在單資料庫模式下,ACID 模型能有效保障數據的完整性,但是在大規模分布式環境下,一個業務往往會跨越多個資料庫,如何保證這多個資料庫之間的數據一致性,需要其他行之有效的策略。在 JavaEE 規范中使用 2PC (2 Phase Commit, 兩階段提交) 來處理跨 DB 環境下的事務問題,但是 2PC 是反可伸縮模式,也就是說,在事務處理過程中,參與者需要一直持有資源直到整個分布式事務結束。這樣,當業務規模達到千萬級以上時,2PC 的局限性就越來越明顯,系統可伸縮性會變得很差。基於此,我們採用 BASE 的思想實現了一套類似 2PC 的分布式事務方案,這就是 DTS。DTS在充分保障分布式環境下高可用性、高可靠性的同時兼顧數據一致性的要求,其最大的特點是保證數據最終一致 (Eventually consistent)。
簡單的說,DTS 框架有如下特性:
以下是分布式事務框架的流程圖
實現
與 2PC 協議比較
1. 電商業務
公司的支付部門,通過接入其它第三方支付系統來提供支付服務給業務部門,支付服務是一個基於 Dubbo 的 RPC 服務。
對於業務部門來說,電商部門的訂單支付,需要調用
從業務規則上需要同時保證業務數據的實時性和一致性,也就是支付成功必須加積分。
我們採用的方式是同步調用,首先處理本地事務業務。考慮到積分業務比較單一且業務影響低於支付,由積分平台提供增加與回撤介面。
具體的流程是先調用積分平台增加用戶積分,再調用支付平台進行支付處理,如果處理失敗,catch 方法調用積分平台的回撤方法,將本次處理的積分訂單回撤。
(點擊圖片可以全屏縮放)
2. 用戶信息變更
分布式服務對衍生的配套系統要求比較多,特別是我們基於消息、日誌的最終一致性方案,需要考慮消息的積壓、消費情況、監控、報警等。
In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability.
英文版 : http://queue.acm.org/detail.cfm?id=1394128
中文版: http://article.yeeyan.org/view/167444/125572
感謝李玉福、余昭輝、蘑菇街七公提供方案,其他多位群成員對本文內容亦有貢獻。
本文編輯李玉福、Tim Yang,轉載請註明來自@高可用架構