前幾天跟朋友聊到這個話題导盅,當時沒有想到分布式鎖,后在google上查詢揍瑟,發(fā)現(xiàn)這篇文章邏輯比較清楚——交易系統(tǒng)在分布式環(huán)境下的探討
眾所周知在互聯(lián)網(wǎng)公司白翻,如果你沒有對你的系統(tǒng)進行分庫分表,那你怎么好意思跟人打招呼月培?但是分庫分表帶來的難題也是眾所周知的嘁字,除了多機查詢(分批查詢、合并結(jié)果等等)等問題杉畜,最重要的就是保障事務問題纪蜒,這一點在交易系統(tǒng)中尤為重要。
最為簡單的解決方式就是使用分布式事務此叠,業(yè)界已經(jīng)有了規(guī)范–XA纯续,他使用兩階段提交來保證分布式下的事務,具體的規(guī)范我就不說了灭袁,可以到維基百科上詳細了解猬错,看似完美,但是這個解決方案在分庫分表的環(huán)境下有些“重”茸歧。我們完全可以退一步來想倦炒,我們既然不能保證強一致性,那么我們保證最終一致性也可以達到理想的結(jié)果软瞎。我們主要依托如下兩個理論來構(gòu)建一個最終一致性的系統(tǒng):CAP理論逢唤、BASE模型拉讯。
讓我們舉個栗子來說明:假如一個用戶在亞馬遜上買了一本書,用戶需要做的就是點擊生成訂單鳖藕,而后付款最后等待收貨魔慷,此時從技術的角度來看,我們大致有四個系統(tǒng):用戶系統(tǒng)著恩,賬戶系統(tǒng)院尔,訂單系統(tǒng),物流系統(tǒng)喉誊,而訂單的狀態(tài)變化大致如下:初始–已支付–已發(fā)貨–完成邀摆。正常情況下訂單狀態(tài)會依次變更,而后亞馬遜收到錢款后組織發(fā)貨裹驰。但是在現(xiàn)實中就沒有那么幸福了隧熙,用戶付款后亞馬遜沒收到錢,收到錢后沒有告知用戶發(fā)貨幻林。因為這四個系統(tǒng)所使用的DB、JVM甚至機房都不一樣音念。對于用戶系統(tǒng)沪饺,習慣上對于整個交易系統(tǒng)來講它是用戶展示結(jié)果的所有我們暫時不去討論,那么對于賬戶系統(tǒng)闷愤,不管用戶使用賬戶余額支付還是使用網(wǎng)絡支付整葡,最終的結(jié)構(gòu)都是用戶的余額減少而商家的余額增加。
那么對于這個局部的交易過程(用戶余額減少–商家余額增加)讥脐,我們同樣不敢肯定其是否同處一個DB遭居,所以我們使用分布式鎖保證同一時間對該資源(賬戶余額)的其他操作是不可用的(比如同一時刻對該余額做減少操作)。這樣我們保證了用戶余額減少–商家余額增加這一過程結(jié)果的可控性旬渠,在分布式這方面俱萍,memcache和Redis等都可實現(xiàn)分布式鎖。
下面我們討論當用戶的支付過程完成之后的事情告丢,順利的情況下訂單系統(tǒng)拿到支付成功的結(jié)果后將訂單狀態(tài)更新為支付成功枪蘑。可是假如在這個過程岖免,因為超時抑或其他原因岳颇,導致用戶支付成功,而訂單狀態(tài)已然是未支付該怎么辦颅湘?這時候我們有兩種選擇:輪訓查詢幾次支付結(jié)果而后更新訂單狀態(tài)话侧,此為同步過程。引入消息中間件闯参,將此過程解耦成異步過程瞻鹏。顯然我們應該使用異步方式更優(yōu)雅悲立,并且解耦之后的擴展性更強。那么如何實現(xiàn)呢乙漓,我簡單說下:支付成功之后賬戶系統(tǒng)發(fā)送消息到MQ级历,訂單系統(tǒng)輪詢MQ獲取最新消息,根據(jù)消息更新訂單狀態(tài)叭披。這樣的結(jié)果就是用戶系統(tǒng)首先依然認為訂單未支付并展示給用戶寥殖,而后臺處理完后可以等待用戶主動獲取訂單狀態(tài)(刷新頁面,京東上就是如此)涩蜘,也可以更高端的主動推送信息給用戶嚼贡。那么物流狀態(tài)依然引入MQ來完成異步化的操作。
看似我們的這個過程已經(jīng)“優(yōu)雅”的完成了同诫,用戶看到了支付狀態(tài)又看到了發(fā)貨提醒粤策,安心的等待中。
后記:還需繼續(xù)思考的點
- 分布式鎖的競態(tài)處理误窖;
- 消息發(fā)送的一致性(100%保證消息送達)