如何讓分庫分表真正落地?(上)

前言

在網際網路系統開發的過程中,分庫分表並不是一個新概念,很多開發人員對分庫分表或多或少都有了解,也知道其使用的場景,但對究竟如何實現實現分庫分表並不是很明確。當然,分庫分表的含義與實現遠比字面意思要複雜的多。這就引出話題:如何讓分庫分表落地?

首先我們從資料儲存和訪問的演進過程說起:

先看一個經典案例:

試想在我們平時寫的小專案,小課設:電商系統中存在訂單表,系統在初始執行期間,一般使用單庫和單表的方式來儲存和訪問資料,因為資料量不大,所以資料庫訪問的瓶頸並不明顯。

如果這時候馬爸爸看中了你的專案,想投資商用,那系統每天可能會產生數十萬,甚至上百萬、千萬。。。(媽耶,想都不敢想)級別的訂單資料,訂單表就會開始出現瓶頸。

以網際網路中常用的MySQL資料庫為例,雖然表單儲存資料原則上可以達到億條級別,但此時訪問效率會變得很差,即使採用各種調優策略,效果也通常微乎其微。業界普遍認為,MySQL表單容量在1千萬以下是最佳狀態,一旦超過這個量級,就需要考慮其他方案了。

既然以MySQL為代表的關係資料庫中的表單無法支援大量資料量的儲存和訪問方案,自然而然的,你就可能想到是否可以採用諸如MongDB等NoSQL的方式來管理資料?

但其實這並不是很好的選擇,原因有很多:一方面,關係型資料庫生態系統非常完善,關係型資料庫經過幾十年的持續發展,具有非關係資料庫無法比擬的穩定性和可靠性;另一方面,關係型資料庫的事務特性,也是其他資料儲存工具所不具備的一項核心功能。目前絕大部分公司的核心資料都儲存在關係型資料庫中,就網際網路公司而言,MySQL是主流的資料儲存方案。

現在,我們選擇了關係型資料庫,就可以考慮採用分表分庫的方案來解決單表庫的瓶頸問題。分庫分表方案,更多的是對關係型資料庫資料儲存和訪問機制的補充,而不是顛覆。

那究竟什麼是分庫分表呢?

什麼是資料分庫分表?

分庫和分表是兩個概念,但是我們通常會將它們合併在一起,簡稱為分庫分表。它沒有一個很嚴格的定義,你可以簡單理解為:

為了解決由於資料量過大而導致的資料庫效能降低的問題,將原來獨立的資料庫拆分成若干資料庫,把原來資料量大的表拆分成若干資料表,使得單一資料庫、單一資料表的資料量變得足夠小,從而達到提升資料庫效能的效果。

分庫分表的表現形式有很多種

分庫和分表是兩個維度,在開發過程中,對於每個維度,都可以採用兩種拆分思想,即

垂直拆分

水平拆分

那什麼叫垂直拆分,什麼叫水平拆分?彆著急,我們一起慢慢看

先來看看垂直拆分表,垂直拆分相比水平拆分,更好理解一點,比如在我們前面提到的電商系統中,使用者在開啟首頁時,往往會載入一些使用者的個人資訊,比如使用者名稱、性別、地理位置等基礎資料。對應使用者表而言,這些位於首頁的基礎訪問資料頻率遠比使用者頭像等資料更高。基於這兩種資料的不同訪問特性,可以把使用者表單單獨存放在一張表中,把訪問頻次高的使用者資訊單獨放在另外一張表中,如圖:

如何讓分庫分表真正落地?(上)

從這裡可以看出,垂直分表的處理方式,就是將一個表按照欄位分成多張表,每個表儲存其中一部分欄位。在實現上,我們通常會把頭像等blob型別的大欄位資料或者熱度較低的資料放在一張獨立表中,將經常需要組合查詢的列放在一張表中,這樣也可以認為是分表操作的一種表現形式。

透過垂直分表,能得到一定程度的效能提升,但資料畢竟仍然位於同一個伺服器中,也就是操作範圍限制在一個伺服器上,每個表還是會競爭同一臺伺服器中的CPU、記憶體、網路IO等資源。基於這個考慮,在有了垂直分表之後,我們自然就想到可不可以垂直分庫?

基於垂直分表的思想,垂直分庫,就是將使用者的相關資料表單獨拆分出來,放在一個獨立的資料庫中,如圖:

如何讓分庫分表真正落地?(上)

這樣的效果就是垂直分庫。從定義上講,垂直分庫是按照業務將表進行分類,然後分佈到不同的資料庫上,其核心理念就是專庫專用,而從實現上講,垂直分庫很大程度上取決於業務的規劃和系統邊界的劃分。比如說,使用者資料的獨立拆分就需要考慮到系統使用者體系和其他其他業務模組之間的關聯關係,而不是簡單地建立一個使用者庫就可以了。在高併發的場景下,垂直分庫能夠在一定程度上提升IO訪問效率和資料庫連線數,並降低單機硬體資源的瓶頸。

從前面的分析中,我們不難明白,垂直拆分儘管實現起來比較簡單,但是並不能解決資料量過大的問題,所以,在實際應用中,我們常常需要在垂直拆分的基礎上再水平拆分。例如,可以對使用者庫的使用者資訊按照使用者ID進行取模,然後分別儲存在不同的資料庫中,這就是水平分庫的常見做法:

如何讓分庫分表真正落地?(上)

可以看到,水平分庫,是把同一個表的資料按照一定的規則拆分到不同的資料庫中,每個資料庫同樣可以位於不同的伺服器上。這種方案往往可以解決單庫儲存量及效能的瓶頸問題,但由於同一個表被分配在不同的資料庫中,資料的訪問需要額外的路由工作,因此大大提高了系統的複雜度。這裡所謂的規則實際上就是一系列的演算法,常見的包括:

取模演算法:取模的方式有很多,比如前面介紹的按照使用者 ID 進行取模,當然也可以透過表的一列或多列欄位進行 hash 求值來取模;

範圍限定演算法:範圍限定也很常見,比如可以採用按年份、按時間等策略路由到目標資料庫或表;

預定義演算法:是指事先規劃好具體庫或表的數量,然後直接路由到指定庫或表中。

按照水平分庫的思路,也可以對使用者庫中的使用者表進行水平拆分,也就是說,水平分表是在同一個資料庫內,把同一個表的資料按一定規則拆到多個表中。

如何讓分庫分表真正落地?(上)

顯然,系統的資料儲存架構演變到現在,已經非常複雜了,與拆分前的單庫單表相比,現在面臨著一系列具有挑戰的問題,比如:

如何對多資料庫進行高效治理?

如何進行跨節點關聯查詢?

如何實現跨節點的分頁和排序操作?

如何生成全域性唯一的主鍵?

如何確保事務一致性?

如何對資料進行遷移?

。。。

如果沒有很好的工具來支援資料的儲存和訪問,資料一致性將很難得到保障。

那麼下節,松鼠就會整理和分享解決以上問題的原理以及選擇怎樣的一款分庫分表開源框架。

> 文章部分來源於:拉鉤教育網

如果對松鼠的文章感興趣也可以關注我的公眾號:松鼠技術站