架構師之路,分佈式架構下數據庫一致性常用方法初探

我們都知道絕大多數的互聯網的應用都是讀多寫少的應用,我們也經常使用一主多從這樣的模式,一是可以提高性能,二是多了一個數據備份,提高了程序的可用性。

主從數據庫如何保持數據一致性,一直都是分佈式系統一個值得探討的問題,也幾乎是BAT後臺開發必問的面試題。我們今天就來講一講,如何保持分佈式系統下數據庫一主多備的數據一致性。


架構師之路,分佈式架構下數據庫一致性常用方法初探


問題的由來

上圖就是我們最常使用的數據庫主備模型,這個模型有什麼問題呢?我們不凡假設存在這麼一個場景,用戶收藏了一個商品,又立馬刷新的數據庫,這個時候後臺再去讀寫從庫的數據,如果數據還沒有同步到,就會發現自己怎麼還沒有收藏這個商品。覺得程序bug了。

方案一:

最笨的方法,就是強制讀讀主庫的數據了,對於一些update操作後重新讀比較多的場景,我們強制要求讀主庫,或者在更新DB後立馬返回主庫更新後的結果,減少更新後立馬讀取數據的業務場景。


架構師之路,分佈式架構下數據庫一致性常用方法初探


這種架構模型我們幾乎就不用擔心數據一致性的問題了,當然,如果主數據宕機了,從數據庫可能還沒同步都最新的數據,這就造成了數據丟失了。

這種方法的優點是操作簡單,邏輯簡單,缺點也是非常明顯那就是從數據庫完全成為一個備庫,對性能上沒有絲毫的幫助。為了提升性能,我們只能業務進行緩存了。

方案二:

利用數據庫的半同步複製。以Mysql為例,Mysql為我們提供了好幾種不同的主從數據庫同步方式,如:

全同步複製:指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。很明顯,全同步的效率太低了。假設又一個從庫,寫主庫需要話200ms的時間,那麼,使用全同步複製的話一個請求會至少需要400ms+的時間(雙倍的寫時間加上一定的TCP往返時間)。

異步複製:

MySQL默認的複製即是異步的,主庫在執行完客戶端提交的事務後會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理。這個會造成可能主庫已經寫完了,但是從庫的數據還沒有同步,讀到的可能是舊數據。另外一方面,如果某個時間主DB宕機了,那麼從庫還沒有同步到最新的數據。

半同步複製:介於異步複製和全同步複製之間,主庫在執行完客戶端提交的事務後不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。這是一個相對摺衷的方案,我們來看看這個東西是怎麼實現。


架構師之路,分佈式架構下數據庫一致性常用方法初探


業務方提交一個寫操作給數據庫,主數據庫寫完記錄後,commit成功後,會像從庫發起寫bin log的請求,因為寫日誌的數據實際上非常的快,寫完就返回,相當於一次寫操作要多一次tcp的往返時間。

事實上,從主庫返回成功,到備庫異步提交成功,還是有一定的時間差,不過這個時間相對於異步複製,已經大大減少了。

方案三:

使用數據庫中間件進行路由,由數據庫中間件進行路由。


架構師之路,分佈式架構下數據庫一致性常用方法初探


一般的做法是我們的數據庫中間件維護一個cache,我們預估好數據庫主從同步的時間,例如200ms,如果某個key在200ms裡面更新過,那麼就讀取主庫的數據,否則就讀從庫的數據。除此之外,我們也會維護一定的數據緩存,在Update的時候,同時把主庫的數據select出來,放在緩存中,加快數據庫的讀取速度。

這種方案就相對與前面兩種,又更進了一步,但是改造成本更大了。好了,今天分佈式的數據庫主從一致性我們就講到這裡。想知道阿里巴巴是怎麼做的麼?想知道微信是怎麼做的麼?歡迎關注我,後面我們會繼續分析。大家共同學習,共同進步。


分享到:


相關文章: