mysql 分庫分表分割槽 動態擴容 總結

2021-10-10 13:55:26 字數 4318 閱讀 2184

mysql 自帶有分區分表策略、具體參考只能說單庫情況下、並且簡單的情況如按時間做range分割槽可以使用mysql自帶分割槽策略。更多的情況下完全要自己**邏輯實現。

sharding-jdbc和mycat使用不同的理念,sharding-jdbc目前是基於jdbc驅動,無需額外的proxy,因此也無需關注proxy本身的高可用。mycat 是基於 proxy,它複寫了 mysql 協議,將 mycat server 偽裝成乙個 mysql 資料庫,而 sharding-jdbc 是基於 jdbc 介面的擴充套件,是以 jar 包的形式提供輕量級服務的。

應用程式和資料庫 中間,單獨部署乙個**層中介軟體,所有的連線和資料庫操作都發給這個**層,由**層去做底層的實現。

(1)事先在**中介軟體上配置分片規則、

(2)**中介軟體攔截客戶端sql、並對sql解析:如分片分析、路由分析、讀寫分離分析、快取分析等,然後將此sql發往後端的真實資料庫

(3)並將返回的結果做適當的處理,最終再返回給使用者。

(4)對返回結果進行合併等相關處理處理、並返回給客戶端。

這樣做對開發人員來說,是完全不需要知道下面做了什麼的,甚至不需要做任何的**改造,就可以完成接入;

常見的框架有:mycat(支援 mysql, oracle, db2, postgresql, sql server等主流資料庫,基於cobar改造的)、cobar(阿里,已停止維護)、mysql-proxy、atlas(360開源的)、sharing-sphere(噹噹)等等。

在客戶端做路由分發等相關操作、如sharding-jdbc,是乙個jar包、應用程式整合此jar包開發即可。

此處列舉幾個常用的演算法

如按照時間2020-10到2020-11月在乙個表、按照金額100此方法可以方便動態擴容、不需要遷移資料、不需要重啟db服務。

容易產生熱點問題、如某個月資料量特別大

對id的hash取模x。網上搜很多例子

事先確定表數量n、直接x%n得到表的下標,對一開始需要分配很多表的比較方便

hash分布不均勻(如果id不是自增整形、hash函式影響河大)、會導致表的負載不均勻

無法指定某個id到某個表

後期動態擴容麻煩、需要重新計算hash、並遷移資料庫、遷移過程可能需要停止愛資料庫服務。

如果增加表、則原來所有表都要重新計算並遷移資料。

如果只新增n個表、則最多隻需要遷移原來的n個表、最少只需要遷移原來的1個表。

請參考下一章節

即插入時、就固定此 記錄 所在哪個表中、此種方式不在需要重啟或者暫停資料庫、不影響應用。

還是回到分片key問題上,要解決熱點寫入問題,最終還是要處理,如何盡可能均衡的寫入到資料庫,緩解熱點壓力,所以還是要從分片key生成策略上入手。既然使用精確分片演算法(preciseshardingalgorithm),那就準確的控制資料最終會落到哪乙個庫哪乙個表。分片key設計如下:

因為新增資料時已經在記錄的key上固定了資料庫表的的編號。

因為不需要遷移

擴充資料庫表時、用用端只需要修改原來的key生成演算法即可。

利用redis 儲存列表+lua原子原子操作。

按照以上的邏輯,是解決了資料庫擴容的問題。但是出現了乙個新的問題,繼續往復的生成分片key,資料還是分散的到每個庫每個表,我們之所以要增加資料庫擴容,是因為原有的資料庫表資料量已經到了計畫擴容的臨界值,我們才進行擴容。這時候我們希望降低原有資料庫的資料寫入權重。這裡我的想法是根據各庫表的容量做乙個分片key生成的動態權重調整,出發點是定時任務統計每個庫的每個表資料量來進行調整。

總的來說:如何確定key的庫表編號 或者說 如何確定資料應該到哪個表或者庫呢,我們根建立據資料庫表時預估容量 和 當前使用容量,來控制插入某個資料庫表的概率或者權重、具體實現請看下面章節。

假如現在表a在庫中分了兩個表、編號分別是0101,0102 他們預估容量是1:1、下面我們要做基於權重生成key。

根據表預估容量大小比為1:2、所以我們 初始化庫表編號dtl列表[0101,0102,0102]

每次生成key隨機從列表中取乙個數

定時或者手動查詢表的容量、動態調整權重。如此時發現兩表的已用容量為2:1,則此時兩表的剩餘容量變為1:4 則要調整dtl=[0101,0102,0102,0102,0102] ,是為了讓更多的資料進入到0102來保持平衡

當擴容時增加表時、同樣要考慮到 預估容量與億使用容量 進行初始化dtl列表。防止資料分配不均衡。

此章節** 

我們計畫單個表的資料量為300萬(可以根據資料庫伺服器效能評估表的資料量上限),當表資料量超過計畫閾值,我們開始降低表的寫入權重,

計畫定了三檔閾值,我們就初始化三個寫入權重,生成好以後放入環形結構的陣列。

任務統計結束後,01庫的01表達到第一檔閾值,重新初始化資料環的時候,移除乙個權重,到達第二檔再移除乙個權重。

當某個表資料量到達第三檔,不再寫入資料,重新初始化環,移除這個表的寫入權重。

增加資料庫後,我們需要重新初始化環,需要確認新增資料寫入擴容新增的資料庫中,可以考慮手動觸發重新初始化,如果任務時間間隔不長,也可以等待任務初始化,只需要注意任務執行後有資料寫入新庫即可。

前面提到的權重調整,判斷依據是表的資料量是否達到閾值,注意是分庫分表的每個庫里的每個表單獨統計是否達到閾值進行調整,採用定時任務的方式執行,間隔頻率可以根據資料增長量評估。

這個方案雖然很好的解決了擴充套件增加資料庫的問題,但是也有一些使用的侷限,首先,依賴於資料分片key的生成,很難再已有資料的基礎上使用這個方案(接受新的資料關聯key有不小的調整成本)。其次,資料分片位生成策略也有一定的複雜度,這裡不再深入,方案其實很多,借助於zk或者redis等三方工具可以搭建乙個序號生成服務,既能保證一定的效率,也能保證序號的唯一性。

如果是新的業務線,在資料增量上無法預估未來一兩年的資料量,考慮使用分庫分表,不妨可以考慮這個方案,減少增加庫和表帶來的痛苦。以後有足夠的運維能力支撐tidb,分庫分表帶來的詬病才能一掃而光,最終還是單錶操作來的香,啥也不多想,上去就幹(tidb也有不少坑等著踩)!

業務場景:關聯不同資料庫中的表的查詢

比如說,要關聯的表是:機器a上的資料庫a中的表a && 機器b上的資料庫b中的表b。

這種情況下,想執行「select a.id,b.id from a left join b on ~~~;「那是不可能的,但業務需求不可變,資料庫設計不可變,這就蛋疼了。。

解決方案:在機器a上的資料庫a中建乙個表b。。。

這當然不是跟你開玩笑啦,我們採用的是基於mysql的federated引擎的建表方式

建表語句示例:create table `table_name`(......) engine =federated connection='mysql://[username]:[password]@[location]:[port]/[db-name]/[table-name]'

前提條件:你的mysql得支援federated引擎(執行show engines;可以看到是否支援)。

如果有federated引擎,但support是no,說明你的mysql安裝了這個引擎,但沒啟用,去my.cnf檔案末新增一行  federated  ,重啟mysql即可;

如果壓根就沒有federated這一行,說明你的mysql就沒有安裝這個引擎,這就不能愉快的玩耍了,最好去找你們家運維搞定吧,因為接下來的動作比較大,而且我也不知道怎麼搞;

解釋:通過federated引擎建立的表只是在本地有表定義檔案,資料檔案則存在於遠端資料庫中,通過這個引擎可以實現類似oracle 下dblink的遠端資料訪問功能。就是說,這種建表方式只會在資料庫a中建立乙個表b的表結構檔案,表的索引、資料等檔案還是在機器b上的資料庫b中,相當於只是在資料庫a中建立了表b的乙個快捷方式。

需要注意的幾點:

1. 本地的表結構必須與遠端的完全一樣。

2.遠端資料庫目前僅限mysql

3.不支援事務

4.不支援表結構修改

mysql oracle 動態擴容分庫分表 面試題

如何設計可以動態擴容縮容的分庫分表方案?對於分庫分表來說,主要是面對以下問題 這個是你必須面對的乙個事兒,就是你已經弄好分庫分表方案了,然後一堆庫和表都建好了,基於分庫分表中介軟體的 開發啥的都好了,測試都 ok 了,資料能均勻分布到各個庫和各個表裡去,而且接著你還通過雙寫的方案咔嚓一下上了系統,已...

MySQL 分庫分表及其平滑擴容方案

眾所周知,資料庫很容易成為應用系統的瓶頸。單機資料庫的資源和處理能力有限,在高併發的分布式系統中,可採用分庫分表突破單機侷限。本文總結了分庫分表的相關概念 全域性id的生成策略 分片策略 平滑擴容方案 以及流行的方案。1 分庫分表概述 在業務量不大時,單庫單錶即可支撐。當資料量過大儲存不下 或者併發...

mysql分表分庫實現 MySql分表分庫思路

一.資料庫瓶頸 1.1io瓶頸 第一種 磁碟讀io瓶頸,熱點資料太多,資料庫快取放不下,每次查詢時會產生大量的io 分庫和垂直分表 第二種 網路io瓶頸,請求的資料太多,網路頻寬不夠 分庫 1.2cpu瓶頸 第一種 sql問題,如sql中包含join,group by,order by,非索引字段條...