先给你们介绍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='一年级';