mycat 使用说明
Mycat是什么
MyCat是一个数据库中间件,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。
MyCat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度。
我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心作用。
Mycat原理
Mycat的原理中最重要的一个动词是"拦截",它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户
相关概念
- schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
- table:表,即物理数据库中存储的某一张表,与传统数据库不同,这里的表格需要声明其所存储的逻辑数据节点DataNode,这是通过表格的分片规则定义来实现的,table可以定义其所属的"子表(childTable)",子表的分片依赖于与"父表"的具体分片地址,简单的说,就是属于父表里某一条记录A的子表的所有记录都与A存储在同一个分片上。
分片规则:是一个字段与函数的捆绑定义,根据这个字段的取值来返回所在存储的分片(DataNode)的序号,每个表格可以定义一个分片规则,分片规则可以灵活扩展,默认提供了基于数字的分片规则,字符串的分片规则等。 - dataNode: MyCAT的逻辑数据节点,是存放table的具体物理节点,也称之为分片节点,通过DataSource来关联到后端某个具体数据库上,一般来说,为了高可用性,每个DataNode都设置两个DataSource,一主一从,当主节点宕机,系统自动切换到从节点。
- dataHost:定义某个物理库的访问地址,用于捆绑到dataNode上。
安装mycat
http://dl.mycat.org.cn/ mycat下载地址
我使用的是mycat Version 1.6.7.5-release(建议高于1.6-release,否则单库多表会有问题)
GitUrl https://github.com/MyCATApache/Mycat-Server.git
MyCatSite http://www.mycat.org.cn
. mycat依赖java环境
- jdk相关安装(必须)本机windows配置JAVA_HOME环境变量这些即可
mkdir /usr/java
tar xf jdk-8u151-linux-x64.tar.gz
mv jdk1.8.0_151/ /usr/java/jdk1.8
echo ‘export JAVA_HOME=/usr/java/jdk1.8
export CLASSPATH= C L A S S P A T H : CLASSPATH: CLASSPATH:JAVA_HOME/lib: J A V A H O M E / l i b / t o o l s . j a r e x p o r t P A T H = JAVA_HOME/lib/tools.jarexport PATH= JAVAHOME/lib/tools.jarexportPATH=JAVA_HOME/bin: J A V A H O M E / j r e / b i n : JAVA_HOME/jre/bin: JAVAHOME/jre/bin:PATH’ >>/etc/profile
source /etc/profile
java -version
… 修改配置
MyCAT主要通过三个配置文件来定义逻辑库和相关配置:
schema.xml中定义逻辑库,表、分片节点等内容;
conf/rule.xml中定义分片规则;
server.xml中定义用户以及系统相关变量,如端口等。
schema.xml:
<schema name="TESTMYDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<!-- <table name="travelrecord" dataNode="dn1,dn2" rule="auto-sharding-long" /> -->
<table name="user" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long" />
<!-- 单库多表配置 实体数据库表 test_user 逻辑表 test_user1_6(6个表) rule分片规则这个看具体业务适合 -->
<table name="test_user" subTables="test_user$1-6" primaryKey="id" dataNode="dn1" rule="mod-long" autoIncrement="true" fetchStoreNodeByJdbc="true">
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<!-- 单库只配置一个 dataHost配置连接 database数据库名 -->
<dataNode name="dn1" dataHost="localhost" database="testdb" />
<dataNode name="dn2" dataHost="remotehost" database="testdb" />
<dataHost name="localhost" 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="root">
</writeHost>
</dataHost>
<dataHost name="remotehost" 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.xx.xx:3306" user="root" password="root"></writeHost>
</dataHost>
我们在schema.xml中使用了mod-long(此规则为对分片字段求模运算)规则,由于是两个节点来提供服务,这里我就将其设置为均分:比如插入时,一个一库,轮流进行
mod-long:比如count=3,则user_id = 1、2、3
假设有3个分片数据库(ds1,ds2,ds3 )
规则: 第1个分片数据库取模=0,第2个=1,第3个=2
这里rule.xml 配置2个库
<function name="mod-long" lass="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
server.xml中配置逻辑数据库的账号密码
<user name="user">
<property name="password">123456</property>
<property name="schemas">TESTMYDB</property>
<property name="readOnly">false</property>
</user>
schema.xml中name 对应账号中配置的schemas数据库名
启动程序
①控制台启动 :去 mycat/bin 目录下执行 ./mycat console
②后台启动 :去 mycat/bin目录下 ./mycat start
为了能第一时间看到启动日志,方便定位问题,我们先选择①控制台启动,如没报错再选择用②启动
D:\tool\mycat\bin>mycat restart
wrapper | Stopping the Mycat-server service...
wrapper | Mycat-server stopped.
wrapper | Starting the Mycat-server service...
wrapper | Mycat-server started.
常用操作:
.. linux
* cd mycat/bin
./mycat start
./mycat status
./mycat start 启动
./mycat stop 停止
./mycat console 前台运行
./mycat install 添加到系统自动启动(暂未实现)
./mycat remove 取消随系统自动启动(暂未实现)
./mycat restart 重启服务
./mycat pause 暂停
./mycat status 查看启动状态
* CMD
mycat install
mycat start
mycat status
Mycat的默认端口是:8066,我使用的navcat连接数据库,权限不足请使用管理员运行后再操作
测试mycat
上述我配置了本地localhost(localhost)和一个测试数据库(remotehost)
可使用对应的账号密码连接查看对应的表数据,只在对应数据库中存在各自的数据,
使用上面配置的mycat逻辑数据库账号密码(端口8066),mysql一般默认3066
查询会得到两个库的总数据:
SELECT * FROM user
;
localhost:2 ;remotehost:5 ,mycat:7
- 单库多表只需要将schema.xml中 配置subTables,例如:subTables=“user$0-3”,在配置对应的规则即可。
分库需要增加配置,对应配置例如:
<table name="test_user" subTables="test_user$1-6" primaryKey="id" dataNode="dn1" rule="mod-long" autoIncrement="true" fetchStoreNodeByJdbc="true"></table>
<dataNode name="dn1" dataHost="localhost1" database="testdb1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="jdbc:mysql://localhost:3306" user="root" password="root">
</writeHost>
</dataHost>
在rule.xml对应的规则配置tableRule-function:property->count值
例如在上述schema中配置的规则是mod-long,在rule中可以配置:
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">6</property>
</function>
- 多库多表配置
server.xml
<user name="root">
......
<property name="schemas">TESTDB,BBSDB</property> #指定多个逻辑库
</user>
schema.xml
<schema name="BBSDB" checkSQLschema="false" sqlMaxLimit="100"> #第一个逻辑库
<table name="company2" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" /> #指定逻辑表名company2
<table name="employee2" primaryKey="ID" dataNode="dn1,dn2,dn3" rule="sharding-by-intfile" /> #指定逻辑表名employee2
</schema>
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"> #第二个逻辑库
......
</schema>
ps: 注意:
分片查询条件最好用between代替>=,查看他的源码来只有条件是=,in,between才会进行分片查询。
Mycat使用DruidParser进行sql解析扫描condition寻找含有分片字段的查询条件,处理where语句里的分片字段进而路由到指定的物理库进行查询时,只会处理BETWEEN…AND、= 和 IN 这三种情况,只有分片字段的查询条件是这三种情况的时候才会路由的指定的Range
if(operator.equals("between")) {
RangeValue rv = new RangeValue(values.get(0), values.get(1), RangeValue.EE);
routeCalculateUnit.addShardingExpr(tableName.toUpperCase(), columnName, rv);
} else if(operator.equals("=") || operator.toLowerCase().equals("in")){ //只处理=号和in操作符,其他忽略
routeCalculateUnit.addShardingExpr(tableName.toUpperCase(), columnName, values.toArray());
}
常见问题说明: mysql主从库实现主从同步和读写分离的研究