一步步用資料庫中間Mycat+SpringBoot完成分庫分表

来源:https://www.cnblogs.com/coderjava/archive/2020/06/17/13154943.html
-Advertisement-
Play Games

一、背景 隨著時間和業務的發展,資料庫中的數據量增長是不可控的,庫和表中的數據會越來越大,隨之帶來的是更高的磁碟、IO、系統開銷,甚至性能上的瓶頸,而一臺服務的資源終究是有限的,因此需要對資料庫和表進行拆分,從而更好的提供數據服務。 當用戶表達到千萬級別,在做很多操作的時候都會很吃力,所以當數據增長 ...


一、背景

 

隨著時間和業務的發展,資料庫中的數據量增長是不可控的,庫和表中的數據會越來越大,隨之帶來的是更高的磁碟、IO、系統開銷,甚至性能上的瓶頸,而一臺服務的資源終究是有限的,因此需要對資料庫和表進行拆分,從而更好的提供數據服務。

當用戶表達到千萬級別,在做很多操作的時候都會很吃力,所以當數據增長到1000萬以上就需要分庫分表來緩解單庫(表)的壓力。

二、什麼是分庫分表[1]

 

簡單來說,就是指通過某種特定的條件,將我們存放在同一個資料庫中的數據分散存放到多個資料庫(主機)上面,以達到分散單台設備負載的效果。

數據的切分(Sharding)根據其切分規則的類型,可以分為兩種切分模式。一種是按照不同的表(或者Schema)來切分到不同的資料庫(主機)之上,這種切可以稱之為數據的垂直(縱向)切分;另外一種則是根據表中的數據的邏輯關係,將同一個表中的數據按照某種條件拆分到多台資料庫(主機)上面,這種切分稱之為數 據的水平(橫向)切分。

垂直切分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非常低,相互影響很小,業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業務模塊所使用的表分拆到不同的資料庫中。根據不同的表來進行拆分,對應用程式的影響也更小,拆分規則也會比較簡單清晰。

水平切分於垂直切分相比,相對來說稍微複雜一些。因為要將同一個表中的不同數據拆分到不同的資料庫中,對於應用程式來說,拆分規則本身就較根據表名來拆分更為複雜,後期的數據維護也會更為複雜一些。

三、垂直切分 [1]

 

個資料庫由很多表的構成,每個表對應著不同的業務,垂直切分是指按照業務將表進行分類,分佈到不同 的資料庫上面,這樣也就將數據或者說壓力分擔到不同的庫上面,如下圖:

 

img

 

系統被切分成了,用戶,訂單交易,支付幾個模塊。 一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模塊所組成的,而每一個功能模塊所需要的數據對應到資料庫中就是一個或者多個表。而在架構設計中,各個功能模塊相互之間的交互點越統一越少,系統的耦合度就越低,系統各個模塊的維護性以及擴展性也就越好。這樣的系統,實現數據的垂直切分也就越容易。

但是往往系統之有些表難以做到完全的獨立,存在這擴庫 join 的情況,對於這類的表,就需要去做平衡,是資料庫讓步業務,共用一個數據源,還是分成多個庫,業務之間通過介面來做調用。在系統初期,數據量比較少,或者資源有限的情況下,會選擇共用數據源,但是當數據發展到了一定的規模,負載很大的情況,就需 要必須去做分割。

一般來講業務存在著複雜 join 的場景是難以切分的,往往業務獨立的易於切分。如何切分,切分到何種 程度是考驗技術架構的一個難題。 下麵來分析下垂直切分的優缺點:

優點

拆分後業務清晰,拆分規則明確;

系統之間整合或擴展容易;

數據維護簡單。

缺點

部分業務表無法 join,只能通過介面方式解決,提高了系統複雜度;

受每種業務不同的限制存在單庫性能瓶頸,不易數據擴展跟性能提高;

事務處理複雜。

由於垂直切分是按照業務的分類將表分散到不同的庫,所以有些業務表會過於龐大,存在單庫讀寫與存儲瓶頸,所以就需要水平拆分來做解決。

四、水平切分 [1]

 

相對於垂直拆分,水平拆分不是將表做分類,而是按照某個欄位的某種規則來分散到多個庫之中,每個表中包含一部分數據。簡單來說,我們可以將數據的水平切分理解為是按照數據行的切分,就是將表中的某些行切分到一個資料庫,而另外的某些行又切分到其他的資料庫中,如圖

 

img

拆分數據就需要定義分片規則。關係型資料庫是行列的二維模型,拆分的第一原則是找到拆分維度。比如: 從會員的角度來分析,商戶訂單交易類系統中查詢會員某天某月某個訂單,那麼就需要按照會員結合日期來拆分,不同的數據按照會員 ID 做分組,這樣所有的數據查詢 join 都會在單庫內解決;如果從商戶的角度來講,要查詢某個商家某天所有的訂單數,就需要按照商戶 ID 做拆分;但是如果系統既想按會員拆分,又想按商家數據,則會有一定的困難。如何找到合適的分片規則需要綜合考慮衡。 幾種典型的分片規則包括:

按照用戶 ID 求模,將數據分散到不同的資料庫,具有相同數據用戶的數據都被分散到一個庫中;

按照日期,將不同月甚至日的數據分散到不同的庫中;

按照某個特定的欄位求摸,或者根據特定範圍段分散到不同的庫中。

如圖,切分原則都是根據業務找到適合的切分規則分散到不同的庫,下麵用用戶 ID 求模舉

img

既然數據做了拆分有優點也就優缺點。 優點

 

拆分規則抽象好,join 操作基本可以資料庫做;

不存在單庫大數據,高併發的性能瓶頸;

應用端改造較少;

提高了系統的穩定性跟負載能力。

缺點

拆分規則難以抽象;

分片事務一致性難以解決;

數據多次擴展難度跟維護量極大;

跨庫 join 性能較差

五、什麼是Mycat

 

它是一個開源的分散式資料庫系統,是一個實現了 MySQL 協議的的 Server,前端用戶可以把它看作是一個資料庫代理,用 MySQL 客戶端工具和命令行訪問,而其後端可以用MySQL 原生(Native)協議與多個 MySQL 伺服器通信,也可以用 JDBC 協議與大多數主流資料庫伺服器通信,其核心功能是分表分庫,即將一個大表水平分割為 N 個小表,存儲在後端 MySQL 伺服器里或者其他資料庫里。

常見應用場景:

單純的讀寫分離,此時配置最為簡單,支持讀寫分離,主從切換;

分表分庫,對於超過 1000 萬的表進行分片,最大支持 1000 億的單表分片;

多租戶應用,每個應用一個庫,但應用程式只連接 Mycat,從而不改造程式本身,實現多租戶化;

報表系統,藉助於 Mycat 的分表能力,處理大規模報表的統計; 替代 Hbase,分析大數據;

作為海量數據實時查詢的一種簡單有效方案,比如 100 億條頻繁查詢的記錄需要在 3 秒內查詢出來結果,除了基於主鍵的查詢,還可能存在範圍查詢或其他屬性查詢,此時 Mycat 可能是最簡單有效的選

六、SpringBoot+Mycat+MySQL實現分表分庫案例

 

關於分庫分表,Mycat已經幫我們在內部實現了路由的功能,我們只需要在Mycat中配置以下切分規則即可,對於開發者來說,我們就可以把Mycat看做是一個資料庫,接下來我們開始搭建環境:

步驟一:

Mycat是使用java寫的資料庫中間件,所以要運行Mycat前要準備要jdk的環境,要求是jdk1.7以上的環境。所以需要在系統中配置JAVA_HOME的環境變數.

步驟二:

從官網下載Mycat,http://dl.mycat.io/1.6-RELEASE/我們是基於CentOS7來搭建Mycat環境的,所以下載版本: Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

步驟三:

將下載好的安裝包上傳到伺服器上並解壓.解壓之後目錄結構如下:

 

img

步驟四:

配置切分規則: 將如下配置複製粘貼覆蓋mycat/conf/schema.xml的內容。

 <?xml version="1.0"?>
 <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
 <mycat:schema xmlns:mycat="http://io.mycat/"><schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
            <table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />  
    </schema>
    
    <!-- 設置dataNode 對應的資料庫,及 mycat 連接的地址dataHost -->  
    <dataNode name="dn01" dataHost="dh01" database="db01" />  
    <dataNode name="dn02" dataHost="dh01" database="db02" />  
    
    <!-- mycat 邏輯主機dataHost對應的物理主機.其中也設置對應的mysql登陸信息 -->  
    <dataHost name="dh01" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">  
            <heartbeat>select user()</heartbeat>  
            <writeHost host="server1" url="127.0.0.1:3306" user="root" password="WolfCode_2017"/>  
    </dataHost> 
 </mycat:schema>

 


 

`:表示的是在mycat中的邏輯庫配置,邏輯庫名稱為:TESTDB`

​ :表示在mycat中的邏輯表配置,邏輯表名稱為:user,映射到兩個資料庫節點dataNode中,切分規則為:rule1(在rule.xml配置) ​

``:表示資料庫節點,這個節點不一定是單節點,可以配置成讀寫分離.

``:真實的資料庫的地址配置

``:用戶心跳檢測

``:寫庫的配置

將如下配置複製粘貼覆蓋mycat/conf/rule.xml的內容。

 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mycat:rule SYSTEM "rule.dtd">
 <mycat:rule xmlns:mycat="http://io.mycat/">
    <tableRule name="rule1">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">2</property>
    </function>
 </mycat:rule>

 

 

 

這裡定義的是切分規則,是按照id列進行切分,切分規則是採取取模的方式, 2:這裡配置了我們有拆分了多個庫(表),需要和前面配置 `` 中的dataNode個數一致,否則會出錯.

步驟五:

在資料庫中創建兩個資料庫db01,db02. 每個庫中執行如下建表語句:

 CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

步驟六:

啟動mycat,執行mycat/bin/startup_nowrap.sh

步驟七:

項目已經上傳到github

搭建SpringBoot環境,執行插入語句. application.properties配置如下:

 
#配置數據源
 spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
 #這裡配置的是Mycat中server.xml中配置賬號密碼,不是資料庫的密碼。
 spring.datasource.druid.username=root
 spring.datasource.druid.password=123456
 #mycat的邏輯庫 埠也是mycat的
 spring.datasource.druid.url=jdbc:mysql://192.168.142.129:8066/TESTDB
 ​
 ​
 UserMapper.java代碼如下:
 ​
 @Mapper
 public interface UserMapper {
    @Insert("insert into user(id,name) value (#{id},#{name})")
    int insert(User user);
    @Select("select * from user")
    List<User> selectAll();
 }
 ​
 UserController.java代碼如下:
 ​
 @RestController
 @RequestMapping("/user")
 public class UserController {
    @Autowired
    private UserMapper userMapper;
    @RequestMapping("/save")
    public String save(User user){
        userMapper.insert(user);
        return "保存成功";
    }
    @RequestMapping("/list")
    public List<User> list(){
        return userMapper.selectAll();
    }
 }

 

步驟八:

測試: 在地址欄輸入: http://localhost:8080/user/save?id=1&name=tom http://localhost:8080/user/save?id=2&name=jack 查看資料庫發現: id為1的數據插入到資料庫db02中的user表。 id為2的數據插入到資料庫db01中的user表。 在地址欄輸入: http://localhost:8080/user/list 是可以看到剛剛插入的兩條記錄.

好到這一步我們就已經完成了分表分庫了.

 

總結

我給大家準備了很多的學習資料免費獲取,包括但不限於java進階學習資料、技術乾貨、大廠面試題系列、技術動向、職業生涯等一切有關程式員的分享.

java進階方法筆記,學習資料,面試題,電子書籍免費領取,讓你更輕鬆的學習java

更多學習內容和乾貨請看我的b站視頻:點擊進入我的主頁


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 伺服器需要將發送的多媒體數據的類型告訴瀏覽器,而告訴瀏覽器的手段就是告知多媒體的MIME類型。 form表單中的enctype屬性,可以告訴伺服器,我們提供給它的內容的MIME類型。 enctype屬性有三種狀態值: 1). application/x-www-form-urlencoded 數據發 ...
  • 優秀的大前端人才應該具備熟練編寫任何一個互聯網系統的前端頁面、交互代碼的能力,作者從事IT6年,目前是一名全棧開發工程師,根據這些年在職場的經驗,結合目前互聯網環境下對於前端工程師的招聘要求分析,總結出企業要求主要分為硬核技能、輔助要求兩部分。 一、硬核技能 第一階段:HTML+CSS:HTML、C ...
  • 本人一直推崇寫流暢、自然、可自解釋的代碼,讓優雅成為一種習慣。 溫故而知新,聊一聊現代編程幾大常見的編程原則 普世原則 KISS (Keep It Simple Stupid) 保持系統結構簡單可信賴 YAGNI (you aren't gonna need it) 當前確實需要,再去做 Do Th ...
  • 模板方法是結構最簡單的行為型設計模式,在抽象類中定義了一個稱為模板方法的方法,在這個方法中定義其他基本方法的執行步驟,而基本方法的實現可以放在抽象類,也可以放在其子類 模式動機 現實生活中很多事情的完成過程都包含幾個基本步驟,例如請客吃飯,無論吃什麼,一般都包含點單、吃東西、買單幾個步驟,到底吃什麼 ...
  • 結合一些文章閱讀源碼後整理的Java容器常見知識點。對於一些代碼細節,本文不展開來講,有興趣可以自行閱讀參考文獻。 ...
  • 一、不同輸出格式會有不同的結果 1.%ld 用於long類型的值,如果系統中int和long大小相同,使用%d就可以,這樣的程式被移植到其他系統(int和long類型的大小不同)。 2.同樣x和o​前面也可以使用l來修飾。 3.對於short類型,前面就是使用h來​當首碼。 4.h和l首碼都可以和u ...
  • 關於變數的命名,這又是一個容易引發程式員論戰的話題。如何命名才能更具有可讀性、易寫性與明義性呢?眾說紛紜。 本期“Python為什麼”欄目,我們將聚焦於變數命名中的連接方式,來切入這塊是非之地,想要回答的問題是——Python 為什麼要推薦蛇形命名法? 首先一點,對於單個字元或者單詞 (例如:a、A ...
  • 最近也是在後臺收到很多小伙伴私信問我線程和線程池這一塊的問題,說自己在面試的時候老是被問到這一塊的問題,被問的很頭疼。前幾天看到後幫幾個小伙伴解決了問題,但是問的人有點多我一個個回答也回答不過來,乾脆花了一個上午時間寫了這篇文章分享給大家。話不多說,滿滿的乾貨都在下麵了! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...