更新時間:2022-08-25 來源:黑馬程序員 瀏覽量:
導讀
各位小伙伴,在目前企業級開發中采用Mysql做為數據庫是一個主流選擇,而當數據量比較大的情況下,為了支撐項目的正常快速的運行,我們不得不選擇對數據庫分庫分表操作,本章節就對數據庫的分表做一些方案的講解,包括如下:
- 為什么要分庫分表
- 分庫分表的具體方式
- 分庫分表帶來的問題及解決方案有哪些
2 .為什么分庫分表
隨著平臺的業務發展,數據可能會越來越多,甚至達到億級。以MySQL為例,單庫數據量在5000萬以內性能比較好,超過閾值后性能會隨著數據量的增大而明顯降低。單表的數據量超過1000w,性能也會下降嚴重。這就會導致查詢一次所花的時間變長,并發操作達到一定量時可能會卡死,甚至把系統給拖垮。
我們是否可以通過提升服務器硬件能力來提高數據處理能力?能,但是這種方案很貴,并且提高硬件是有上限的。**那我們能不能把數據分散在不同的數據庫中,使得單一數據庫和表的數據量變小,從而達到提升數據庫操作性能的目的?** 可以,這就是數據庫分庫分表。
分庫分表就是把較大的數據庫和數據表按照某種策略進行拆分。目的在于:降低每個庫、每張表的數據量,減小數據庫的負擔,提高數據庫的效率,縮短查詢時間。另外,因為分庫分表這種改造是可控的,底層還是基于RDBMS,因此整個數據庫的運維體系以及相關基礎設施都是可重用的。
3. 分庫分表的方式
3.1 垂直分表
用戶在電商平臺流覽商品時,首先看到的是商品的基本信息,如果對該商品感興趣時才會繼續查看該商品的詳細描述。因此,商品基本信息的訪問頻次要高于商品詳細描述信息,商品基本信息的訪問效率要高于商品詳細描述信息(大字段)。 由于這兩種數據的特性不一樣,因此考慮將商品信息表拆分如下:
這種拆分就叫垂直分表。垂直分表定義:將一個表的字段分散到多個表中,每個表存儲其中一部分字段。垂直分表帶來的提升是:
1.減少IO爭搶,減少鎖表的幾率,查看商品詳情的與商品概述互不影響
2. 充分發揮高頻數據的操作效率,對商品概述數據操作的高效率不會被操作商品詳情數據的低效率所拖累。
一般來說,某業務實體中的各個數據項的訪問頻次是不一樣的,部分數據項可能是占用存儲空間比較大的BLOB或是TEXT,例如上例中的商品描述字段。所以,當數據量很大時,可以將表按字段拆分,將熱門字段、冷門字段分開放置在不同表中。垂直切分帶來的性能提升,主要集中在熱門數據的操作效率上,而且磁盤爭用情況減少。通常我們按以下原則進行垂直拆分:
- 把不常用的字段單獨放在一張表
- 把text,blob等大字段拆分出來單獨放在一張表
- 經常組合查詢的字段單獨放在一張表中
3.2 垂直分庫
通過垂直分表,數據庫性能得到了一定程度的提升,但是還沒有達到要求,并且磁盤空間也快不夠了,因為數據還是始終存放在一臺服務器。庫內垂直分表只解決了單一表數據量過大的問題,但沒有將表分布到不同機器的庫上,因此對于減輕數據庫的壓力來說,作用有限,大家還是競爭同一個物理機的CPU、內存、網絡IO、磁盤。
以電商平臺為例,可以把原有的SELLER_DB(賣家庫),拆分為PRODUCT_DB(商品庫)和STORE_DB(店鋪庫),并把這兩個庫分散到不同服務器上,如下圖所示:
由于商品信息與商品描述業務耦合度較高,因此一起被存放在PRODUCT_DB(商品庫);而店鋪信息相對獨立,因此單獨被存放在STORE_DB(店鋪庫),這就叫垂直分庫。
垂直分庫是指按照業務將表進行分類,分布到不同的數據庫上面,每個庫可以放在不同的服務器上,從而達到多個服務器共同分攤壓力的效果。垂直分庫帶來的提升是:
- 解決業務層面的耦合,業務清晰
- 能對不同業務的數據進行分級管理、維護、監控、擴展等
- 高并發場景下,垂直分庫在一定程度上可以提升IO、數據庫連接數、單機硬件資源的性能
3.3 水平分庫
經過**垂直分表和垂直分庫**后,數據庫性能問題就完全解決了?假設某電商平臺發展迅猛,PRODUCT_DB(商品庫)單庫存儲數據已經超出預估。假設目前該平臺有8w店鋪,每個店鋪平均有150個不同規格的商品,再算上增長,那商品數量就會達到1500w+級別,并且PRODUCT_DB(商品庫)屬于訪問非常頻繁的資源,性能瓶頸再次出現。
能再次垂直分庫嗎?從業務角度分析,目前已經無法再次垂直拆分。于是我們又想了一個辦法,判斷商品ID是奇數還是偶數,然后把商品信息分別存放到兩個數據庫中。也就是說,要操作某條數據,先分析這條數據的商品ID,如果商品ID為奇數,將此操作映射至RRODUCT_DB1(商品庫1);如果商品ID為偶數,將操作映射至RRODUCT_DB2(商品庫2),這就叫**水平分庫**。
水平分庫是把同一個表的數據按一定規則拆分到不同的數據庫中,每個庫可以放在不同的服務器上。它帶來的提升是:
- 解決了單庫大數據,高并發的性能瓶頸。
- 按照合理拆分規則拆分,join操作基本避免跨庫。
- 提高了系統的穩定性及可用性。
當一個應用難以再細粒度的垂直切分,或切分后數據量行數仍然巨大,存在單庫讀寫、存儲性能瓶頸,這時候就需要進行**水平分庫**了,經過水平切分的優化,往往能解決單庫存儲量及性能瓶頸。但由于同一個表被分配在不同的數據庫,需要額外進行數據操作的路由工作,因此大大增加了系統復雜度。
3.4 水平分表
數據庫能水平拆分,那數據表是不是也可以呢?我們嘗試把某PRODUCT_DB(商品庫)內的表,進行了一次水平拆分:
與水平分庫的思路類似,不過這次拆分的目標是表,商品信息及商品描述被分成了兩套表。如果商品ID為奇數,將此操作映射至商品信息1表;如果商品ID為偶數,將操作映射至商品信息2表,這就叫水平分表。水平分表是在同一個數據庫內,把同一個表的數據按一定規則拆分到多個表中。它帶來的提升是:
- 優化單一表數據量過大而產生的性能問題
- 避免IO爭搶并減少鎖表的幾率
庫內的水平分表,解決了單一表數據量過大的問題,分出來的小表中只包含一部分數據,從而使得單個表的數據量變小,提高檢索性能。但由于同一個表的數據被拆分為多張表,也需要額外進行數據操作的路由工作,因此增加了系統復雜度。
3.5 小結
- 垂直分表:可以把一個寬表的字段按訪問頻次、業務耦合松緊、是否是大字段的原則拆分為多個表,這樣既能使業務清晰,還能提升部分性能。拆分后,盡量從業務角度避免聯查,否則性能方面將得不償失。
- 垂直分庫:可以把多個表按業務耦合松緊歸類,分別存放在不同的庫,這些庫可以分布在不同服務器,從而使訪問壓力被多服務器負載,大大提升性能,同時能提高整體架構的業務清晰度,不同的業務庫可根據自身情況定制優化方案。但是它需要解決跨庫帶來的所有復雜問題。
- 水平分庫:可以把一個表的數據(按數據行)分到多個不同的庫,每個庫只有這個表的部分數據,這些庫可以分布在不同服務器,從而使訪問壓力被多服務器負載,大大提升性能。它不僅需要解決跨庫帶來的所有復雜問題,還要解決數據路由的問題。
- 水平分表:可以把一個表的數據(按數據行)分到多個同一個數據庫的多張表中,每個表只有這個表的部分數據,這樣做能小幅提升性能,它僅僅作為水平分庫的一個補充優化。
一般來說,在系統設計階段就應該根據業務耦合松緊來確定垂直分庫,垂直分表方案,在數據量及訪問壓力不是特別大的情況,首先考慮緩存、讀寫分離、索引技術等方案。若數據量極大,且持續增長,再考慮水平分庫分表方案。
4 .分庫分表帶來的問題
分庫分表有效的緩解了大數據、高并發帶來的性能和壓力,也能突破網絡IO、硬件資源、連接數的瓶頸,但同時也帶來了一些問題。
4.1 事務一致性問題
由于分庫分表把數據分布在不同庫甚至不同服務器,不可避免會帶來**分布式事務**問題,我們需要額外編程解決該問題。
4.2 跨節點join
在沒有進行分庫分表前,我們檢索商品時可以通過以下SQL對店鋪信息進行關聯查詢:
SELECT p.*,s.[店鋪名稱],s.[信譽] FROM [商品信息] p LEFT JOIN [店鋪信息] s ON p.id = s.[所屬店鋪] WHERE...ORDER BY...LIMIT... ```
但經過分庫分表后,[商品信息]和[店鋪信息]不在一個數據庫或一個表中,甚至不在一臺服務器上,無法通過sql語句進行關聯查詢,我們需要額外編程解決該問題。
4.3 跨節點分頁、排序和聚合函數
跨節點多庫進行查詢時,limit分頁、order by排序以及聚合函數等問題,就變得比較復雜了。需要先在不同的分片節點中將數據進行排序并返回,然后將不同分片返回的結果集進行匯總和再次排序。例如,進行水平分庫后的商品庫,按ID倒序排序分頁,取第一頁:
以上流程是取第一頁的數據,性能影響不大,但由于商品信息的分布在各數據庫的數據可能是隨機的,如果是取第N頁,需要將所有節點前N頁數據都取出來合并,再進行整體的排序,操作效率可想而知,所以請求頁數越大,系統的性能也會越差。
在使用Max、Min、Sum、Count之類的函數進行計算的時候,與排序分頁同理,也需要先在每個分片上執行相應的函數,然后將各個分片的結果集進行匯總和再次計算,最終將結果返回。
4.4 主鍵避重
在分庫分表環境中,由于表中數據同時存在不同數據庫中,主鍵值平時使用的自增長將無用武之地,某個分區數據庫生成的ID無法保證全局唯一。因此需要單獨設計全局主鍵,以避免跨庫主鍵重復問題。
由于分庫分表之后,數據被分散在不同的服務器、數據庫和表中。因此,對數據的操作也就無法通過常規方式完成,并且它還帶來了一系列的問題。我們在開發過程中需要通過一些中間件解決這些問題,市面上有很多中間件可供我們選擇,其中Sharding-JDBC和mycat較為流行。
5 .總結
通過以上學習呢,我們知道,當數據庫特別大的情況下,數據庫存儲數量達到了一定的閾值以后會變慢,我們需要使用分庫分表的方案來解決這個問題。我們主要學習了垂直分表、垂直分庫、水平分表、水平分庫四種方案。當我們選擇分庫分表以后也會帶來一些問題,比如事務一致的問題、垮節點聚合的問題、分頁、主鍵避重等等問題,大家也要掌握這些問題的解決方案。