分庫分表的故事

數(shù)據(jù)分片

  • 一般單表的數(shù)據(jù)閾值在1TB之內(nèi),當(dāng)超過1TB的時(shí)候,就需要進(jìn)行數(shù)據(jù)分片了

垂直分片

按照業(yè)務(wù)進(jìn)行拆分,不同的業(yè)務(wù)在不同的庫中,將數(shù)據(jù)訪問壓力由單庫分散到不同的庫中,但是,當(dāng)表數(shù)據(jù)量超過單節(jié)點(diǎn)閾值的時(shí)候,還是需要進(jìn)行水平分片


水平分片

水平分片一般是指將單表根據(jù)某個(gè)或者某幾個(gè)字段 分成多個(gè)庫或者多個(gè)表內(nèi),每個(gè)分片只包含數(shù)據(jù)的一部分。

邏輯表

水平拆分的數(shù)據(jù)庫(表)的相同邏輯和數(shù)據(jù)結(jié)構(gòu)表的總稱。例:訂單數(shù)據(jù)根據(jù)主鍵尾數(shù)拆分為 10 張表,分別是 t_order_0 到 t_order_9,他們的邏輯表名為 t_order。不是一個(gè)真實(shí)存在的表

真實(shí)表

在分片的數(shù)據(jù)庫中真實(shí)存在的物理表。即上個(gè)示例中的 t_order_0 到 t_order_9。

數(shù)據(jù)節(jié)點(diǎn)

數(shù)據(jù)分片的最小單元。由數(shù)據(jù)源名稱和數(shù)據(jù)表組成,例:ds_0.t_order_0。

綁定表

  • 指分片規(guī)則一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,則此兩張表互為綁定表關(guān)系。綁定表之間的多表關(guān)聯(lián)查詢不會(huì)出現(xiàn)笛卡爾積關(guān)聯(lián),關(guān)聯(lián)查詢效率將大大提升
  • 想我們一般的電商系統(tǒng)中,一般都會(huì)使用用戶id進(jìn)行分片,這樣,用戶的訂單信息,會(huì)員信息,優(yōu)惠價(jià)信息等等都在一個(gè)分片中
  • 如不配置,那么在進(jìn)行聯(lián)表查詢的時(shí)候,如果兩個(gè)表,會(huì)雙雙組合,成
    01,10,11,00,四個(gè)語句,如果配置了,只會(huì)在產(chǎn)生11,00兩條查詢語句。

廣播表

指所有的分片數(shù)據(jù)源中都存在的表,表結(jié)構(gòu)和表中的數(shù)據(jù)在每個(gè)數(shù)據(jù)庫中均完全一致。適用于數(shù)據(jù)量不大且需要與海量數(shù)據(jù)的表進(jìn)行關(guān)聯(lián)查詢的場(chǎng)景

分片策略

  • 標(biāo)準(zhǔn)分片策略 -> 單字段分片
  • 符合分片策略 -> 多字段分片
  • Hint分片策略 -> 外部條件分片

分片維度

  • 表維度 - 分表
  • 數(shù)據(jù)源維度 - 分庫

核心原理

解析引擎

將sql語句解析為語法樹,分為詞法分析和語法分析。


抽象語法樹中的關(guān)鍵字的 Token 用綠色表示,變量的 Token 用紅色表示,灰色表示需要進(jìn)一步拆分

路由引擎

用于根據(jù)分片鍵進(jìn)行路由的場(chǎng)景,又細(xì)分為直接路由、標(biāo)準(zhǔn)路由和笛卡爾積路由這 3 種類型。

改寫引擎

  • 標(biāo)識(shí)符改寫
    將原始邏輯表sql語句更改為可以執(zhí)行的真實(shí)表sql語句,一般為更改表名,還有其他的索引,視圖。
SELECT order_id FROM t_order WHERE order_id=1 AND remarks=' t_order xxx';
改為
SELECT order_id FROM t_order_1 WHERE order_id=1 AND remarks=' t_order xxx';
  • 補(bǔ)列
  1. 對(duì)于分組和排序的sql,如果在返回結(jié)果中沒有排序或者分組的列,會(huì)自動(dòng)將這列進(jìn)行補(bǔ)充
  2. 使用avg函數(shù)的時(shí)候,需要把sum和cout,補(bǔ)充,否則計(jì)算也是不準(zhǔn)確的

執(zhí)行引擎

sql的執(zhí)行需要考慮是否為每一個(gè)sql語句創(chuàng)建一個(gè)連接,同一個(gè)庫里面是否只創(chuàng)建一個(gè)連接。

  • 內(nèi)存限制模式
    不限制連接數(shù)量,每張表創(chuàng)建一個(gè)連接,并使用多線程的方式處理,速度最快。
  • 連接限制模式
    同一個(gè)庫只會(huì)創(chuàng)建一個(gè)連接,不同庫中的表,每個(gè)庫也只會(huì)創(chuàng)建一個(gè)連接

自動(dòng)化執(zhí)行引擎

    • 不必配置執(zhí)行模式,Sharding根據(jù)當(dāng)前情況自動(dòng)選擇,根據(jù)用戶設(shè)置的 maxConnectionSizePerQuery ,每個(gè)連接最多執(zhí)行的sql數(shù)

1. 準(zhǔn)備階段

  • 用于準(zhǔn)備執(zhí)行的數(shù)據(jù)。它分為結(jié)果集分組和執(zhí)行單元?jiǎng)?chuàng)建兩個(gè)步驟。
  • 首先根據(jù)庫進(jìn)行分組,然后使用下圖的方式進(jìn)行判斷


    選擇情況
  • 為了防止獲取連接的時(shí)候死鎖的出現(xiàn),每次獲取連接都是原子性獲取本次需要的全部連接

2. 執(zhí)行階段

用于真正的執(zhí)行 SQL,它分為分組執(zhí)行和歸并結(jié)果集生成兩個(gè)步驟。


執(zhí)行過程

歸并引擎

  • 流式歸并是指每一次從結(jié)果集中獲取到的數(shù)據(jù),都能夠通過逐條獲取的方式返回正確的單條數(shù)據(jù),它與數(shù)據(jù)庫原生的返回結(jié)果集的方式最為契合。遍歷、排序以及流式分組都屬于流式歸并的一種。

  • 內(nèi)存歸并則是需要將結(jié)果集的所有數(shù)據(jù)都遍歷并存儲(chǔ)在內(nèi)存中,再通過統(tǒng)一的分組、排序以及聚合等計(jì)算之后,再將其封裝成為逐條訪問的數(shù)據(jù)結(jié)果集返回。

  • 裝飾者歸并是對(duì)所有的結(jié)果集歸并進(jìn)行統(tǒng)一的功能增強(qiáng),目前裝飾者歸并有分頁歸并和聚合歸并這 2 種類型。

遍歷歸并

將多個(gè)數(shù)據(jù)集合并為一個(gè)數(shù)據(jù)集

排序歸并

將每個(gè)數(shù)據(jù)集,采用游標(biāo)的方式,一步一步的去處數(shù)據(jù),實(shí)現(xiàn)排序


排序方式

分組歸并

  • 流式歸并
    需要排序字段和分組字段一致,這樣使用next指針不用回溯就可以實(shí)現(xiàn)歸并
  • 內(nèi)存歸并
    全部數(shù)據(jù)取出來,在內(nèi)存中進(jìn)行排序

聚合歸并

  • 其他聚合能力的裝飾
    比較類型的聚合函數(shù)是指 MAX 和 MIN。它們需要對(duì)每一個(gè)同組的結(jié)果集數(shù)據(jù)進(jìn)行比較,并且直接返回其最大或最小值即可。

累加類型的聚合函數(shù)是指 SUM 和 COUNT。它們需要將每一個(gè)同組的結(jié)果集數(shù)據(jù)進(jìn)行累加。

求平均值的聚合函數(shù)只有 AVG。它必須通過 SQL 改寫的 SUM 和 COUNT 進(jìn)行計(jì)算。

分頁歸并

  • 其他聚合能力的裝飾
  • 如果直接使用limit進(jìn)行分頁,可能會(huì)造成,將查詢頁前所有數(shù)據(jù)查詢出來,造成大量的內(nèi)存浪費(fèi),為了解決這個(gè)問題,除了內(nèi)存分組,其他情況Sharding采用流式歸并的方法獲取結(jié)果集
  • 另外采用官方建議采用id分頁的方式
歸并

分片算法

求余算法:

只要根據(jù)分片參數(shù)進(jìn)行求余即可得出分片。性能也比較好。缺點(diǎn)是伸縮性不太好,一旦要增加一個(gè)新的分片,就需要對(duì)全部舊的數(shù)據(jù)進(jìn)行數(shù)據(jù)遷移。

哈希一致性算法

  • 假設(shè)一個(gè)圓由2的32次方組成,這個(gè)圓稱為為哈希環(huán)。每個(gè)節(jié)點(diǎn)負(fù)責(zé)一個(gè)區(qū)域,獲取到哈希值的時(shí)候,其落點(diǎn)的下一個(gè)節(jié)點(diǎn)就是分片位置。這樣當(dāng)需要節(jié)點(diǎn)增減的時(shí)候,只需要移動(dòng)最近的一個(gè)節(jié)點(diǎn)數(shù)據(jù)即可,而不用對(duì)全部分片的數(shù)據(jù)都進(jìn)行遷移。
  • 哈希值劃分不均勻,導(dǎo)致每個(gè)區(qū)域不太一致
  • 劃分的節(jié)點(diǎn)太少的時(shí)候,容易造成一個(gè)很大的區(qū)間,導(dǎo)致所有的數(shù)據(jù)都流入某一個(gè)節(jié)點(diǎn),解決方式,使用虛擬節(jié)點(diǎn),將區(qū)域劃分為多個(gè)虛擬節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)負(fù)載幾個(gè)虛擬節(jié)點(diǎn)。這樣即使只有很少的節(jié)點(diǎn),也可以實(shí)現(xiàn)均衡。


    哈希一致性
  • 在java中實(shí)現(xiàn)中,如果覺得劃分過大,可以減少哈希環(huán)的大小,比如1000個(gè),然后我們使用 SortedMap 來實(shí)現(xiàn),這樣,我們使用tailMap方法 ,就可以獲取比當(dāng)前值大的一個(gè)節(jié)點(diǎn),很容易實(shí)現(xiàn)哈希算法

熱點(diǎn)分配

  • 大部分?jǐn)?shù)據(jù)都不是熱點(diǎn)數(shù)據(jù),但是若是某一個(gè)庫的數(shù)據(jù)熱點(diǎn)數(shù)據(jù)較多的時(shí)候,這個(gè)庫壓力就很大,等于我們的分片失去了應(yīng)有的作用,這個(gè)時(shí)候可以使用熱點(diǎn)分配法
  • 建立用戶級(jí)別熱點(diǎn)映射表,根據(jù)用戶的行為將用戶標(biāo)示為熱點(diǎn)用戶,以及其對(duì)應(yīng)的庫表,熱點(diǎn)數(shù)據(jù)可以定期遷移,保持各個(gè)節(jié)點(diǎn)之間的均衡

分布式ID

雪花算法 snowflake

生成一個(gè)long類型的數(shù)字id,其實(shí)就是對(duì)這64位的二進(jìn)制形式里面填值,把這64位分成幾個(gè)部分,彼此間互不影響,每部分都有自己的生成規(guī)則,這樣在一定的簡(jiǎn)單的大前提下,能保證全局唯一。


image.png

讀寫分離

  • 對(duì)于同一時(shí)刻有大量并發(fā)讀操作和較少寫操作類型的應(yīng)用系統(tǒng)來說,將數(shù)據(jù)庫拆分為主庫和從庫,主庫負(fù)責(zé)處理事務(wù)性的增刪改操作,從庫負(fù)責(zé)處理查詢操作,能夠有效的避免由數(shù)據(jù)更新導(dǎo)致的行鎖,使得整個(gè)系統(tǒng)的查詢性能得到極大的改善

  • ShardingSphere實(shí)現(xiàn)了 透明化讀寫分離所帶來的影響,讓使用方盡量像使用一個(gè)數(shù)據(jù)庫一樣使用主從數(shù)據(jù)庫集群

https://shardingsphere.apache.org/document/current/cn/features/sharding/principle/parse/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容