1 MyCat 基本概念
从定义和分类来看,一个数据库的中间件,介于应用与数据库之间,是进行数据处理和交互的中间服务,可以视作为一个开源的分布式数据库系统。前端的用户可以把它看成一个数据库代理,用 MySql
客户端和命令行工具都可以访问,而其后端则是用 MySql
原生的协议与多个 MySql
服务之间进行通信。MyCat
的核心功能是分库分表,即将一个大表水平切分成 N
个小表,然后存放在后端的 MySql
数据当中,如下图:
MyCat
发展到目前的版本,已经不是一个单纯的MySql
代理了,它的后端支持MySql
,Oracle
,SqlServer
,DB2
等主流的数据库,也支持MongoDB
这种NoSql
数据库。
常见的典型的应用场景有:
- 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换;
- 分库分表,对于超过1000w的表进行分片,最大支持1000亿的数据;
- 多租户应用,每个应用一个数据库,应用只连接
MyCat
,程序本身不需要改造; - 代替
HBase
,分析大数据
1.1 逻辑库 Schema
在实际的开发中,开发人员不需要知道数据库中间件的存在,开发人员只需要有数据库的概念就可以了,所以数据库中间件可以被看做是一个或者多个数据库集群构成的逻辑库。
1.2 逻辑表 table
、分片表、非分片表、全局表
既然有逻辑库,那么就有逻辑表,对于应用系统来说,读写数据的表,就是逻辑表。而逻辑表中的数据,则是被水平切分后,分布在不同的分片库中。业务系统在进行用户数据的读写时,只需要操作逻辑表就可以了,后面的分片细节则由 MyCat
进行操作,这些对于业务开发人员来说时完全透明的。
有些表的数据量没有那么大,完全不需要进行分片,只在一个物理的数据库表中即可。凡是我们做的数据水平切分的表,我们把它叫做 分片表。而数据量比较小,没有进行分片的表,我们叫它 非分片表。
在真实的业务系统中,有些表的数据基本上很少变动,比如:订单状态表,查询订单时,需要把订单状态关联查出,如果订单表做了分片,分布在不同的数据库中,而订单状态表由于数据量小,没有做分片,那么我们查询的时候就要跨库关联查询订单状态,增加了不必要的麻烦,不如我们干脆把订单状态表 冗余 到所有的订单分片库中,这样关联查询就不需要跨库了。我们把这种通过数据冗余方式复制到所有的分片库中的表,叫做 全局表。
1.3 分片节点 dataNode
数据被切分后,一张大表被分到不同的分片数据库上面,每个分片表所在的数据库就叫做 分片节点。
1.4 节点主机 dataHost
数据切分后,每一个分片节点不一定都会占用一个真正的物理主机,会存在多个分片节点在同一个物理主机上的情况,这些分片节点所在的主机就叫做 节点主机。为了避免单节点并发数的限制,尽量将读写压力高的分片节点放在不同的节点主机上。
1.5 分片规则 rule
一个大表被拆分成多个分片表,就需要一定的规则,按照某种业务逻辑,将数据分到一个确定的分片当中,这个规则就叫做分片规则。数据切分选择合适的分片规则非常重要,这将影响到后的数据处理难度,结合业务。
1.6 全局序列号
数据切分以后,数据库表的中的 id
怎么办?原来在一张表的时候,采用 id
自增,但是数据分布到多个库怎么办?这样 id
就混乱了,我们也无法确定一条数据的唯一标识了。这时,我们需要借助外部的机制保证数据的唯一标识,这种保证数据唯一标识的机制,我们叫做 全局序列号。
2 MyCat 配置
官网 下载 MyCat,解压到对应的目录下即可。然后进入到配置目录下 /usr/local/mycat/conf
。
2.1 server.xml
配置文件
这里重要的是设置登录 MyCat
时的用户信息,如下
<mycat:server xmlns:mycat="http://io.mycat/">
.....
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB,TESTDB2</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
name
属性表示用户名defaultAccount
属性表示默认用户password
属性表示登录时的密码schemas
属性表示登录后该用户有哪些逻辑数据库权限readOnly
属性如果设置为true
表示该用户只能进行查询操作
配置完之后使用 Navicat
客户端连接 MyCat
与连接 MySql
无异,不过注意默认端口为 8066
。
2.2 schema.xml
配置文件
最核心的配置文件,例子:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
<table name="user" dataNode="dnBak1,dnBak2" rule="auto-sharding-long" />
</schema>
<dataNode name="dnBak1" dataHost="dhBak1" database="dbBak1" />
<dataNode name="dnBak2" dataHost="dhBak2" database="dbBak2" />
<dataHost name="dhBak1" 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.212.129:3306" user="root"
password="123456">
</writeHost>
</dataHost>
<dataHost name="dhBak2" 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.212.130:3306" user="root"
password="123456">
</writeHost>
</dataHost>
</mycat:schema>
配置节点主机 dataHost
<dataHost name="dhBak1" 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.212.129:3306" user="root"
password="123456">
<!-- can have multi read host(readHost) -->
</writeHost>
<!-- <writeHost host="hostM2" ... /> -->
</dataHost>
name
属性设置节点主机名称maxCon
属性设置最大连接数minCon
属性设置最小连接数balance
属性表示读的负载均衡,即一个读请求进来,这个请求语句是落在读库上还是写库上:- 数值为
0
表示不开启读分离,即所有读请求都落在写库writeHost
上 - 数值为
1
表示读随机分配,双主双从模式下有效(M1 => S1
,M2 => S2
,并且M1
与M2
互为主备),此时读操作会落在S1
,M1
,S2
- 数值为
2
表示读随机分配 - 数值为
3
表示读操作落在readHost
标签上
- 数值为
writeType
属性表示所有的写请求落在哪个写库上- 数值为
0
表示配置多个写库writeHost
时,所有的写请求会落在第一个写库writeHost
上,当第一个写库writeHost
挂掉后,写请求才会落到第二个写库上 - 数值为
1
表示所有的写请求会均匀的落在所有的写库上writeHost
上
- 数值为
dbType
:数据库类型writeHost
标签表示写库,其中的url
,user
,password
属性用于连接数据库,一个写库标签里可以包含多个读库readHost
标签
注意配置了
writeHost
和readHost
并没有真正地实现读写分离,Mycat
只是决定写库读库时使用哪个数据库,并不能实现数据的同步,数据库的数据同步需要数据库本身自行配置
配置数据节点 dataNode
<dataNode name="dnBak1" dataHost="dhBak1" database="dbBak1" />
name
属性指定数据节点的名称dataHost
属性指定节点主机dataHost
,即dataHost
标签的name
属性database
属性表示节点主机中引用的具体数据库名
配置逻辑库 schema
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
<table name="user" dataNode="dnBak1,dnBak2" rule="auto-sharding-long" />
</schema>
name
属性指定逻辑库的名称,在server.xml
配置文件中需要引用到checkSQLschema
属性表示查询sqlMaxLimit
属性表示检索的时候加上默认limit
语句,仅对分片表有效,如果用户在 SQL 语句中显示地声明了limit
语句,则该sqlMaxLimit
属性不生效table
标签定义逻辑表dataNode
属性设置节点分片rule
属性定义分片表的分片规则
分片规则的定义文件在 rule.xml
中,如 auto-sharding-long
,它的规则可以在 rule.xml
文件中查看到如下:
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
它表示使用 id
字段进行划分,划分规则 rang-long
可以在下方看到以下配置
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
再从配置目录下查看 autopartition-long.txt
,即可了解到当 id
数值介于 0-2000000
时,写进第一个 writeHost
数据库上,介于 2000001-4000000
时,写入第二个 writeHost
数据库上
2000001-4000000=1
0-2000000=0
启动 MyCat
./mycat start
修改配置文件后,除了重启 Mycat
,还有别的方法使配置文件重新生效,Mycat
的正常端口是 8066
,同时它还有一个管理端口 9066
,使用 navicat 通过访问 9066
端口可以进入管理,使用上面 server.xml
配置的用户名和密码登录即可,使用下面命令获取帮助文档。
show @@help
使用一下命令刷新:
reload @@config_all
注意,如果 MySql 的版本高于
8.0
,它的用户密码采用的是新的加密方式,而 MyCat 使用的旧版本的加密方式,所以如果在 MySql 创建用户时,没有显式地指定密码的加密方式为旧版本的加密方式,那么此时使用 MyCat 连接访问 MySql 就无法访问。