目录
配置详解
server.xml
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property>
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">1</property>
<property name="useGlobleTableCheck">0</property>
<!-- 全局ID生成方式。(0:为本地文件方式,1:为数据库方式;2:为时间戳序列方式;3:为ZK生成ID;4:为ZK递增ID生成。 -->
<property name="sequnceHandlerType">2</property>
<property name="subqueryRelationshipCheck">false</property>
<property name="processorBufferPoolType">0</property>
<property name="handleDistributedTransactions">0</property>
<property name="useOffHeapForMerge">1</property>
<property name="memoryPageSize">1m</property>
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<property name="systemReserveMemorySize">389m</property>
<property name="useZKSwitch">false</property>
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<!-- user 用户配置节点 -->
<user name="root">
<property name="password">123456</property>
<property name="schemas">666888HGfeDuAM9FtWcrsZBGkiga,111222HGfeDuAM9FtWcrsZBGkiga,1112223LR6zbpYi6eLoEFAkXjazH,667128moYWU9vY6aLtcH6EezNWR,667118moYWU9vY6aLtcH6EezNWR,667108BnaL7HrFBqYVsLude4MNVd,667098BnaL7HrFBqYVsLude4MNVd,111222BnaL7HrFBqYVsLude4MNVd,666888NgDLgoKgHPvy56mqDQobu5,111222NgDLgoKgHPvy56mqDQobu5,667078BnaL7HrFBqYVsLude4MNVd,666888BnaL7HrFBqYVsLude4MNVd,6670383LR6zbpYi6eLoEFAkXjazH,6668883LR6zbpYi6eLoEFAkXjazH</property>
</user>
<!-- 对用户的 schema以及表进行精细化的DML权限控制 -->
<privileges check="false">
</privileges>
<!-- check 表示是否开启DML权限检查。默认是关闭。server.dtd文件中 <!ELEMENT privileges (schema)*> 说明可以有多个schema的配置。 -->
<!-- dml 顺序说明:insert,update,select,delete -->
<schema name="db1" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
<!-- db1的权限是update,select。 -->
<!-- tb01的权限是啥都不能干。 -->
<!-- tb02的权限是insert,update,select,delete。 -->
<!-- 其他表默认是udpate,select。 -->
<!-- 防火墙的设置,也就是在网络层对请求的地址进行限制,主要是从安全角度来保证Mycat不被匿名IP进行访问 -->
<!-- 只要设置了白名单,表示开启了防火墙,只有白名单的连接才可以进行连接。 -->
<firewall>
<whitehost>
<host host="127.0.0.1" user="mycat"/>
<host host="127.0.0.2" user="mycat"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
</mycat:server>
schemal.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应 -->
<!-- checkSQLschema 数据库前缀相关设置,当该值为true时,例如我们执行语句select * from TESTDB.company 。mycat会把语句修改为 select * from company 去掉TESTDB。 -->
<!--sqlMaxLimit当该值设置为某个数值时,每条执行的sql语句,如果没有加上limit语句,Mycat会自动加上对应的值。不写的话,默认返回所有的值。 需要注意的是,如果运行的schema为非拆分库的,那么该属性不会生效。需要自己sql语句加limit。 -->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名,具体规则下文rule详细介绍
type 该属性定义了逻辑表的类型,目前逻辑表只有全局表和普通表。全局表: global 普通表:无 -->
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
rule="mod-long" />
<table name="employee" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile" />
<!-- childTable 标签用于定义 E-R 分片的子表。通过标签上的属性与父表进行关联。
name 子表的名称
joinKey 子表中字段的名称
parentKey 父表中字段名称
primaryKey 同Table
needAddLimit 同Table -->
<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>
</schema>
<!--datanode标签定义了mycat中的数据节点,也就是我们所说的数据分片。一个datanode标签就是一个独立的数据分片。
例子中的表述的意思为,使用名字为localhost1数据库实例上的db1物理数据库,这就组成一个数据分片,最后我们用dn1来标示这个分片。
--name 定义数据节点的名字,这个名字需要唯一。我们在table标签上用这个名字来建立表与分片对应的关系
--dataHost 用于定义该分片属于哪个数据库实例,属性与datahost标签上定义的name对应
--database 用于定义该分片属于数据库实例上 的具体库。-->
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" />
<!--dataHost标签直接定义了具体数据库实例,读写分离配置和心跳语句。
--name 唯一标示dataHost标签,供上层使用
--maxCon 指定每个读写实例连接池的最大连接。
--minCon 指定每个读写实例连接池的最小连接,初始化连接池的大小
--balance 负载均称类型
balance="0":不开启读写分离机制,所有读操作都发送到当前可用的writeHost上
balance="1":全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1-S1,M2-S2 并且M1 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
balance="2":所有读操作都随机的在writeHost、readHost上分发
balance="3":所有读请求随机的分发到writeHst对应的readHost执行,writeHost不负担读写压力。(1.4之后版本有)
--writeType 负载均衡类型。
writeType="0", 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties .
writeType="1",所有写操作都随机的发送到配置的 writeHost。1.5以后版本废弃不推荐。
--switchType -1不自动切换 1 默认值 自动切换 -->
<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="123456">
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
</writeHost>
<writeHost host="hostS1" 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>
rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<!-- --name 属性指定唯一的名字,用于标识不同的表规则。 内嵌的 rule 标签则指定对物理表中的哪一列进行拆分和使用什么路由算法。 -->
<!-- --columns 内指定要拆分的列名字。 -->
<!-- --algorithm 使用 function 标签中的 name 属性。连接表规则和具体路由算法。当然,多个表规则可以连接到 同一个路由算法上。table 标签内使用。让逻辑表使用这个规则进行分片。 -->
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="murmur"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
</function>
<!-- --name 指定算法的名字。 -->
<!-- --class 制定路由算法具体的类名字。 -->
<!-- --property 为具体算法需要用到的一些属性。 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
</mycat:rule>
mycat实战
单库大表拆分
一个逻辑库中的一个逻辑表company对应一个物理库DB中的三个物理表company、company2、company3
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="company" subTables="company$1-3" dataNode="dn1" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="DB" />
<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:3316" user="root"
password="111111" />
</dataHost>
使用的分片规则是mod-long,取模分片;所以在mycat库中插入六条数据,会分配到DB库的三个company表中,select *查询时会到三个库物理表中查询,通过expain查看执行情况:
如果where条件是id,会路由到相应的company表;如果是name,会路由到三个conpany表查询。
跨库分表
相当于一个逻辑库中一个逻辑表对应三个物理库中的物理表
schema.xml
三个物理库,db1、db2、db3,每个库都有record表,配置三个节点,映射到三个物理库的三个物理表。
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="record" dataNode="dn1,dn2,dn3" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" 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>
<!--真实数据库服务-->
<writeHost host="hostM1" url="localhost:3316" user="root"
password="111111" />
</dataHost>
分片规则也是mod-long取模分片,插入三条数据会分别存入三个库中的record表,实现跨库分片。
读写分离
读写分离是在mysql主从复制的基础上实现的,mysql配置主从同步后,mycat配置主库写数据,从库读数据,实现读写分离。
第一种方式
schema.xml
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode=""dn1></schema>
<dataNode name="dn1" dataHost="localhost1" database="DB" />
<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="192.168.22.11:3316" user="root" password="111111" >
<readHost host="hostS1" url="192.168.22.12:3316" user="root" password="222222"
</writeHost>
</dataHost>
写数据会写到192.168.22.11数据库上,读数据会从192.168.22.12数据库上请求。但是这种方式,如果hostM1挂了,hostS1也就不起作用了,即读写都不可操作了
第二种方式
还有一种读写分离的配置如下:
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode=""dn1></schema>
<dataNode name="dn1" dataHost="localhost1" database="DB" />
<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="192.168.22.11:3316" user="root" password="111111" ></writeHost>
<writeHost host="hostS1" url="192.168.22.12:3316" user="root" password="222222" ></writeHost>
</dataHost>
配置两个writehost节点,这样依然是读写分离,但第一个11节点挂了,mycat的心跳检测,会自动切换可用的12节点上继续执行DML语句。