分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論_第1頁
分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論_第2頁
分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論_第3頁
分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論_第4頁
分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論_第5頁
已閱讀5頁,還剩4頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

/分布式環(huán)境下的數(shù)據(jù)一致性問題的方案討論由于互聯(lián)網(wǎng)目前越來越強調分布式架構,如果是交易類系統(tǒng),面臨的將會是分布式事務上的挑戰(zhàn)。當然目前有很多開源的分布式事務產(chǎn)品,例如javaJTA,但是這種解決方案的成本是非常高的,而且實現(xiàn)起來非常復雜,效率也比較低下。對于極端的情況:例如發(fā)布,故障的時候都是沒有辦法保證強一致性的。首先,在目前的互聯(lián)網(wǎng)應用中,我們通過一個比較常見的例子,讓大家更深入的了解一下分布式系統(tǒng)設計中關于數(shù)據(jù)一致性的問題。拿我們經(jīng)常使用的功能來考慮吧,最近網(wǎng)購比較熱門,就以京東為例的,我們來看看京東的一個簡單的購物流程用戶在京東上下了一個訂單,發(fā)現(xiàn)自己在京東的賬戶里面有余額,然后使用余額支付,支付成功之后,訂單狀態(tài)修改為支付成功,然后通知倉庫發(fā)貨。假設訂單系統(tǒng),支付系統(tǒng),倉庫系統(tǒng)是三個獨立的應用,是獨立部署的,系統(tǒng)之間通過遠程服務調用。訂單的有三個狀態(tài):I:初始P:已支付W:已出庫,訂單金額100,會員帳戶余額200如果整個流程比較順利,正常情況下,訂單的狀態(tài)會變?yōu)镮->P->W,會員帳戶余額100,訂單出庫。但是如果流程不順利了呢?考慮以下幾種情況1:訂單系統(tǒng)調用支付系統(tǒng)支付訂單,支付成功,但是返回給訂單系統(tǒng)數(shù)據(jù)超時,訂單還是I(初始狀態(tài)),但是此時會員帳戶余額100,會員肯定會馬上找京東罵京東,為啥不給老子發(fā)貨,我都付錢了2:訂單系統(tǒng)調用支付系統(tǒng)成功,狀態(tài)也已經(jīng)更新成功,但是通知倉庫發(fā)貨失敗,這個時候訂單是P(已支付)狀態(tài),此時會員帳戶余額是100,但是倉庫不會發(fā)貨。會員也要罵京東。3:訂單系統(tǒng)調用支付系統(tǒng)成功,狀態(tài)也已經(jīng)更新成功,然后通知倉庫發(fā)貨,倉庫告訴訂單系統(tǒng),沒有貨了。這個時候數(shù)據(jù)狀態(tài)和第二種情況一樣。對于情況一的問題,我們來分析一下解決方案,能想到的解決方案如下1假設調用支付系統(tǒng)支付訂單的時候先不扣錢,訂單狀態(tài)更新完成之后,在通知支付系統(tǒng)你扣錢如果采用這種設計方案,那么在同一時刻,這個用戶,又支付了另外一筆訂單,訂單價格200,順利完成了整個訂單支付流程,由于當前訂單的狀態(tài)已經(jīng)變成了支付成功,但是實際用戶已經(jīng)沒有錢支付了,這筆訂單的狀態(tài)就不一致了。即使用戶在同一個時刻沒有進行另外的訂單支付行為,通知支付系統(tǒng)扣錢這個動作也有可能完不成,因為也有可能失敗,反而增加了系統(tǒng)的復雜性。2訂單系統(tǒng)自動發(fā)起重試,多重試幾次,例如三次,直到扣款成功為止。這個看起來也是不錯的考慮,但是和解決方案一樣,解決不了問題,還會帶來新的問題,假設訂單系統(tǒng)第一次調用支付系統(tǒng)成功,但是沒有辦法收到應答,訂單系統(tǒng)又發(fā)起調用,完了,重復支付,一次訂單支付了200。假設支付系統(tǒng)正在發(fā)布,你重試多少次都一樣,都會失敗。這個時候用戶在等待,你怎么處理?3在第二種方案的基礎上,我們先解決訂單的重復支付行為,我們需要在支付系統(tǒng)上對訂單號進行控制,一筆訂單如果已經(jīng)支付成功,不能在進行支付。返回重復支付標識。那么訂單系統(tǒng)根據(jù)返回的標識,更新訂單狀態(tài)。接下來解決重試問題,我們假設應用上重試三次,如果三次都失敗,先返回給用戶提示支付結果未知。假設這個時候用戶重新發(fā)起支付,訂單系統(tǒng)調用支付系統(tǒng),發(fā)現(xiàn)訂單已經(jīng)支付,那么繼續(xù)下面的流程。如果會員沒有發(fā)起支付,系統(tǒng)定時(一分鐘一次)去核對訂單狀態(tài),如果發(fā)現(xiàn)已經(jīng)被支付,則繼續(xù)后續(xù)的流程。這種方案,用戶體驗非常差,告訴用戶支付結果未知,用戶一定會罵你,你丫咋回事情,我明明支付了,你告訴我未知。假設告訴用戶支付失敗,萬一實際是成功的咋辦。你告訴用戶支付成功,萬一支付失敗咋辦。4第三種方案能夠解決訂單和支付數(shù)據(jù)的一致性問題,但是用戶體驗非常差。當然這種情況比較可能是少數(shù),可以犧牲這一部分的用戶體驗,我們還有沒有更好的解決方案,既能照顧用戶體驗,又能夠保證資金的安全性。我們再回來看看第一種方案,我們先不扣錢,但是有木有辦法讓這一部分錢不讓用戶使用,對了,我們先把這一部分錢凍結起來。訂單系統(tǒng)先調用支付系統(tǒng)成功的時候,支付系統(tǒng)先不扣錢,而是先把錢凍結起來,不讓用戶給其他訂單支付,然后等訂單系統(tǒng)把訂單狀態(tài)更新為支付成功的時候,再通知支付系統(tǒng),你扣錢吧,這個時候支付系統(tǒng)扣錢,完成后續(xù)的操作??雌饋磉@個方案不錯,我們仔細在分析一下流程,這個方案還存在什么問題,假設訂單系統(tǒng)在調用支付系統(tǒng)凍結的時候,支付系統(tǒng)凍結成功,但是訂單系統(tǒng)超時,這個時候返回給用戶,告知用戶支付失敗,如果用戶再次支付這筆訂單,那么由于支付系統(tǒng)進行控制,告訴訂單系統(tǒng)凍結成功,訂單系統(tǒng)更新狀態(tài),然后通知支付系統(tǒng),扣錢吧。如果這個時候通知失敗,木有問題,反正錢都已經(jīng)是凍結的了,用戶不能用,我只要定時掃描訂單和支付狀態(tài),進行扣錢而已。那么如果變態(tài)的用戶重新拍下來一筆訂單,100塊錢,對新的訂單進行支付,這個時候由于先前那一筆訂單的錢被凍結了,這個時候用戶余額剩余100,凍結100,發(fā)現(xiàn)可用的余額足夠,那就直接在對用戶扣錢。這個時候余額剩余0,凍結100。先前那一筆怎么辦,一個辦法就是定時掃描,發(fā)現(xiàn)訂單狀態(tài)是初始的話,就對用戶的支付余額進行解凍處理。這個時候用戶的余額變成100,訂單數(shù)據(jù)和支付數(shù)據(jù)又一致了。假設原先用戶余額只有100,被凍結了,用戶重新下單,支付的時候就失敗了啊,的確會發(fā)生這一種情況,所以要盡可能的保證在第一次訂單結果不明確的情況,盡早解凍用戶余額,比如10秒之內。但是不管如何快速,總有數(shù)據(jù)不一致的時刻,這個是沒有辦法避免的。上面分析解決了第一個的問題以及相應的方案,發(fā)現(xiàn)在數(shù)據(jù)分布的環(huán)境下,很難絕對的保證數(shù)據(jù)一致性(任何一段區(qū)間),但是有辦法通過一種補償機制,最終保證數(shù)據(jù)的一致性。下面再分析一下第二個問題:訂單系統(tǒng)調用支付系統(tǒng)成功,狀態(tài)也已經(jīng)更新成功,但是通知倉庫發(fā)貨失敗,這個時候訂單是P(已支付)狀態(tài),此時會員帳戶余額是100,但是倉庫不會發(fā)貨。會員也要罵京東。通過上面的分析,這個相對來說是比較簡單的,我可以采取重試機制,如果發(fā)現(xiàn)通知倉庫發(fā)貨失敗,就一致重試,這里面有兩種方式:1異步方式:通過類似MQ(消息通知)的機制,這個是異步的通知2同步調用:類似于遠程過程調用對于同步的調用的方式,比較簡單,我們能夠及時獲取結果;對于異步的通知,就必須采用請求,應答的方式進行,這一點在(關于分布式系統(tǒng)的數(shù)據(jù)一致性問題(一))里面有介紹。這里面就不再闡述。來看看第三個問題:訂單系統(tǒng)調用支付系統(tǒng)成功,狀態(tài)也已經(jīng)更新成功,然后通知倉庫發(fā)貨,倉庫告訴訂單系統(tǒng),沒有貨了。這個時候數(shù)據(jù)狀態(tài)和第二種情況一樣。我覺得這是一個很有意思的問題,我們還是考慮幾種解決的方案1在會員下單的時刻,就告訴倉庫,我要你把貨物留下來,2在會員支付訂單時候,在支付之前檢查倉庫有沒有貨,如果沒有貨,就告知會員木有貨物了3如果會員支付成功,這個時候沒有貨了,就會退款給用戶或者等待有貨的時候再發(fā)貨正常情況,京東的倉庫一般都是有貨的,所以影響到的會員很少,但是在秒殺和營銷的時候,這個時候就不一定了,我們考慮假設倉庫有10臺iphone如果采用第一種方案,1在會員下單的時候,相當于庫存就減1,那么用戶惡意拍下來,沒有去支付,就影響到了其他用戶的購買。京東可以設置一個訂單超時時間,如果這段時間內沒有支付,就自動取消訂單2在會員支付之前,檢查倉庫有貨,這種方案了,對于用戶體驗不好,但是對于京東比較好,至少我東西都賣出去了。那些沒有及時付款的用戶,只能投訴了京東無故取消訂單3第三種方案,這個方案體驗更不好,而且用戶感覺受到京東欺詐,但是對于京東來說,比第二種方案更有益,畢竟我還可以多賣出一點東西。個人覺得,京東應該會采用第二種或者第三種方式來處理這類情況,我在微博上搜索了“京東無故取消訂單”,發(fā)現(xiàn)果真和我預料的處理方式。不過至于這里的無故取消是不是技術上的原因我不知道,如果真的是技術上的原因,我覺得京東可以采用不同的處理方案。對于秒殺和促銷商品,可以考慮第一種方案,大多數(shù)人都會直接付款,畢竟便宜啊,如果用戶搶不到便宜的東西,抱怨當然很大了。這樣可以照顧大多數(shù)用戶的體驗。對于一般的訂單,可以采用第二種或者第三種方式,這種情況下,發(fā)生付款之后倉庫沒有貨的情況會比較少,并且就算發(fā)生了,用戶也會覺得無所謂,大不了退錢嗎,這樣就可以實現(xiàn)自己的利益最大化而最低程度的減少用戶體驗。而鐵道部在這個問題上,采用的是第一種方案,為什么和京東不一樣,就是因為用戶體驗,如果用戶把票都買了,你告訴我木有票了,旅客會殺人的。哈哈,不過鐵道部不擔心票賣不出去,第一種方案對他影響沒有什么。說了這么多,就是說分布式環(huán)境下(數(shù)據(jù)分布)要任何時刻保證數(shù)據(jù)一致性是不可能的,只能采取妥協(xié)的方案來保證數(shù)據(jù)最終一致性。這個也就是著名的CAP定理。在前面的文章中,介紹了關于分布式系統(tǒng)中數(shù)據(jù)一致性的問題,這一篇主要介紹CAP定理以及自己對CAP定理的了解。CAP定理是2000年,由EricBrewer提出來的。Brewer認為在分布式的環(huán)境下設計和部署系統(tǒng)時,有3個核心的需求,以一種特殊的關系存在。這里的分布式系統(tǒng)說的是在物理上分布的系統(tǒng),比如我們常見的web系統(tǒng)。這3個核心的需求是:Consistency,Availability和PartitionTolerance,賦予了該理論另外一個名字-CAP。Consistency:一致性,這個和數(shù)據(jù)庫ACID的一致性類似,但這里關注的所有數(shù)據(jù)節(jié)點上的數(shù)據(jù)一致性和正確性,而數(shù)據(jù)庫的ACID關注的是在在一個事務內,對數(shù)據(jù)的一些約束。Availability:可用性,關注的在某個結點的數(shù)據(jù)是否可用,可以認為某一個節(jié)點的系統(tǒng)是否可用,通信故障除外。PartitionTolerance:分區(qū)容忍性,是否可以對數(shù)據(jù)進行分區(qū)。這是考慮到性能和可伸縮性。為什么不能完全保證這個三點了,個人覺得主要是因為一旦進行分區(qū)了,就說明了必須節(jié)點之間必須進行通信,涉及到通信,就無法確保在有限的時間內完成指定的行文,如果要求兩個操作之間要完整的進行,因為涉及到通信,肯定存在某一個時刻只完成一部分的業(yè)務操作,在通信完成的這一段時間內,數(shù)據(jù)就是不一致性的。如果要求保證一致性,那么就必須在通信完成這一段時間內保護數(shù)據(jù),使得任何訪問這些數(shù)據(jù)的操作不可用。如果想保證一致性和可用性,那么數(shù)據(jù)就不能夠分區(qū)。一個簡單的理解就是所有的數(shù)據(jù)就必須存放在一個數(shù)據(jù)庫里面,不能進行數(shù)據(jù)庫拆分。這個對于大數(shù)據(jù)量,高并發(fā)的互聯(lián)網(wǎng)應用來說,是不可接受的。我們可以拿一個簡單的例子來說明:假設一個購物系統(tǒng),賣家A和賣家B做了一筆交易100元,交易成功了,買家把錢給賣家。這里面存在兩張表的數(shù)據(jù):Trade表Account表,涉及到三條數(shù)據(jù)Trade(100),AccountA,AccountB假設trade表和account表在一個數(shù)據(jù)庫,那么只需要使用數(shù)據(jù)庫的事務,就可以保證一致性,同時不會影響可用性。但是隨著交易量越來越大,我們可以考慮按照業(yè)務分庫,把交易庫和account庫單獨分開,這樣就涉及到trade庫和account庫進行通信,也就是存在了分區(qū),那么我們就不可能同時保證可用性和一致性。我們假設初始狀態(tài)trade(buyer,seller,tradeNo,status)=trade(A,B,20121001,I)account(accountNo,balance)=account(A,300)account(accountNo,balance)=account(B,10)在理想情況下,我們期望的狀態(tài)是trade(buyer,seller,tradeNo,status)=trade(A,B,20121001,S)account(accountNo,balance)=account(A,200)account(accountNo,balance)=account(B,110)但是考慮到一些異常情況假設在trade(20121001,S)更新完成之后,帳戶A進行扣款之前,帳戶A進行了另外一筆300款錢的交易,把錢消費了,那么就存在一個狀態(tài)trade(buyer,seller,tradeNo,status)=trade(A,B,20121001,S)account(accountNo,balance)=account(A,0)account(accountNo,balance)=account(B,10)產(chǎn)生了數(shù)據(jù)不一致的狀態(tài)由于這個涉及到資金上的問題,對資金要求比較高,我們必須保證一致性,那么怎么辦,只能在進行trade(A,B,20121001)交易的時候,對于任何A的后續(xù)交易請求trade(A,X,X),必須等到A完成之后,才能夠進行處理,也就是說在進行trade(A,B,20121001)的時候,Account(A)的數(shù)據(jù)是不可用的。任何架構師在設計分布式的系統(tǒng)的時候,都必須在這三者之間進行取舍。首先就是是否選擇分區(qū),由于在一個數(shù)據(jù)分區(qū)內,根據(jù)數(shù)據(jù)庫的ACID特性,是可以保證一致性的,不會存在可用性和一致性的問題,唯一需要考慮的就是性能問題。對于可用性和一致性,大多數(shù)應用就必須保證可用性,畢竟是互聯(lián)網(wǎng)應用,犧牲了可用性,相當于間接的影響了用戶體驗,而唯一可以考慮就是一致性了。犧牲一致性對于犧牲一致性的情況最多的就是緩存和數(shù)據(jù)庫的數(shù)據(jù)同步問題,我們把緩存看做一個數(shù)據(jù)分區(qū)節(jié)點,數(shù)據(jù)庫看作另外一個節(jié)點,這兩個節(jié)點之間的數(shù)據(jù)在任何時刻都無法保證一致性的。在web2.0這樣的業(yè)務,開心網(wǎng)來舉例子,訪問一個用戶的信息的時候,可以先訪問緩存的數(shù)據(jù),但是如果用戶修改了自己的一些信息,首先修改的是數(shù)據(jù)庫,然后在通知緩存進行更新,這段期間內就會導致的數(shù)據(jù)不一致,用戶

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論