當前位置:
首頁 > 知識 > 快狗打車CTO沈劍:資料庫架構一致性最佳實踐

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

本文根據沈劍在2018年10月18日【第十屆中國系統架構師大會(SACC2018)】現場演講內容整理而成。

講師介紹:

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

打開今日頭條,查看更多精彩圖片

沈劍,快狗打車CTO,互聯網架構技術專家,「架構師之路」公眾號作者。曾任百度高級工程師,58同城高級架構師,58同城技術委員會主席。2015年調至58到家任高級總監,技術委員會主席,負責基礎架構,技術平台,運維安全,信息系統等後端技術體系搭建。現任快狗打車CTO,負責快狗打車技術體系的搭建,本質是技術人一枚。

本文摘要:

沈劍分享了快狗打車資料庫架構的一致性實踐,在一致性實踐的過程中,能夠體現快狗打車資料庫架構的演進歷程。從單庫到多庫再到高可用等等,包括在研究的過程中,每個階段可能會碰到不同的問題,快狗打車是採用一些什麼樣的技術手段去解決這些問題?以快狗打車的實踐跟大家做一些分享。

分享大綱:

主從不一致,優化實踐

緩存不一致,優化實踐

數據冗餘不一致,優化實踐

多庫事務不一致,優化實踐

總結

演講正文:

快狗打車(原58速運)是一個創業型公司,技術架構、技術體系、資料庫架構的變遷,和在座很多公司是很相近的,今天和大家聊一聊,我們在快狗打車資料庫架構一致性方面碰到一些問題。

不一致的優化歷程,也是資料庫架構演進的過程

主線是我們的資料庫架構變化的過程,在這個過程中,我列出了四個跟一致性相關的節點,主從會不一致、緩存會不一致、冗餘數據會不一致、多庫多實例會不一致。不一致的優化歷程,也是我們資料庫架構演進的一個過程。從單庫到現在,有哪些坑在等著我們呢?


快狗打車CTO沈劍:資料庫架構一致性最佳實踐

先看一下,最初的資料庫架構,最早是這個樣子的。那個時候沒有什麼微服務分層, web通過DAO訪問一個單庫資料庫,最早我這麼玩的。單庫,它不具備什麼高可用,高並發特性,擴展性也比較差。我相信很多創業公司初期也是這樣。

單庫最早會遇到什麼樣的瓶頸呢?在創業的時候,數據量變大了,並發量大了,業務變複雜了,整個系統的瓶頸最先出現在哪裡?我的經驗是資料庫。資料庫的瓶頸又會在哪裡?我的經驗是讀。因為絕大部分的業務是讀多寫少的業務,讀,最容易稱為系統的瓶頸。

最早在資料庫讀扛不住的時候,最先想到的優化方式是什麼?互聯網公司都講快,今天出問題,能不能明天後天給我搞定?最先想到的方案是什麼,如何能快速擴充資料庫的讀性能呢?

快狗打車CTO沈劍:資料庫架構一致性最佳實踐


加兩個實例,主從同步,讀寫分離,這是創業型公司,當資料庫讀成為瓶頸的時候,最先想到的方案,快速擴充讀性能。主從同步碰到的問題是什麼?這就是本主題要講的第一個問題,主從一致性的問題。

當數據量越來越多,吞吐量越來越大的時候,寫到了主庫,主庫同步到從庫,主從同步存在延時,在延時窗口期內,讀寫分離去讀從庫,就有可能讀到一個舊數據。這個問題,我相信大家也會碰到。

對於這個問題,不少接業務的解法方案是,忍,有些業務如果對一致性的要求沒這麼高。但有沒有優化方案呢?

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

這兩個圖是我們的兩個常見的實踐。

第一個是中間件,我們的服務層或者站點層不直接調資料庫,通過一個中間層,去調資料庫。中間層它能夠知道哪一個庫,哪一個表,哪一個KEY發生了寫操作,如果說接下來的這一段時間(假設主從同步一秒鐘完成),有讀請求落到從庫上,就會讀到舊數據。那麼此時,中間件就要將讀請求,路由到主庫上去,讀新數據。

第二個是強制讀主。第二個圖,雙主同步,強制讀主有什麼好處?第一解決了高可用問題,雙主使用同一個VIP,一個主庫如果掛了,另一個主庫能隨時頂上,保障高可用。第二避免了主從之間的不一致。

強制讀主它帶來的新的問題是什麼呢?解決了一致性問題,但讀性能擴展的問題又來了,主庫抗讀寫,還是沒有解決讀性的擴大的問題。

除了增加從庫,互聯網公司還有一種常見的提升系統讀性能的方式,緩存加服務化。抽象出服務層,向調用方屏蔽底層資料庫的複雜性,屏蔽資料庫的高可用的複雜性,屏蔽緩存的複雜性,對業務層提供服務。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

服務化加緩存確實是提升系統讀容量的架構方案。通過緩存來提升讀性,又會遇到什麼新的問題呢?用主從架構,有主從不一致問題;用緩存架構,當然也有緩存不一致的問題。只要你把同一份數據放在了多個地方,多個地方的修改有時間差,這個時間差就會有數據訪問不一致的問題。

當我們出現資料庫與緩存中的數據不一致的時候,我們怎麼來解決?

首先來看一下為什麼會不一致。緩存的常用玩法是「Cache Aside Pattern」。Cache Aside Pattern,旁路緩存,一般是怎麼玩的?淘汰緩存,而不是更新緩存,這是Cache Aside Pattern的結論。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

讀寫時序是什麼樣的?對於讀請求有緩存,毫無爭議的,先讀緩存,如果數據命中我就直接返回,如果數據沒有命中,讀從庫讀寫分離,把這個數據從從庫里拿出,放到緩存里,這是讀請求的一個流程。

對於寫請求,Cache Aside Pattern的做法是,先寫資料庫,再淘汰緩存。在什麼情況下會出現不一致?當並發量相對會比較高時,對於同一個KEY做了一個寫操作,馬上又來了一個讀操作,會出現什麼樣的情況?先發生一個寫操作,先更新到資料庫,淘汰了Cache,馬上又來了一個讀操作,這個時候主從同步還沒同步完成,先讀緩存,緩存被剛剛的寫操作已經淘汰掉了,又去讀從庫,把從庫的臟數據拿過來放到緩存里去,不一致就出現。

高並髮狀態下,寫後立即讀的場景,容易出現臟數據入Cache。

大家發現沒有,這裡的數據不一致,比主從的數據不一致的情況更嚴重。主從不一致,只有一個主動同步時間差不一致,同步之後,從庫就能讀到新數據了。但是緩存與資料庫的不一致,它會導致後續一直不一致,一旦臟數據入了緩存,臟數據會延續到下一個寫發生的時候才會被淘汰掉,所以它其實更嚴重。

如何來解決呢?緩存和資料庫的數據不一致,我們的兩個實踐:非同步淘汰緩存,確保從庫已經同步成功;設定超時時間,極限情況下有機會修正。

第一個,等從庫已經完全同步成功,再去非同步淘汰緩存?只要監聽從庫的binlog,從庫binlog完成,一定是寫操作執行完畢,此時再淘汰緩存,就能避免時間差。

第二個,就是如果允許Cache miss,不要將緩存過期時間設為永久,如果你設置為無限長的過期時間,就沒有一個機會去修正不一致了。

隨著業務的發展,除了流量的增加,我們要提升系統的讀性能,我們要提升系統的資料庫高可用,還會面臨一個什麼問題?對了,數據量會增大。我們業務數據量越來越大了,通常採用什麼樣的方式去解決?創業型公司,這兩個方案應該是大家用得最多的。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

第一個,分庫。降低每個庫,降低每個實例的數據量,這樣就能夠承載更多的數據。分庫又帶來什麼新的問題?舉了個例子,訂單一個庫,它有多個維度的查詢,有訂單ID的查詢,有用戶ID的查詢,有司機ID的查詢,一個庫沒有任何問題。

但分庫以後,變成多個庫以後,一旦用了一個維度分庫,你會發現其他的維度的查詢就要變成多個庫了,是不是?

一般來說是通過用戶的ID去分庫,在訂單ID里去放上分庫因子,這樣通過用戶ID以及訂單ID都能夠定位到相關數據。但是對於司機ID就不同了,司機ID和用戶ID是一個多對多的關係。一個用戶他可能下了多個司機的單,一個司機接了多個用戶的單,通過司機ID去查詢,並不能一次性查詢到所有的數據,同一個司機的訂單一定是分布在多個庫里。怎麼辦呢?此時最常用解決方案是,數據冗餘。

我用一個存儲元數據,用一個存儲關係數據,元數據通過用戶ID來分庫,保證同一個用戶的所有訂單在一個庫里。關係數據用司機ID來分庫,保證同一個司機的所有訂單在一個庫里。同一份數據,由於它存在兩個維度的查詢,這兩個維度查詢都可以不誇庫,而通過數據冗餘來實現,這個在業內屬於很常見的方案。

數據冗餘,又會出現什麼問題?一起來看一下。上面是應用,中間是服務,一個數據存在兩個庫里,一個庫是通過用戶ID分庫,一個庫是通過司機ID去分庫,調用方來了一個請求,先要往第一份數據里寫一個數據,再往另外一個庫里寫一個冗餘數據。能保證冗餘數據的一致性么?是不能夠保證,這兩個庫同時寫成功的,那怎麼辦呢?

這就是冗餘數據的一致性問題。數據冗餘數據的不一致優化,今天介紹三種方法,其實本質的方法論都是最終一致性。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

第一個方案是掃全量。怎麼發現冗餘數據不一致?寫個腳本,每天晚上跑,理論上A庫里有的B庫裡面也有,一旦掃庫發現怎麼A庫有B庫里沒有,就是出現不一致了,就要根據業務特性來做補償。到底是將後一半補進去,還是把前一半刪掉,跟業務特性相關,不過思路大致是這樣的,一個非同步的方式,最終來保證一致性。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

第二個方案是掃增量。通過服務操作兩個庫,寫成功第一個庫寫一條日誌,寫成功第二個庫再寫一條日誌。這些日誌里的就是每天改變的數據,每天不用掃描全量,只要掃描每天改變的數據就行了。如果掃描日誌不匹配,就通過非同步的方式修復,保證最終一致性。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

第三個方式,比前兩種方式更加實時。不寫日誌了,而是發消息。用一個消息組件,資料庫正向表操作成功了,發一個消息,冗餘表操作成功了,發另一個消息。用一個非同步的服務去監聽這兩個消息,如果只有一條消息到達,就去資料庫檢測一致性,並用非同步的方式來補償。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

最後是多實例多庫,這也是解決數據量大的一個常見方案。它會帶來什麼樣的不一致呢?這裡有一個案例,下單的一個操作,可能有三個數據要修改,一個是餘額的數據,我可能要扣減一些餘額;一個是訂單的數據,要新增一條訂單;一個是流水的數據,要新增一條流水。原來是單庫事務來保證一致性,現在數據量大了,變成多個庫,餘額是一個單獨的實例,訂單是一個單獨的實例,流水是一個單獨的實例,所以原來的一個事務,在多庫狀態下,就變成三個事務。

多實例,多庫事務,不一致,怎麼辦?這一塊我們有兩個優化實踐。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

第一個是補償事務,業內應該也經常用到補償事務。

餘額操作,正向的操作是扣減餘額,補償事務就是把餘額加回來。

訂單操作,正向的操作是新增訂單,補償事務就是把訂單刪除掉。

流水操作,正向的操作是新增流水,補償事務就是把流水刪除。

總之,補償事務就是當你發現前面的事務執行失敗的時候,要執行一個應用層的事務,回滾一個動作。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

另外一種方式,偽分散式事務的解決方案,是後置提交。

先細化的看一下三個事務是怎麼執行的?第一個事務先執行再提交,第二個事務執行再提交,第三個事務執行再提交。事務的執行過程很慢,事務的提交過程很快。上圖這個例子,可能執行時間200毫秒,提交時間幾毫秒,什麼時候會出現不一致呢?第一個事務提交成功之後,最後一個事務提交成功之前的中間,任何一個地方出現異常都會導致不一致。

優化其實也很簡單,後置提交。第一個事務執行,第二個事務執行,第三個事務執行;第一個事務提交,第二個事務提交,第三個事務提交。什麼時候會出現不一致呢?仍然是第一個事務提交成功之後,第三個事務提交成功之前的時間間隔,如果出現了,網路異常,伺服器掛了,就會不一致。但是這個間隔就只有後面的兩毫秒,所以整個不一致的概率是降低了百倍左右。

最後做一個簡單的總結。根據我的經驗,40分鐘50分鐘的一個技術分享,第二天能夠記住的只有10%。如果只記住10%,那我希望大家能夠記住這一頁的內容,並希望自己的邏輯是清晰的。

快狗打車CTO沈劍:資料庫架構一致性最佳實踐

資料庫架構最初是單庫,單庫會碰到什麼問題?會碰到讀性能瓶頸的問題。讀性能瓶頸最早用什麼樣的方式去解決?主從同步讀寫分離,它會帶來什麼問題?主從的不一致,用什麼方案解決?我們的實踐是中間件,以及強制讀主。

提升讀性能,服務化加緩存也是常見方案,帶來什麼新的問題?緩存和資料庫的不一致。在Cache Aside Pattern的情況下,有寫後立即讀的問題,舊數據可能入緩存。我們的實踐,可以通過非同步淘汰的方式,當寫操作在從庫上真正完成的時候再去淘汰緩存。同時,我們建議為所有允許Cache miss的數據設置超時時間。

資料庫架構,數據量大的問題,怎麼解決?常用的解決方案是分庫,多實例。分庫帶來什麼新的問題?記得我的例子么,分了庫之後,可以保證同一個用戶的數據在同一個庫里,不能夠保證同一個司機數據也在同一個庫里,怎麼解決?使用數據冗餘。冗餘帶來什麼問題?冗餘數據的不一致問題,方向是最終一致性。怎麼最終保證一致性?掃全量,掃增量,實時消息對。除了多庫,多實例也可以擴展數據存儲量,會遇到什麼問題?多庫的事務不能在保證原則性,補償事務,後置提交,都是我們的優化實踐。

今天的內容這麼多,希望大家有收穫,謝謝大家。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT168企業級 的精彩文章:

Splunk>live!2018北京開講:合格的大數據處理平台是什麼樣子?
AI訓練場:英特爾-南京大學人工智慧聯合研究中心成立

TAG:IT168企業級 |