1. 程式人生 > >架構師之路---資料庫水平切分實踐

架構師之路---資料庫水平切分實踐

本人一應屆生,在去實習的地鐵上,看了一篇沈劍老師寫資料庫水平切分架構思路,看完人清氣爽。現在寫一篇部落格記錄下。

引言:

涉及到資料庫水平切分問題,主要有以下兩種問題:
第一:專案開始之前進行資料庫架構設計,考核,規劃以後資料庫量大的情況有很好的擴充套件性;
第二:當專案使用者量持續增大時,資料庫壓力過大,相應速度降低,使用者體驗度降低,這時可以通過優化資料庫來解決,即水平切分資料庫。

本文以使用者登陸為例,來討論學習資料庫水平切分的思路,如有哪裡寫的不對,望原諒並留言提出,謝謝。

如何切分

專案初期一般都採用單表單庫來解決使用者登陸功能,但是當資料量大的時候可以考慮資料庫水平切分,如何切分?

第一:範圍法;

範圍法顧名思義,就是通過主鍵uid來劃分,例如1-1kw的資料為一個數據庫,1kw-2kw的資料為一個數據庫。

優點:
1.切分策略簡單,根據uid可以快速定位到哪個資料庫上;
2.擴容簡單,如果容量持續增大,只要增加資料庫伺服器即可解決。
缺點:
1.uid必須滿足遞增的特性
2.資料量不均,新增的資料庫會很少請求到,短時間內浪費記憶體;
3.請求量不均勻,一般來說,新註冊的使用者活躍度會比較高,故db2的資料庫壓力往往比db3的壓力大,導致資料庫利用率不平衡;

第二:雜湊法;

顧名思義,雜湊法主要是對uid進行hash演算法,根據值來切分資料庫。
例如:uid%2=1的存入db1,uid%2=0的存入db2.
優點:


1.切分簡單:根據uid直接可以定位到哪個db中;
2.資料量均勻:只要uid是均勻的,資料再各個庫中的分配一定是均勻的。
3.請求量均勻:只要uid是均勻的,請求負載在各個庫上的分佈一定也是均勻的。
缺點:
1.擴容麻煩:需要對uid進行重新hash演算法,如何平滑的進行資料遷移是一個需要考量的問題。

切分後帶來的問題

切分思路很清晰,但是我們也要考慮到分庫後所帶來的問題,例如以上如何平滑的遷移資料。這個問題不是在今天討論的範圍之內。
還有一個問題,就是非uid屬性username屬性查詢需求分析。
具體來說:

  • 使用者方面,前臺使用使用者名稱,手機號和emai登陸,如何做好username等屬性和uid的對映關係?

思路:建立非uid屬性到uid的對映關係

解決方案:
1.索引表法:建立一個索引記錄表的對映關係表,用username訪問時,先在索引表查詢uid然後再定位到相應的表。索引表屬性儘量少,可以容納較多資料,一般不需要分庫,如果需要分庫可以username來進行分庫;
2.快取對映法:可以將對映關係存入快取中

3.username屬性生成uid,使用者註冊時,username通過一定規則來生成uid;

4.username基因嵌入到uid中,假設分8個庫,採用uid%8路由,潛臺詞是uid最後3個bit決定這條資料落在哪個庫上,這三個bit就是所謂的基因。如果uid設計長度為64位,在使用者註冊時先根據username生成3bit基因,同時生成61bit的全域性唯一id,作為使用者標識,然後拼接為最後的64bit的uid。
如果用username登陸時,先通過函式將username復原為3bit基因,然後通過3bit基因定位到庫。

- 運營方面,後臺訪問。
運營基本都是批量分頁的訪問,這樣返回資料量大,比較消耗資料庫效能。但是運營的請求也不多,但是一旦查詢會影響線上的其他使用者的查詢。
解決方法:

前後端分離,業務架構基本不變,
— 對於運營的查詢只需要抽取獨立的web/service/db來支援,解決系統之間的耦合或者直接去掉service層,
— 直接呼叫dao層查詢資料,不需要反向代理,不需要叢集冗餘,不需要訪問實時庫,可以通過MQ或者線下非同步同步資料,
—-如果資料量非常大的情況,可以使用更高延遲的索引外接或者HIVE涉及方案。