前幾天跟朋友聊到這個(gè)話題,當(dāng)時(shí)沒有想到分布式鎖,后在google上查詢,發(fā)現(xiàn)這篇文章邏輯比較清楚——交易系統(tǒng)在分布式環(huán)境下的探討
眾所周知在互聯(lián)網(wǎng)公司,如果你沒有對(duì)你的系統(tǒng)進(jìn)行分庫分表,那你怎么好意思跟人打招呼?但是分庫分表帶來的難題也是眾所周知的,除了多機(jī)查詢(分批查詢、合并結(jié)果等等)等問題,最重要的就是保障事務(wù)問題,這一點(diǎn)在交易系統(tǒng)中尤為重要。
最為簡單的解決方式就是使用分布式事務(wù),業(yè)界已經(jīng)有了規(guī)范–XA,他使用兩階段提交來保證分布式下的事務(wù),具體的規(guī)范我就不說了,可以到維基百科上詳細(xì)了解,看似完美,但是這個(gè)解決方案在分庫分表的環(huán)境下有些“重”。我們完全可以退一步來想,我們既然不能保證強(qiáng)一致性,那么我們保證最終一致性也可以達(dá)到理想的結(jié)果。我們主要依托如下兩個(gè)理論來構(gòu)建一個(gè)最終一致性的系統(tǒng):CAP理論、BASE模型。
讓我們舉個(gè)栗子來說明:假如一個(gè)用戶在亞馬遜上買了一本書,用戶需要做的就是點(diǎn)擊生成訂單,而后付款最后等待收貨,此時(shí)從技術(shù)的角度來看,我們大致有四個(gè)系統(tǒng):用戶系統(tǒng),賬戶系統(tǒng),訂單系統(tǒng),物流系統(tǒng),而訂單的狀態(tài)變化大致如下:初始–已支付–已發(fā)貨–完成。正常情況下訂單狀態(tài)會(huì)依次變更,而后亞馬遜收到錢款后組織發(fā)貨。但是在現(xiàn)實(shí)中就沒有那么幸福了,用戶付款后亞馬遜沒收到錢,收到錢后沒有告知用戶發(fā)貨。因?yàn)檫@四個(gè)系統(tǒng)所使用的DB、JVM甚至機(jī)房都不一樣。對(duì)于用戶系統(tǒng),習(xí)慣上對(duì)于整個(gè)交易系統(tǒng)來講它是用戶展示結(jié)果的所有我們暫時(shí)不去討論,那么對(duì)于賬戶系統(tǒng),不管用戶使用賬戶余額支付還是使用網(wǎng)絡(luò)支付,最終的結(jié)構(gòu)都是用戶的余額減少而商家的余額增加。
那么對(duì)于這個(gè)局部的交易過程(用戶余額減少–商家余額增加),我們同樣不敢肯定其是否同處一個(gè)DB,所以我們使用分布式鎖保證同一時(shí)間對(duì)該資源(賬戶余額)的其他操作是不可用的(比如同一時(shí)刻對(duì)該余額做減少操作)。這樣我們保證了用戶余額減少–商家余額增加這一過程結(jié)果的可控性,在分布式這方面,memcache和Redis等都可實(shí)現(xiàn)分布式鎖。
下面我們討論當(dāng)用戶的支付過程完成之后的事情,順利的情況下訂單系統(tǒng)拿到支付成功的結(jié)果后將訂單狀態(tài)更新為支付成功??墒羌偃缭谶@個(gè)過程,因?yàn)槌瑫r(shí)抑或其他原因,導(dǎo)致用戶支付成功,而訂單狀態(tài)已然是未支付該怎么辦?這時(shí)候我們有兩種選擇:輪訓(xùn)查詢幾次支付結(jié)果而后更新訂單狀態(tài),此為同步過程。引入消息中間件,將此過程解耦成異步過程。顯然我們應(yīng)該使用異步方式更優(yōu)雅,并且解耦之后的擴(kuò)展性更強(qiáng)。那么如何實(shí)現(xiàn)呢,我簡單說下:支付成功之后賬戶系統(tǒng)發(fā)送消息到MQ,訂單系統(tǒng)輪詢MQ獲取最新消息,根據(jù)消息更新訂單狀態(tài)。這樣的結(jié)果就是用戶系統(tǒng)首先依然認(rèn)為訂單未支付并展示給用戶,而后臺(tái)處理完后可以等待用戶主動(dòng)獲取訂單狀態(tài)(刷新頁面,京東上就是如此),也可以更高端的主動(dòng)推送信息給用戶。那么物流狀態(tài)依然引入MQ來完成異步化的操作。
看似我們的這個(gè)過程已經(jīng)“優(yōu)雅”的完成了,用戶看到了支付狀態(tài)又看到了發(fā)貨提醒,安心的等待中。
后記:還需繼續(xù)思考的點(diǎn)
- 分布式鎖的競態(tài)處理;
- 消息發(fā)送的一致性(100%保證消息送達(dá))