應用系統中的關鍵服務絕大部分都會是對數據庫的依賴。前端
當多個進程同時操做同一個數據,會產生資源爭搶,數據一致性的問題。數據庫
若是隻有一個數據庫服務器,數據一致性問題也就不存在了。後端
但是,隨着系統訪問量、數據量的不斷增加,數據庫出現多個服務器,又出現緩存服務,又要拆分數據庫,還要分拆到不一樣的子應用等等。緩存
這樣一來,數據一致性問題就會變得愈來愈突出。服務器
咱們來看這樣一個數據流程。併發
用戶提交一個訂單(2個不一樣商家各一件商品)——數據源頭分佈式
應用服務器驗證用戶信息、訂單信息、庫存信息等等,而後將這個訂單發送到訂單消息隊列——消息隊列性能
訂單處理服務器從消息隊列中拿到新訂單,接下來的處理,可能作的數據操做有:網站
生成一個訂單/也可能會分拆爲兩個訂單3d
更新兩個商品庫存數量
更新商家的銷售數據
生成訂單對應的支付信息
生成用戶訂單成功的狀態信息
上面的數據處理中,涉及到的數據有:訂單數據、商品數據、商家數據、支付數據、用戶數據。
涉及到的應用和服務有:前端應用系統,消息隊列,後端應用系統,數據庫,緩存,甚至訂單、商品、商家、支付、用戶可能都是獨立的子應用。
可能大部分系統不會像上面這麼龐大。
若是先後端都是一塊兒的,也就沒有消息隊列。
若是也沒有這些子系統,數據庫是集中的,那可能數據一致性問題會稍微小些。
這時候,只須要注意數據庫更新的一致性就行了,比較容易想到的應對方法,就是用數據庫事務來保證。
若是這些數據不僅是一份數據庫,還有緩存中一份,又要考慮緩存數據的更新,因此問題仍是複雜了。
程序中處理,數據庫更新後,就要立刻更新緩存數據
若是緩存更新失敗或者程序出現異常,要有異常處理方法
異常處理方法能夠是程序中實時的糾正或者重試
異常處理方法也能夠是針對數據庫的更新,二次檢查緩存數據的更新
這裏還只是一個數據庫和一個緩存的狀況,已經要作出這麼多事情。
程序開發更加複雜,不能有些許的遺漏
數據驗證和重試帶來的性能降低
數據庫事務帶來的數據庫瓶頸明顯
二次檢查再次增長複雜度和額外開銷
原本一個訂單處理,若是不考慮數據一致性問題,數據庫寫入/更新510次,緩存寫入/更新510次,整個過程應該在10ms內完成。
可是加上數據庫事務以後,會把這些操做中涉及到的幾個表都加鎖,意味着數據的讀、寫都串行化了,整個應用系統的併發能力急劇降低。
固然,由於這裏引入緩存,對數據庫的依賴會減小不少,並且還有從庫能夠提供讀的服務,應用系統的訪問併發能力不至於降低太多。
但這些代價在交易處理中是難以免的,爲了解決數據一致性問題,犧牲的是訂單處理的併發能力。
對於大部分商城、網站,訂單併發量也不高,這類問題不太常發生,因此也就這麼過去了。
可是在一些促銷活動的時候,確定仍是會遇到下單等待過久的問題。
爲了具有更大併發的訂單處理能力,單數據庫、緩存確定是行不通了。
那麼要在這麼多的子應用、大量的數據庫、緩存服務中保持數據一致性又要怎麼作呢?
每一個子應用都要支持分佈式事務,共同保證數據庫所有成功更新
每一個子應用各自要保證本身的數據更新一致性(異常處理、重試、二次檢查等方法同上)
上面看上去只有兩條,可是要作的事情和困難會比上面要多十倍,難百倍。
看到這裏,是否是對於數據一致性的問題都有點絕望了。
正因如此,大部分的分佈式系統,大部分應用,是沒有作到數據一致性,哪怕是弱一致性。
好比:論壇裏面發帖,要更新10份左右的數據,出現髒數據是常有的,這就是沒有作到數據一致性。
好比:商城裏面庫存超賣,訂單狀態不一致等,也是由於沒有作到數據一致性。
之因此會這樣,由於投入產出嚴重不成比例,是很無奈的選擇。
數據不一致的狀況畢竟比例極低,可是投入的代價卻極大。
數據不一致引起的後果,能夠忍受和容忍,哪怕是發現後再修正。
下面有幾個方法能夠考慮:
一個每秒鐘上百萬請求的應用系統能不能分拆爲1000個每秒鐘1000請求的獨立集羣呢?
一個上百萬的商家、商品、訂單庫,能不能分拆爲1000個只有1000個商家、商品、訂單的子庫呢?
上面的訂單、庫存、商家、支付、用戶幾個數據,核心數據只有訂單,其餘的幾個數據徹底能夠從訂單數據推導出來,減小訂單處理中的一致性要求。
減小業務耦合,集中資源重點投入。