1. 程式人生 > 程式設計 >記一次資料庫冷熱分離

記一次資料庫冷熱分離

前言

最近在一家小公司實習,文章也沒怎麼更新。前兩天參與了後臺系統資料庫冷熱分離(一期)的工作,雖然只是參與了定時任務和介面的開發改造,但還是想了解一下它的前因後果,畢竟作為一隻鹹魚,就要有翻身之後再作鹹魚的覺悟,於是就有了這篇文章。

先說一下背景吧,隨著業務的發展,生產庫中訂單等資料已經有數千萬,而類似訂單詳情、結算詳情的資料則已經過億,並且每天以 20w+ 的資料在增加,可以說對資料庫的改造已經是迫在眉睫了。

解決方案

考慮到具體的業務需要,按照使用者的習慣,一般在近期的訂單、訂單詳情等資料,由於有待評價、售後等問題,訪問會比較多,這些資料就稱之為熱資料;

而對於較早時間的訂單、訂單詳情等資料,一般都是已評價、已完成售後等狀態,使用者一般不會經常訪問,這些資料就稱之為冷資料。

所以考慮是否能夠進行冷熱分離。對於需要經常查詢的資料放在生產庫中,例如一個月之內的資料;而那些查詢不多的資料,例如一個月之前的資料,將其遷移到歷史庫中。這樣既可以減輕生產庫的壓力,也可以保持資料的完整。

如何遷移

定好大致方案後,就要考慮如何對資料進行遷移了。由於資料量過大,遷移不可能一次並在短時間內就完成。

對於以前的資料,考慮在凌晨分批次進行遷移。由於不同時期的資料量不同,定時任務不好實現,只能通過手動查詢,可能剛開始是好幾個月的資料一起遷移,到後面就是十幾天的資料一起遷移。

這裡通過人工去判斷一段時間內的資料量,並進行遷移,主要就是為了保證遷移工作不能影響生產庫的正常執行,另外也要讓遷移次數較少,遷移工作儘早完成。

而對於以後的增量資料,則可以設定定時任務,每日凌晨自動執行,遷移一個月之前的資料。

在遷移資料時,以訂單為粒度進行遷移,其整體的邏輯主要分為以下幾步:

  • 資料遷移工作:
    • 每次查詢一部分資料(例如 500 條/1000條),判斷其是否已經遷移過(額外一張表記錄遷移狀態),這主要是為了防止一次查詢過多資料會影響生產庫的執行;
    • 如果沒有遷移過,則查詢與該訂單相關的資料,將其遷移到新庫中,並更新遷移狀態;
  • 測試檢驗工作:
  • 主庫刪除工作:在測試一段時間後,如果無誤,則將主庫中的已經遷移完成的資料刪除,同樣這裡每次刪除一部分資料。

讀寫設計

在資料遷移後,另一個問題就是如何讀寫了,一般會有如下幾種方案。

對於讀操作,一種方案是,每次在查詢時,優先查詢熱庫,只有當結果沒有命中,或只有部分命中時,才去查詢冷庫。這裡為了區分全部命中和部分命中,可以在熱庫中建立一個表,記錄每次要求查詢冷庫時的查詢條件、查詢的結果數量等。在查詢熱庫時,如果相同查詢條件的查詢結果數量一致,則本地查詢結束,否則就要到冷庫中進行查詢。

另一種方案,則可以通過前端配合實現,每次查詢時,預設只查詢最近一段時間內的資料,也就是主庫內的資料。如果使用者需要查詢以前的資料時,再去冷庫中查詢就好了。這也是目前我司的實現方案。

而對於寫操作,也有兩種方案。

一種是每次在儲存資料時,在熱庫中儲存一份,在冷庫歷史表中同樣儲存一份。然後每日凌晨通過定時任務刪除一段時間之前的資料,如果資料量較大的話,可以按照區間進行刪除,防止影響生產庫的正常執行。

另一種方案,與之類似,只不過在寫操作時,只是在熱庫中進行儲存。將資料從熱庫遷移到冷庫的操作,放在凌晨的定時任務中執行。

擴充套件學習

其實一般來說,單表資料量在數千萬時,資料的寫入和查詢效率就會受到影響。這時就應該考慮進行分表,例如水平分表、垂直分表。

分表

對於水平分表,也有多種分表的策略。

按照範圍劃分

按照範圍劃分,例如將表中的資料按照時間,每個月或每個季度一張表。

這種做法也有利有弊:

  • 好處是可以很容易來控制單表的大小,天然擴充套件,資料量很大時只需要減小時間的粒度即可;
  • 缺點是對批量寫入等操作的效率問題沒有解決,還是集中在一種表上。

按照 Hash 切分

按照 Hash 切分,一般使用 Mod 2^n 將資料劃分到不同的表中。

mod 的值選擇為 2^n,具體根據業務決定,目標就是為了在以後的擴充套件時能儘量少遷移,甚至不遷移資料。

這種做法如果劃分均勻,批量寫入、查詢等操作均攤到各個表中,對效能不會有太大影響。但是需要對 mod 的值仔細權衡,方便以後的擴充套件。

分庫

分表很大程度上解決了單表寫入和查詢的效率,但對於資料庫而言,其負載壓力並沒有變化,對於分庫也有類似於分表的很多策略,這裡就不再多說了。

最後

分庫分表雖然帶來了很大的好處,但也有一些問題需要處理,除了讀寫設計外,還有分散式 id,分散式事務,動態擴容等問題等著我們一個一個去挑戰。活到老,學到老。

參考資料