一、分庫分表介紹

1、分庫分表簡介

  爲什麼要用分庫分表,是因爲隨着公司業務快速發展,數據庫中的數據量猛增,訪問性能也變慢了,優化迫在眉睫。分析一下問題出現在哪?
  關係型數據庫本身比較容易成爲系統瓶頸,單機存儲容量、連接數、處理能力都有限。當檔表的數據量達到1000w或100g以後,由於查詢維度較多,即使添加從庫、優化索引,做很多操作時性能扔下降嚴重。
  方案一:
  通過提升服務器硬件能力來提高數據處理能力,比如增加存儲容器、CPU等,這種方案成本很高,並且如果瓶頸在MySQL本身那麼提高硬件也是很有限的。
  方案二:
  把數據分散在不同的數據庫中,使得單一數據庫的數據量變小來緩解單一數據庫的性能問題,從而達到能提升數據庫性能的目的,如下圖:將電商數據庫拆分爲若干獨立的數據庫,並且對於大表也拆分爲若干小表,通過這種數據庫拆分的方法來解決數據庫的性能問題。在這裏插入圖片描述
  分庫分表就是爲了解決由於數據量過大而導致數據庫性能降低的問題,將原來獨立的數據庫拆分爲若干數據庫,將大數據表拆分爲若干數據表,使得單一數據庫、單一數據表的數據量變小,從而達到提升數據庫性能的目的。

2 分庫分表的方式

  分庫分表包括分庫和分表兩部分,在生產中通常包括:垂直分庫、水平分庫、垂直分表、水平分表四種方式。

2.1 垂直分表

  以一張商品信息表爲例,用戶在瀏覽商品列表時,只有對某商品感興趣時纔會查看該商品的詳細描述,因此,商品信息中商品描述字段訪問頻次較低,且該字段存儲佔用空間較大,訪問單個數據 IO 時間較長;而商品信息中商品名稱、商品圖片、商品價格等其他字段數據訪問平次較高。
  由於這兩種數據的特性不一樣,因此考慮將商品信息進行拆分,將訪問頻次低的商品描述信息單獨存放在一張表中,訪問頻次較高的商品基本信息單獨放在另一張表中,這叫垂直分表,如下圖所示:
在這裏插入圖片描述
  爲什麼這樣分?放在一張表中不行嗎?分了之後寫 sql 還需多表聯查,之前的一條 sql 就搞定了
  熟悉淘寶之類的購物網站都知道,在商品列表中,都是商品的基本信息,而當看中某件商品之後纔會點進去查看詳細信息。
  有人覺得是這樣沒錯,但是和之前的有什麼分別呢?
  這就得從關係型數據庫的存儲開始理解。

  • 第一,大字段的 IO 效率低,數據量本身較大,需要更多的讀取時間
  • 第二,數據庫存儲的單位是頁,很多查找及定位操作doushi以頁爲單位,單頁內的數據行越多,數據庫整體性能就越好。而大字段佔用空間大,單頁內存儲行數就變少,因此效率低
  • 第三,數據庫以行爲單位將數據加載到內存中,這樣表中字段長度較短且訪問頻次較高,內存能加載到更多的數據,命中率更高,減少磁盤 IO,從而提高數據庫性能。
      因此,我們通常按以下原則進行垂直拆分
  • 把不常用的字段單獨放在一張表
  • 把 text,blob 等大字段拆分出來放在附表中
  • 經常組合查詢的列放在一張表中

2.2 垂直分庫

  通過垂直分表性能得到了一定程度的提升,但是還沒有達到要求,並且磁盤空間也快不夠了,因爲數據還是始終限制在一臺服務器,庫內垂直分表只能解決了單一表數據量過大的問題,但是沒有將表分佈到不同的服務器上,因此每個表還是競爭同一個物理機的 CPU、內存、網絡 IO、磁盤。
  比如,當前有 1 個電商數據庫,庫中有商品基本信息表、商品詳細信息表、店鋪表、地域區域表等。由於商品信息和商品描述業務耦合度較高,我們可以將商品歸在一個一臺物理機的數據庫中,而店鋪信息相對獨立,因此將店鋪表歸爲另一臺物理機的數據庫中。這就是垂直分庫
  垂直分庫是指按照業務將表進行分類,分佈到不同的數據庫上面,每個庫可以放在不同的服務器上,它的核心理念是專庫專用。

  優點

  • 解決業務層面的歐歐赫,業務清晰
  • 能對不同業務的數據進行分級管理、維護、監控、擴展等
  • 高併發場景下,垂直分庫一定程度的提升 IO、數據庫連接數、降低單機硬件資源的瓶頸

  垂直分庫通過將表按照業務分類,然後分佈在不同數據庫中,並且可以將這些數據庫部署在不同的服務器上,從而達到多個服務器共同分攤壓力的效果,但是依然沒有解決單表數據量過大的問題。

2.3 水平分庫

  經過垂直分庫後,數據庫性能問題得到一定程度的解決,但是隨着業務量的增長,商品庫單庫存儲數據已經超過預估。粗略估計,目前有 8w 店鋪,每個店鋪平均 150 個不同規格的商品,再算上增長,那商品數量得往 1500w+ 上預估,並且商品庫屬於訪問非常頻繁的資源,單臺服務器已經無法支撐。此時該如何優化?
  再次分庫?但是從業務角度分析,目前情況已經無法再次垂直分庫。
  嘗試水平分庫,將店鋪 ID 爲單數的和店鋪 ID 爲雙數的商品信息分別放在兩個庫中。
  也就是說,要操作某條數據,先分析這條數據所屬的店鋪 ID。如果店鋪 ID 爲雙數,將此操作印射至雙數的商品庫;反之則印射到單數的商品庫。這叫水平分庫
  水平分庫是把同一個表的數據按一定規則拆分到不同的數據庫中,每個庫可以放在不同的服務器上。

對比垂直分庫:垂直分庫是把不同表拆到不同數據庫中,它是對數據行的拆分,不影響表結構

  優點

  • 解決了單庫大數據,高併發的性能瓶頸
  • 提高了系統的穩定性及可用性

穩定性體現在 IO 衝突減少,鎖也減少,可用性指某個庫出問題,部分可用。

  當一個應用難以再細粒度的垂直切分,或切分後數據量行數巨大,存在單庫讀寫、存儲性能瓶頸,這時候就需要進行水平分庫了,經過水平切分的優化,往往能解決單庫存儲量及性能瓶頸。但由於同一個表被分配在不同的數據庫,需要額外進行數據操作的路由工作,因此大大提升了系統複雜度。

2.4 水平分表

  水平分表其目的也是爲了解決單表數據量大的問題。本來水平分庫就可以解決了數據單表數據量過大的問題,爲啥還要進行水平分表呢?
  在水平分庫中,如果繼續按照其他規則分下去,會不斷得增加服務器數量,對運維的成分是相當的高。因此需要水平分表。
  水平分表與水平分庫的思路類似,不過這次操作的目標是表,商品信息及商品描述被分爲兩套表。如果商品 ID 爲雙數,將此操作映射到雙數的商品信息表,反之則插入單數的商品信息表。這就是水平分表
  水平分表是在同一個數據庫內,把同一張表的數據按照一定規則拆到多個表中。

對數據行的拆分,不影響表結構

  優點

  • 優化單一表數據量過大而產生的性能問題
  • 避免 IO 爭搶並減少鎖表的機率

  庫內的水平分表,解決了單一表數據量過大的問題,分出來的小表中只含有一部分數據,從而使得單個表的數據量變小,提高檢索性能。

3 分庫分錶帶來的問題

  分庫分表能有效的緩解了單機和單庫帶來的性能瓶頸和壓力,突破網絡 IO、硬件資源、連接數的瓶頸,同時也帶來了一些問題。

3.1 事務一致性問題

  由於分庫分表把數據分佈在不同庫甚至不同服務器,不可避免會帶來分佈式事務問題。

3.2 跨節點關聯查詢

  在沒有分庫之前,我們檢索商品時可以通過以下 SQL 對店鋪信息進行關聯查詢,

Select p.*,r.[地理區域名稱], s.[店鋪名稱], s.[信譽] from shop 
Left join [地理區域] r on p.[產地] = r.[地理區域編碼]
Left join [店鋪信息] s on p.id = s.[所屬店鋪]
where ... order by ...limit ..

  但垂直分庫之後【商品信息】和【店鋪信息】不在一個數據庫,甚至不在一臺服務器,無法進行關聯查詢。
  可將原關聯查詢分爲兩次查詢,第一次查詢的結果集中找出關聯數據 id,然後根據 id 發起第二次請求得到關聯數據,最後將得到的數據進行拼裝。

3.3 跨節點分頁、排序函數

  跨節點多庫進行查詢時,limit 分頁、order by 排序等問題,就變得比較複雜了。需要先在不同的分片節點中將數據進行排序並返回,然後將不同分片返回的結果集進行彙總和再次排序。
  如,進行水平分庫後的商品庫,按 ID 排序分頁,取第一頁:

在這裏插入圖片描述
  以上流程是第一頁的數據,性能影響不大,但由於商品信息的分佈在各數據庫的數據可能是隨機的,如果是取第 N 頁,需要將所有節點前 N 頁數據都取出來合併,再進行整體的排序,操作效率可想而知,所以請求頁數越大,系統的性能也會越差。
  在使用 Max、Min、Sum、Count 之類的函數進行計算的時候,與排序分頁同理,也需要先在每個分片上執行相應的函數,然後將各個分片的結果集進行彙總和再次計算,最終將結果返回。

3.4 主鍵避重

  在分庫分表環境中,有偶遇表中數據同時存在不同數據庫中,主鍵值平時的自增長將無用武之地,某個分區數據庫生成的 ID 無法保證全局唯一。因此需要單獨設計全局主鍵,以避免跨庫主鍵重複問題。

在這裏插入圖片描述

3.5 公共表

  實際的應用場景中,參數表、數據字典表等都是數據量較小,變動少,而且數據高頻聯合查詢的依賴表。例子中地理區域表也屬於此類型。
  可以將這類表在每個數據庫都保存一份,所有對公共表的更新操作都同時發動到所有分庫執行。
  由於分庫分表之後,數據被分散在不同的數據庫、服務器。因此,對數據的操作也就無法通過常規方式完成,並且它還帶來了一系列的問題。好在,這些問題不是所有都需要我們在應用層面上解決,市面上有很多中間件可供我們選擇,其中 Sharding-JDBC 使用流行度較高,接下來的章節來了解一下它。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章