快狗叫車CTO沈劍:資料庫架構一致性最佳實踐
本文根據沈劍在2018年10月18日【第十屆中國系統架構師大會(SACC2018)】現場演講內容整理而成。
講師介紹:
沈劍,快狗叫車CTO,網際網路架構技術專家,“架構師之路”公眾號作者。曾任百度高階工程師,58同城高階架構師,58同城技術委員會主席。2015年調至58到家任高階總監,技術委員會主席,負責基礎架構,技術平臺,運維安全,資訊系統等後端技術體系搭建。現任快狗叫車CTO,負責快狗叫車技術體系的搭建,本質是技術人一枚。
本文摘要:
沈劍分享了快狗叫車資料庫架構的一致性實踐,在一致性實踐的過程中,能夠體現快狗叫車資料庫架構的演進歷程。從單庫到多庫再到高可用等等,包括在研究的過程中,每個階段可能會碰到不同的問題,快狗叫車是採用一些什麼樣的技術手段去解決這些問題?以快狗叫車的實踐跟大家做一些分享。
分享大綱:
主從不一致,最佳化實踐
快取不一致,最佳化實踐
資料冗餘不一致,最佳化實踐
多庫事務不一致,最佳化實踐
總結
演講正文:
快狗叫車(原58速運)是一個創業型公司,技術架構、技術體系、資料庫架構的變遷,和在座很多公司是很相近的,今天和大家聊一聊,我們在快狗叫車資料庫架構一致性方面碰到一些問題。
不一致的最佳化歷程,也是資料庫架構演進的過程
主線是我們的資料庫架構變化的過程,在這個過程中,我列出了四個跟一致性相關的節點,主從會不一致、快取會不一致、冗餘資料會不一致、多庫多例項會不一致。不一致的最佳化歷程,也是我們資料庫架構演進的一個過程。從單庫到現在,有哪些坑在等著我們呢?
先看一下,最初的資料庫架構,最早是這個樣子的。那個時候沒有什麼微服務分層, web透過DAO訪問一個單庫資料庫,最早我這麼玩的。單庫,它不具備什麼高可用,高併發特性,擴充套件性也比較差。我相信很多創業公司初期也是這樣。
單庫最早會遇到什麼樣的瓶頸呢?在創業的時候,資料量變大了,併發量大了,業務變複雜了,整個系統的瓶頸最先出現在哪裡?我的經驗是資料庫。資料庫的瓶頸又會在哪裡?我的經驗是讀。因為絕大部分的業務是讀多寫少的業務,讀,最容易稱為系統的瓶頸。
最早在資料庫讀扛不住的時候,最先想到的最佳化方式是什麼?網際網路公司都講快,今天出問題,能不能明天后天給我搞定?最先想到的方案是什麼,如何能快速擴充資料庫的讀效能呢?
加兩個例項,主從同步,讀寫分離,這是創業型公司,當資料庫讀成為瓶頸的時候,最先想到的方案,快速擴充讀效能。主從同步碰到的問題是什麼?這就是本主題要講的第一個問題,主從一致性的問題。
當資料量越來越多,吞吐量越來越大的時候,寫到了主庫,主庫同步到從庫,主從同步存在延時,在延時視窗期內,讀寫分離去讀從庫,就有可能讀到一箇舊資料。這個問題,我相信大家也會碰到。
對於這個問題,不少接業務的解法方案是,忍,有些業務如果對一致性的要求沒這麼高。但有沒有最佳化方案呢?
這兩個圖是我們的兩個常見的實踐。
第一個是中介軟體,我們的服務層或者站點層不直接調資料庫,透過一箇中間層,去調資料庫。中間層它能夠知道哪一個庫,哪一個表,哪一個KEY發生了寫操作,如果說接下來的這一段時間(假設主從同步一秒鐘完成),有讀請求落到從庫上,就會讀到舊資料。那麼此時,中介軟體就要將讀請求,路由到主庫上去,讀新資料。
第二個是強制讀主。第二個圖,雙主同步,強制讀主有什麼好處?第一解決了高可用問題,雙主使用同一個VIP,一個主庫如果掛了,另一個主庫能隨時頂上,保障高可用。第二避免了主從之間的不一致。
強制讀主它帶來的新的問題是什麼呢?解決了一致性問題,但讀效能擴充套件的問題又來了,主庫抗讀寫,還是沒有解決讀性的擴大的問題。
除了增加從庫,網際網路公司還有一種常見的提升系統讀效能的方式,快取加服務化。抽象出服務層,向呼叫方遮蔽底層資料庫的複雜性,遮蔽資料庫的高可用的複雜性,遮蔽快取的複雜性,對業務層提供服務。
服務化加快取確實是提升系統讀容量的架構方案。透過快取來提升讀性,又會遇到什麼新的問題呢?用主從架構,有主從不一致問題;用快取架構,當然也有快取不一致的問題。只要你把同一份資料放在了多個地方,多個地方的修改有時間差,這個時間差就會有資料訪問不一致的問題。
當我們出現資料庫與快取中的資料不一致的時候,我們怎麼來解決?
首先來看一下為什麼會不一致。快取的常用玩法是“Cache Aside Pattern”。Cache Aside Pattern,旁路快取,一般是怎麼玩的?淘汰快取,而不是更新快取,這是Cache Aside Pattern的結論。
讀寫時序是什麼樣的?對於讀請求有快取,毫無爭議的,先讀快取,如果資料命中我就直接返回,如果資料沒有命中,讀從庫讀寫分離,把這個資料從從庫裡拿出,放到快取裡,這是讀請求的一個流程。
對於寫請求,Cache Aside Pattern的做法是,先寫資料庫,再淘汰快取。在什麼情況下會出現不一致?當併發量相對會比較高時,對於同一個KEY做了一個寫操作,馬上又來了一個讀操作,會出現什麼樣的情況?先發生一個寫操作,先更新到資料庫,淘汰了Cache,馬上又來了一個讀操作,這個時候主從同步還沒同步完成,先讀快取,快取被剛剛的寫操作已經淘汰掉了,又去讀從庫,把從庫的髒資料拿過來放到快取裡去,不一致就出現。
高併發狀態下,寫後立即讀的場景,容易出現髒資料入Cache。
大家發現沒有,這裡的資料不一致,比主從的資料不一致的情況更嚴重。主從不一致,只有一個主動同步時間差不一致,同步之後,從庫就能讀到新資料了。但是快取與資料庫的不一致,它會導致後續一直不一致,一旦髒資料入了快取,髒資料會延續到下一個寫發生的時候才會被淘汰掉,所以它其實更嚴重。
如何來解決呢?快取和資料庫的資料不一致,我們的兩個實踐:非同步淘汰快取,確保從庫已經同步成功;設定超時時間,極限情況下有機會修正。
第一個,等從庫已經完全同步成功,再去非同步淘汰快取?只要監聽從庫的binlog,從庫binlog完成,一定是寫操作執行完畢,此時再淘汰快取,就能避免時間差。
第二個,就是如果允許Cache miss,不要將快取過期時間設為永久,如果你設定為無限長的過期時間,就沒有一個機會去修正不一致了。
隨著業務的發展,除了流量的增加,我們要提升系統的讀效能,我們要提升系統的資料庫高可用,還會面臨一個什麼問題?對了,資料量會增大。我們業務資料量越來越大了,通常採用什麼樣的方式去解決?創業型公司,這兩個方案應該是大家用得最多的。
第一個,分庫。降低每個庫,降低每個例項的資料量,這樣就能夠承載更多的資料。分庫又帶來什麼新的問題?舉了個例子,訂單一個庫,它有多個維度的查詢,有訂單ID的查詢,有使用者ID的查詢,有司機ID的查詢,一個庫沒有任何問題。
但分庫以後,變成多個庫以後,一旦用了一個維度分庫,你會發現其他的維度的查詢就要變成多個庫了,是不是?
一般來說是透過使用者的ID去分庫,在訂單ID裡去放上分庫因子,這樣透過使用者ID以及訂單ID都能夠定位到相關資料。但是對於司機ID就不同了,司機ID和使用者ID是一個多對多的關係。一個使用者他可能下了多個司機的單,一個司機接了多個使用者的單,透過司機ID去查詢,並不能一次性查詢到所有的資料,同一個司機的訂單一定是分佈在多個庫裡。怎麼辦呢?此時最常用解決方案是,資料冗餘。
我用一個儲存後設資料,用一個儲存關係資料,後設資料透過使用者ID來分庫,保證同一個使用者的所有訂單在一個庫裡。關係資料用司機ID來分庫,保證同一個司機的所有訂單在一個庫裡。同一份資料,由於它存在兩個維度的查詢,這兩個維度查詢都可以不誇庫,而透過資料冗餘來實現,這個在業內屬於很常見的方案。
資料冗餘,又會出現什麼問題?一起來看一下。上面是應用,中間是服務,一個資料存在兩個庫裡,一個庫是透過使用者ID分庫,一個庫是透過司機ID去分庫,呼叫方來了一個請求,先要往第一份資料裡寫一個資料,再往另外一個庫裡寫一個冗餘資料。能保證冗餘資料的一致性麼?是不能夠保證,這兩個庫同時寫成功的,那怎麼辦呢?
這就是冗餘資料的一致性問題。資料冗餘資料的不一致最佳化,今天介紹三種方法,其實本質的方法論都是最終一致性。
第一個方案是掃全量。怎麼發現冗餘資料不一致?寫個指令碼,每天晚上跑,理論上A庫裡有的B庫裡面也有,一旦掃庫發現怎麼A庫有B庫裡沒有,就是出現不一致了,就要根據業務特性來做補償。到底是將後一半補進去,還是把前一半刪掉,跟業務特性相關,不過思路大致是這樣的,一個非同步的方式,最終來保證一致性。
第二個方案是掃增量。透過服務操作兩個庫,寫成功第一個庫寫一條日誌,寫成功第二個庫再寫一條日誌。這些日誌裡的就是每天改變的資料,每天不用掃描全量,只要掃描每天改變的資料就行了。如果掃描日誌不匹配,就透過非同步的方式修復,保證最終一致性。
第三個方式,比前兩種方式更加實時。不寫日誌了,而是發訊息。用一個訊息元件,資料庫正向表操作成功了,發一個訊息,冗餘表操作成功了,發另一個訊息。用一個非同步的服務去監聽這兩個訊息,如果只有一條訊息到達,就去資料庫檢測一致性,並用非同步的方式來補償。
最後是多例項多庫,這也是解決資料量大的一個常見方案。它會帶來什麼樣的不一致呢?這裡有一個案例,下單的一個操作,可能有三個資料要修改,一個是餘額的資料,我可能要扣減一些餘額;一個是訂單的資料,要新增一條訂單;一個是流水的資料,要新增一條流水。原來是單庫事務來保證一致性,現在資料量大了,變成多個庫,餘額是一個單獨的例項,訂單是一個單獨的例項,流水是一個單獨的例項,所以原來的一個事務,在多庫狀態下,就變成三個事務。
多例項,多庫事務,不一致,怎麼辦?這一塊我們有兩個最佳化實踐。
第一個是補償事務,業內應該也經常用到補償事務。
餘額操作,正向的操作是扣減餘額,補償事務就是把餘額加回來。
訂單操作,正向的操作是新增訂單,補償事務就是把訂單刪除掉。
流水操作,正向的操作是新增流水,補償事務就是把流水刪除。
總之,補償事務就是當你發現前面的事務執行失敗的時候,要執行一個應用層的事務,回滾一個動作。
另外一種方式,偽分散式事務的解決方案,是後置提交。
先細化的看一下三個事務是怎麼執行的?第一個事務先執行再提交,第二個事務執行再提交,第三個事務執行再提交。事務的執行過程很慢,事務的提交過程很快。上圖這個例子,可能執行時間200毫秒,提交時間幾毫秒,什麼時候會出現不一致呢?第一個事務提交成功之後,最後一個事務提交成功之前的中間,任何一個地方出現異常都會導致不一致。
最佳化其實也很簡單,後置提交。第一個事務執行,第二個事務執行,第三個事務執行;第一個事務提交,第二個事務提交,第三個事務提交。什麼時候會出現不一致呢?仍然是第一個事務提交成功之後,第三個事務提交成功之前的時間間隔,如果出現了,網路異常,伺服器掛了,就會不一致。但是這個間隔就只有後面的兩毫秒,所以整個不一致的機率是降低了百倍左右。
最後做一個簡單的總結。根據我的經驗,40分鐘50分鐘的一個技術分享,第二天能夠記住的只有10%。如果只記住10%,那我希望大家能夠記住這一頁的內容,並希望自己的邏輯是清晰的。
資料庫架構最初是單庫,單庫會碰到什麼問題?會碰到讀效能瓶頸的問題。讀效能瓶頸最早用什麼樣的方式去解決?主從同步讀寫分離,它會帶來什麼問題?主從的不一致,用什麼方案解決?我們的實踐是中介軟體,以及強制讀主。
提升讀效能,服務化加快取也是常見方案,帶來什麼新的問題?快取和資料庫的不一致。在Cache Aside Pattern的情況下,有寫後立即讀的問題,舊資料可能入快取。我們的實踐,可以透過非同步淘汰的方式,當寫操作在從庫上真正完成的時候再去淘汰快取。同時,我們建議為所有允許Cache miss的資料設定超時時間。
資料庫架構,資料量大的問題,怎麼解決?常用的解決方案是分庫,多例項。分庫帶來什麼新的問題?記得我的例子麼,分了庫之後,可以保證同一個使用者的資料在同一個庫裡,不能夠保證同一個司機資料也在同一個庫裡,怎麼解決?使用資料冗餘。冗餘帶來什麼問題?冗餘資料的不一致問題,方向是最終一致性。怎麼最終保證一致性?掃全量,掃增量,實時訊息對。除了多庫,多例項也可以擴充套件資料儲存量,會遇到什麼問題?多庫的事務不能在保證原則性,補償事務,後置提交,都是我們的最佳化實踐。
今天的內容這麼多,希望大家有收穫,謝謝大家。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545803/viewspace-2219723/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 快狗叫車CTO沈劍:開源框架VS自研框架,企業該如何選擇?框架
- 大資料在快狗叫車中的應用與實踐大資料
- 快取一致性最佳實踐快取
- 快狗叫車財報:2023年快狗叫車實現總收入7.53億元 同比下降2.6%
- TiDB 異構資料庫複製最佳實踐TiDB資料庫
- 最佳實踐:騰訊HTAP資料庫TBase助力某省核心IT架構升級資料庫架構
- 鬥魚資料庫混合雲架構實踐資料庫架構
- 快狗叫車實時數倉演進之路
- 微服務架構最佳實踐微服務架構
- PHP最佳實踐之資料庫PHP資料庫
- 朱曜鑫:阿里巴巴第四代資料庫架構最佳實踐阿里資料庫架構
- 快取資料一致性 - 架構師峰會演講實錄快取架構
- 資料庫安全最佳實踐:基本指南資料庫
- 快狗叫車逆勢上市的底氣
- 微服務架構下,解決資料一致性問題的實踐微服務架構
- 微服務架構十條最佳實踐微服務架構
- 微服務的【資料庫管理】最佳實踐微服務資料庫
- 企業級雲資料庫最佳實踐資料庫
- 包銀消費CTO湯向軍:消費金融大資料風控架構與實踐大資料架構
- 視訊:豆瓣資料架構實踐DX架構
- 編寫架構文件的最佳實踐 - Singh架構
- 快取與資料庫一致性快取資料庫
- 資料庫伺服器運維最佳實踐資料庫伺服器運維
- 資料庫設計的十個最佳實踐資料庫
- SACC2017:資料庫架構設計與實踐的後半生資料庫架構
- B站萬億級資料庫選型與架構設計實踐資料庫架構
- 騰訊雲原生資料庫TDSQL-C架構探索和實踐資料庫SQL架構
- 前端快取最佳實踐前端快取
- 美圖大資料平臺架構實踐大資料架構
- MySQL高可用架構案例篇:UCloud最佳實踐MySql架構Cloud
- 雲原生架構日誌監控最佳實踐架構
- 從實戰出發,聊聊快取資料庫一致性快取資料庫
- 快取與資料庫的一致性快取資料庫
- Android 中的升級資料庫最佳方法實踐Android資料庫
- 【BEST】Oracle 資料庫19c配置最佳實踐Oracle資料庫
- ES資料庫架構資料庫架構
- 騰訊音樂內容庫資料平臺架構演進實踐架構
- 資料治理實踐:後設資料管理架構的演變架構