先給你們介紹2個概念:數據的切分(Sharding)根據其切分規則的類型,能夠分爲兩種切分模式。前端
一種是按照不一樣的表(或者Schema)來切分到不一樣的數據庫(主機)之上,這種切能夠稱之爲數據的垂直(縱向)切分;另一種則是根據表中的數據的邏輯關係,將同一個表中的數據按照某種條件拆分到多臺數據庫(主機)上面,這種切分稱之爲數據的水平(橫向)切分。
垂直切分的最大特色就是規則簡單,實施也更爲方便,尤爲適合各業務之間的耦合度很是低,相互影響很小,業務邏輯很是清晰的系統。在這種系統中,能夠很容易作到將不一樣業務模塊所使用的表分拆到不一樣的數據庫中。根據不一樣的表來進行拆分,對應用程序的影響也更小,拆分規則也會比較簡單清晰。
水平切分於垂直切分相比,相對來講稍微複雜一些。由於要將同一個表中的不一樣數據拆分到不一樣的數據庫中,對於應用程序來講,拆分規則自己就較根據表名來拆分更爲複雜,後期的數據維護也會更爲複雜一些。
java
無論怎麼來講,數據切分雖然分散了單臺服務器負載,可是帶來了是設計和開發的複雜度。MyCat是一個開源的分佈式數據庫中間件,實現了MySQL協議的服務器,前端用戶能夠把它看做是一個數據庫代理,用MySQL客戶端工具和命令行訪問,而其後端能夠用MySQL原生協議與多個MySQL服務器通訊,在MyCat裏,咱們面向的是一個傳統的數據庫表,支持標準的SQL語句進行數據的操做,這樣一來,對前端業務系統來講,能夠大幅下降開發難度,提高開發速度。mysql
操做系統:CentOS / 7.1 (64bit)
JDK:1.8
MySQL:5.7
MyCat:1.6程序員
好比說咱們如今有個實際的業務上設計需求,要將student和grade表進行垂直劃分,分別存儲不一樣的database中;還須要將student水平拆分,也要3個不一樣database存分別儲。以下圖所示,MyCat能夠幫助實現這4個database的管理,而對於終端用戶來講,就像只操做student和grade兩張表,保證了中間件分庫分頁對程序員的透明性。
算法
首先,咱們確定須要建立4個database:beijing、shanghai、guangzhou、basic,並生成對應的表。能夠看出,student和grade表存在於不一樣的數據庫,並且student表中的數據,分散存儲在3個不一樣的數據庫中:sql
create database beijing; use beijing; create table student( id int primary key, name varchar(8) not null, grade int not null ); create database shanghai; use shanghai; create table student( id int primary key, name varchar(8) not null, grade int not null ); create database guangzhou; use guangzhou; create table student( id int primary key, name varchar(8) not null, grade int not null ); create database basic; use basic; create table grade( id int primary key, name varchar(8) not null );
比較簡單,下載Mycat-1.6-RELEASE,直接解壓縮便可。
爲了方便,將/mycat/bin
目錄添加到環境變量:
/etc/profile文件後增長設置export PATH=/data/mycat/bin:$PATH
讓profile當即生效:
# source /etc/profile
數據庫
編輯\mycat\conf\server.xml:後端
<user name="test"> <property name="password">test</property> <property name="schemas">TESTDB</property> </user>
這裏MyCat會幫助咱們生成一個虛擬的邏輯database,咱們命名爲TESTDB,並設置能夠訪問的用戶名和密碼,默認訪問的端口號8066,其實MyCat還會提供一個管理端口:9066,方便咱們對MyCat管理和監測,這個咱們之後有機會再說。服務器
編輯\mycat\conf\schema.xml:app
<mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"> <!-- 取模分片 --> <table name="student" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long" /> <table name="grade" primaryKey="id" dataNode="dn4"/> </schema> <!-- 申明節點對應的database --> <dataNode name="dn1" dataHost="localhost1" database="beijing" /> <dataNode name="dn2" dataHost="localhost1" database="shanghai" /> <dataNode name="dn3" dataHost="localhost1" database="guangzhou" /> <dataNode name="dn4" dataHost="localhost1" database="basic" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- 可讀寫的數據庫實例 --> <writeHost host="hostM1" url="localhost:3306" user="root" password="******"> </writeHost> </dataHost> </mycat:schema>
schema是比較重要的一塊配置,主要維護了虛擬庫與實際庫的映射關係:
能夠看到,虛擬的邏輯庫TESTDB中維護了2張表student和grade;
grade對應存儲在實際的數據庫節點dn4,也就是basic;
而student被拆分爲存儲在3個實際的數據庫節點,分別是beijing、shanghai、guangzhou,分片的算法取模,根據取模映射到不一樣的節點;
最後,咱們將實際的訪問地址、訪問權限配置完成,固然,這裏還能夠配置主從/讀寫分離配置,這塊不是本文討論的重點,咱們之後單獨說。
這時候,咱們敲入命令:# mycat start
,正常的話能夠啓動MyCat,輸入# mycat status
,能夠查看是否運行正常,若是運行中止,證實啓動有誤,能夠進入控制檯啓動,# mycat console
,進行調試。(有可能報內存錯誤,通常是因爲配置java虛擬機的默認大小的問題,咱們能夠根據命令行的提示,去wrapper.conf
中修改)
MyCat啓動後,咱們就能夠鏈接MyCat幫咱們生成的邏輯庫了:
# mysql -utest -ptest -h127.0.0.1 -P8066 -DTESTDB
接下來,咱們在邏輯庫中插入一下數據驗證一下:
insert into grade (id,name) values (1,'一年級'); insert into grade (id,name) values (2,'二年級'); insert into grade (id,name) values (3,'三年級'); insert into student (id,name,grade) values (1,'張三',2); insert into student (id,name,grade) values (2,'李四',1); insert into student (id,name,grade) values (3,'王五',3); insert into student (id,name,grade) values (4,'甲',3); insert into student (id,name,grade) values (5,'乙',2); insert into student (id,name,grade) values (6,'丙',1);
咱們插入了6條student記錄,這時應該根據不一樣的取模結果,存在不一樣的實際數據庫的student表中,因此咱們切換到實際數據庫:# mysql -uroot -ppassword
分別查看實際數據庫:
再看此時的邏輯數據庫:
邏輯數據庫,查詢grade和student兩張表,已經數據聚合,還能夠進行排序;
若是咱們須要將2張表進行關聯,也是能夠的:
/*!mycat:catlet=io.mycat.catlets.ShareJoin */select * from student s,grade g on s.grade=g.id where g.name='一年級';