手把手帶你用數據庫中間件Mycat+SpringBoot完成分庫分表

1、背景 隨着時間和業務的發展,數據庫中的數據量增加是不可控的,庫和表中的數據會愈來愈大,隨之帶來的是更高的磁盤、IO、系統開銷,甚至性能上的瓶頸,而一臺服務的資源終究是有限的,所以須要對數據庫和表進行拆分,從而更好的提供數據服務。前端

當用戶表達到千萬級別,在作不少操做的時候都會很吃力,因此當數據增加到1000萬以上就須要分庫分表來緩解單庫(表)的壓力。java

2、什麼是分庫分表[1] 簡單來講,就是指經過某種特定的條件,將咱們存放在同一個數據庫中的數據分散存放到多個數據庫(主機)上面,以達到分散單臺設備負載的效果。mysql

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

垂直切分的最大特色就是規則簡單,實施也更爲方便,尤爲適合各業務之間的耦合度很是低,相互影響很小,業務邏輯很是清晰的系統。在這種系統中,能夠很容易作到將不一樣業務模塊所使用的表分拆到不一樣的數據庫中。根據不一樣的表來進行拆分,對應用程序的影響也更小,拆分規則也會比較簡單清晰。git

水平切分於垂直切分相比,相對來講稍微複雜一些。由於要將同一個表中的不一樣數據拆分到不一樣的數據庫中,對於應用程序來講,拆分規則自己就較根據表名來拆分更爲複雜,後期的數據維護也會更爲複雜一些。程序員

3、垂直切分 [1]github

個數據庫由不少表的構成,每一個表對應着不一樣的業務,垂直切分是指按照業務將表進行分類,分佈到不一樣spring

的數據庫上面,這樣也就將數據或者說壓力分擔到不一樣的庫上面,以下圖:sql

系統被切分紅了,用戶,訂單交易,支付幾個模塊。數據庫

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

可是每每系統之有些表難以作到徹底的獨立,存在這擴庫 join 的狀況,對於這類的表,就須要去作平衡,是數據庫讓步業務,共用一個數據源,仍是分紅多個庫,業務之間經過接口來作調用。在系統初期,數據量比較少,或者資源有限的狀況下,會選擇共用數據源,可是當數據發展到了必定的規模,負載很大的狀況,就需

要必須去作分割。

通常來說業務存在着複雜 join 的場景是難以切分的,每每業務獨立的易於切分。如何切分,切分到何種

程度是考驗技術架構的一個難題。

下面來分析下垂直切分的優缺點:

優勢:

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

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

數據維護簡單。

缺點:

部分業務表沒法 join,只能經過接口方式解決,提升了系統複雜度;

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

事務處理複雜。

因爲垂直切分是按照業務的分類將表分散到不一樣的庫,因此有些業務表會過於龐大,存在單庫讀寫與存儲瓶頸,因此就須要水平拆分來作解決。

4、水平切分 [1]

相對於垂直拆分,水平拆分不是將表作分類,而是按照某個字段的某種規則來分散到多個庫之中,每一個表中包含一部分數據。簡單來講,咱們能夠將數據的水平切分理解爲是按照數據行的切分,就是將表中的某些行切分到一個數據庫,而另外的某些行又切分到其餘的數據庫中,如圖

拆分數據就須要定義分片規則。關係型數據庫是行列的二維模型,拆分的第一原則是找到拆分維度。好比:

從會員的角度來分析,商戶訂單交易類系統中查詢會員某天某月某個訂單,那麼就須要按照會員結合日期來拆分,不一樣的數據按照會員 ID 作分組,這樣全部的數據查詢 join 都會在單庫內解決;若是從商戶的角度來說,要查詢某個商家某天全部的訂單數,就須要按照商戶 ID 作拆分;可是若是系統既想按會員拆分,又想按商家數據,則會有必定的困難。如何找到合適的分片規則須要綜合考慮衡。

幾種典型的分片規則包括:

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

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

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

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

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

優勢:

拆分規則抽象好,join 操做基本能夠數據庫作;

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

應用端改造較少;

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

缺點:

拆分規則難以抽象;

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

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

跨庫 join 性能較差

5、什麼是Mycat

它是一個開源的分佈式數據庫系統,是一個實現了 MySQL 協議的的

Server,前端用戶能夠把它看做是一個數據庫代理,用 MySQL 客戶端工具和命令行訪問,而其後端能夠用MySQL 原生(Native)協議與多個 MySQL 服務器通訊,也能夠用 JDBC 協議與大多數主流數據庫服務器通訊,其核心功能是分表分庫,即將一個大表水平分割爲 N 個小表,存儲在後端 MySQL 服務器裏或者其餘數據庫裏。

常見應用場景:

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

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

多租戶應用,每一個應用一個庫,但應用程序只鏈接 Mycat,從而不改造程序自己,實現多租戶化;

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

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

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

關於分庫分表,Mycat已經幫咱們在內部實現了路由的功能,咱們只須要在Mycat中配置如下切分規則便可,對於開發者來講,咱們就能夠把Mycat看作是一個數據庫,接下來咱們開始搭建環境:

步驟一:

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

步驟二:

從官網下載Mycat,dl.mycat.io/1.6-RELEASE…

Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

步驟三:

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

< ?xml version="1.0"?>

< !DOCTYPE mycat:schema SYSTEM "schema.dtd">

< mycat:schema xmlns:mycat="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">

< h eartbeat>select user()< /heartbeat >

<!- - 以爲文章對你有幫助的話,能夠加一下個人企鵝技術交流圈:519752913,我會在裏面不定時分享乾貨資源,但願可以對你有幫助 -->

< writeHost host="server1" url="127.0.0.1:3306" user="root" password="WolfCode_2017"/>

< /dataHost>

</ mycat:schema>

< s chema>:表示的是在mycat中的邏輯庫配置,邏輯庫名稱爲:TESTDB

< table>:表示在mycat中的邏輯表配置,邏輯表名稱爲:user,映射到兩個數據庫節點dataNode中,切分規則爲:rule1(在rule.xml配置)

< dataNode>:表示數據庫節點,這個節點不必定是單節點,能夠配置成讀寫分離.

< dataHost>:真實的數據庫的地址配置

< heartbeat>:用戶心跳檢測

< writeHost>:寫庫的配置

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

< !DOCTYPE mycat:rule SYSTEM "rule.dtd">

< m ycat:rule xmlns:mycat="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">

< property name="count">2< /property>

< /function>

< /mycat:rule>

這裏定義的是切分規則,是按照id列進行切分,切分規則是採起取模的方式,

< property name="count">2< /property>:這裏配置了咱們有拆分了多個庫(表),須要和前面配置

< table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />

中的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

github.com/javalanxion…

搭建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 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 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程序員涉及到的絕大部分難題我作成了文檔和架構視頻資料免費分享給你們(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式、高併發等架構技術資料),但願能幫助到且找到一個好的工做,也節省你們在網上搜索資料的時間來學習,也能夠關注我一下之後會有更多幹貨分享。

相關文章
相關標籤/搜索