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

前言

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

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

先看一個經典案例:

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

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

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

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

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

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

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

什麼是數據分庫分表?

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

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

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

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

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

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


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


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

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

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


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

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

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


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


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

取模算法:取模的方式有很多,比如前面介紹的按照用戶 ID 進行取模,當然也可以通過表的一列或多列字段進行 hash 求值來取模;

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

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

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


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

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

如何對多數據庫進行高效治理?

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

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

如何生成全局唯一的主鍵?

如何確保事務一致性?

如何對數據進行遷移?

...

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

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

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

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


分享到:


相關文章: