Mycat 是数据库中间件,就是介于数据库与应用之间,进行数据处理与交互的中间服 务。由于前面讲的对数据进行分片处理之后,从原有的一个库,被切分为多个分片数据库,所有的分片数据库集 群构成了整个完整的数据库存储。
如下图:
如上图所表示,数据被分到多个分片数据库后,应用如果需要读取数据,就要需要处理多个数据源的数据。
如果没有数据库中间件,那么应用将直接面对分片集群,数据源切换、事务处理、数据聚合都需要应用直接处 理,原本该是专注于业务的应用,将会花大量的工作来处理分片后的问题,最重要的是每个应用处理将是完全的 重复造轮子。
所以有了数据库中间件,应用只需要集中与业务处理,大量的通用的数据聚合,事务,数据源切换都由中间 件来处理,中间件的性能与处理能力将直接决定应用的读写性能,所以一款好的数据库中间件至关重要。
第一部MyCat的环境搭建。
首先去官网下载MyCat,官网地址为:dl.mycat.io
注意必须下载发行版,也就是说带有RELEASE字眼的就是发行版,BETA是测试版。选择windows版本来学习即可。
我们主要关注的是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"> <!-- auto sharding by id (long) --> <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" /> <!-- global table is auto cloned to all defined data nodes ,so can join with any table whose sharding node is in the same data node --> <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" /> <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" /> <!-- random sharding using mod sharind rule --> <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long" /> <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global" needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3" rule="mod-long" /> --> <table name="employee" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile" /> <table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile"> <childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id"> <childTable name="order_items" joinKey="order_id" parentKey="id" /> </childTable> <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" /> </table> <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate" /> --> </schema> <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743" /> --> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataNode name="dn2" dataHost="localhost1" database="db2" /> <dataNode name="dn3" dataHost="localhost1" database="db3" /> <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" /> <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" /> <dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" /> <dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> --> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> </writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" /> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost> <!-- <dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc"> <heartbeat> </heartbeat> <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost> </dataHost> <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat> <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql> <writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost> <dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost> <dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc"> <heartbeat> </heartbeat> <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> --> <!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql" dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost> </dataHost> --> </mycat:schema>
schema 标签用于定义 MyCat 实例中的逻辑库,MyCat 可以有多个逻辑库,每个逻辑库都有自己的相关配 置。可以使用 schema 标签来划分这些不同的逻辑库。 如果不配置 schema 标签,所有的表配置,会属于同一个默认的逻辑库。
对于我们开发人员来说,我们知道连接到mycat的逻辑库,后面拖着多少个MySQL我们不管的,我们只需要连接到MyCat这个逻辑库,对于后面的分库分表,MyCat给我们屏蔽了分库分表的复杂性。
table 标签定义了 MyCat 中的逻辑表,所有需要拆分的表都需要在这个标签中定义。
table标签里面的子标签childTabel表示这个表跟父table分在一起,不会被拆散,也就是前面所说的分库分表之前,要考虑好表的关联,不然否则就面临跨库Join连接问题。
如下代码:
<table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile"> <childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id"> <childTable name="order_items" joinKey="order_id" parentKey="id" /> </childTable> <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" /> </table>
table中的type属性的global表示该表为全局表。即前面所提到每一个节点可以读到这个表,这对是否在分库分表中的join查询很关键。而且这属性表示不会进行分片,即全局表使用,每个节点都有。代码如下:
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
table中的dataNode属性表示你要分片,要分到那几个节点上去,rule代表着分库分表的规则。他的分片分表规则在rule.xml文件中,你可以在Table标签的rule属性设置复合
自己的分片分表规则,都在rule.xml中对应着如下图:
<dataNode>标签,标签中的name属性表示节点的名字。dataHost属性表示对应MySQL的数据库连接,database属性表示Mysql数据库名,代码如下:
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost>标签节点表示对应MySQL的数据库连接对应配置,什么最大连接数,最小连接数之类的属性。
<dataHost>标签中的子标签<hearbeat>表示存活检测,
<dataHost>标签中的子标签<writeHost>和<readHost>表示MySQL中的读写分离,而<writeHost>子标签中还有<readHost>子标签,表示写操作的数据库还要承担一部分读库的压力。
代码如下:
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> </writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" /> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost>
下面进行读写分离的演示:
第一步先注释schma里面的配置如下图:
接着在修改<dataNode>,<dataHost>节点信息,详细信息在图中说明。如下图:
接着再还要修改mycat中server.xml文件,我这里没有使用zookeeper所以要把zookeeper协调切换关闭。因为我们只是在本地玩,如下图:
接着在继续修改server.xml文件。如下图:
接着就是启动了,启动之前要进行环境变量设置如下:
接着就是设置一起启动参数了,在startup_newrap.bat文件中修改如下图:
接着就是启动了,如下:
接着就是用图形化工具连接MyCat了。如下图:
接着自己在图形化界面中修改数据库,这里就不演示了。如下:
接着mycat进行分库分表演示:
注意一定要在每一个mysql中建立好tabel标签对应的travelrecord表,而表中必须要有id这属性,
如下图:
注意一定要在每一个mysql中建立好tabel标签对应的travelrecord表,而表中必须要有id这属性,因为上面的分库分表策略是根据id分的,在rule.xml中找到分表策略如下:
在根据rang-long在rule.xml找到对应的function,如下图:
在找到autoparitition-long.txt文件,看到如下分库分表了,如下图:
然后在分别对应修改dataNode和dataHost标签,如下图:
最后进行分库分表测试
比如490M=4900000分到第0个节点,在mycat总设置,如下图:
接着去查看第0个节点会有一条数据分到这里,其他节点没有。
如果使用上面的分库分表策略不能超过范autoparitition-long.txt里面配置的范围的。
其他的分配策略,还可以用CRC32slot策略类似于redis集群中的Slot,如下:
还可以用rang-mod求模来分,如下:
然后找partition-range-mod.txt,可以具体,如下:
其他就不演示了。