MyCat
是一个功能强大的分布式数据库中间件,是一个实现了 MySQL
协议的 Server
,前端人员可以把它看做是一个数据库代理中间件,用 MySQL
客户端工具和命令行访问;而后端人员可以用 MySQL
原生协议与多个 MySQL
服务器通信,也可以用 JDBC
协议与大多数主流数据库服务器通信。可以用作 读写分离、分库分表(分片)、容灾备份、多租户应用开发、大数据基础设施,使底层数据架构具备很强的适应性和灵活性。
MyCat
的智能优化模块可以使系统的数据访问瓶颈和热点一目了然,并且可以将这些统计分析数据自动或手工调整后端存储,将不同的表映射到不同存储引擎上,而整个应用的代码可以一行也不用变。
Hbase
:用于分析大数据;环境:
MyCat 使用 Java 开发,因此,运行 MyCat ,一定要具备 Java 环境,配置 Java 运行环境这个比较容易,网上资料也很多,我就不详细介绍了。
Java 环境安装好之后,首先下载 MyCat:
$ wget http://dl.mycat.io/1.6.7.1/Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz
下载完成后,对下载文件进行解压。
$ tar -zxvf Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz
解压成功后,会出现一个 mycat
目录,进入到 mycat/conf
目录,对 mycat
进行配置,首先来配置 schema.xml
文件:
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="hellomycat" checkSQLschema="true" sqlMaxLimit="100">
<table />
schema>
<dataNode name="dataNode1" dataHost="dataHost1" database="hellomycat_1" />
<dataNode name="dataNode2" dataHost="dataHost2" database="hellomycat_2" />
<dataNode name="dataNode3" dataHost="dataHost3" database="hellomycat_3" />
<dataHost name="dataHost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="jdbc" switchType="-1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost
host="192.168.127.130"
url="jdbc:mysql://192.168.127.130:3306?useSSL=false&serverTimezone=UTC&characterEncoding=utf8"
user="root" password="123456">
writeHost>
dataHost>
<dataHost name="dataHost2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="jdbc" switchType="-1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost
host="192.168.127.130"
url="jdbc:mysql://192.168.127.130:3307?useSSL=false&serverTimezone=UTC&characterEncoding=utf8"
user="root" password="123456">
writeHost>
dataHost>
<dataHost name="dataHost3" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="jdbc" switchType="-1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost
host="192.168.127.130"
url="jdbc:mysql://192.168.127.130:3308?useSSL=false&serverTimezone=UTC&characterEncoding=utf8"
user="root" password="123456">
writeHost>
dataHost>
mycat:schema>
schema
中指定逻辑库的名字,逻辑库是指 MyCat
中的库,这个库不存储数据,数据存储在 MySQL
中的物理库中。dataNode
节点, dataNode
就是指数据库存储的位置dataNode
,dataNode
指定 dataHost
和物理库的名字。dataHost
则配置 MySQL
的主机和从机的位置,登录密码等。主机和从机都可以配置多个。配置完 schema.xml 后 ,接下来配置 server.xml。server.xml 中主要配置 MyCat 的登录用户名和密码,以及需要操作的逻辑库。
<mycat:server xmlns:mycat="http://io.mycat/">
<user name="root">
<property name="password">123456property>
<property name="schemas">hellomycatproperty>
<property name="usingDecrypt">0property>
user>
mycat:server>
配置完成后,接下来就可以启动 MyCat 了 。执行 MyCat 解压目录下的 bin 目录下的 mycat 命令,可以启动 MyCat
$ ./bin/mycat start
如果启动后,提示无法创建 mycat.pid
文件,就自己手动创建一个 mycat.pid
文件。启动成功之后,就可以在本地连接 MyCat
了,连接方式和 MySQL
一样,唯一的区别在于端口号不同。
在连接 MyCat
之前,先在 MySQL
物理库中创建 db1
、db2
以及 db3
三个数据库。
使用 SQLyog
连接 192.168.127.130:8066,也可以在 cmd
命令行登录 MyCat
:
$ mysql -u root -h 192.168.127.130 -P 8066 -p
登录成功后 ,在 MyCat
的窗口中,执行如下命令,创建表:
create table t_user (id integer primary key,username varchar(255))
执行成功后,我们会发现物理库中出现了相应的表。 接下来,手动往各个物理库的物理表中存储一条数据,然后在 MyCat 窗口中可以查询到三个库中的三个表中的数据。
整个过程不难,但是在第一次配置的过程中还是容易出错,因此我这里还是来说两句,出错了要如何定位。
一般来说,配置 MyCat 出错,问题可能发生在两个阶段。第一个阶段就是客户端连接 MyCat 出错,第二个阶段就是 MyCat 连接 MySQL 出错。
无论你是使用 SQLyog 还是 Navicat ,我们在连接数据库的过程中,都可以先测试连接,很多人卡在这一步。
如果在测试连接的时候就连接不通,说明是 MyCat 的问题,这个时候检查步骤如下:
这是第一种可能的问题,第二种问题就是测试连接没问题,但是测试完后,却连接不上。反映到 Navicat 上,就是测试连接没问题,测完之后,点击连接名要打开连接时,Navicat 就崩了,出现这个问题一般是 MyCat 在连接 MySQL 出问题了,这个时候就要去检查 schema.xml 文件中关于 MySQL 主机和从机的配置是否正确,数据库地址是否正确,用户名密码是否正确。
一般来说,对于应用而言,数据库中间件是透明的,应用并不需要去了解中间件复杂的运作过程,中间件对应用来说就是透明的,我们操作中间件就像操作一个普通的 MySQL 一样,这就是 MyCat 的优势之一。
但是我们毕竟操作的不是 MySQL ,而是 MyCat ,MyCat 中的数据库并不真正存储数据,数据还是存储在 MySQL 中,因此,我们可以将 MyCat 看作是一个或者多个数据库集群构成的逻辑库。
逻辑表又有几种不同的划分:
逻辑表:既然有逻辑库,那么就会有逻辑表。因为数据库分片之后,本来存储在一张表中的数据现在被分散到 N 张表中去了,但是在应用程序眼里,还是只有一张表,它也只操作这一张表,这张表并不真正存储数据,数据存储在 N 张物理表中,这个并不真正存储数据的表称之为逻辑表。
分片表:是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。
非分片表:一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。
ER 表:关系型数据库是基于实体关系模型之上,通过其描述了真实世界中事物与关系,Mycat 中的 ER 表即是来源于此。根据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组保证数据 join 不会跨库操作。
表分组是解决跨分片数据 join 的一种很好的思路,也是数据切分规划的重要一条规则。
全局表
一个真实的业务系统中,往往存在大量的类似字典表的表,这些表基本上很少变动,字典表具有以下几个特性:
变动不频繁
数据量总体变化不大
数据规模不大,很少有超过数十万条记录
对于这类的表,在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关联,就成了比较棘手的问题,所以 MyCat 中通过数据冗余来解决这类表的 join ,即所有的分片都有一份数据的拷贝,所有将字典表或者符合字典表特性的一些表定义为全局表。
数据冗余是解决跨分片数据 join 的一种很好的思路,也是数据切分规划的另外一条重要规则。
数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。
数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。
MyCat 提供的分片规则有如下几种:
指通过某种特定的条件,将存放在同一个数据库中的数据分散存放到多个数据库上面,以达到分散单台设备负载的效果。
根据切分规则的类型可以分为以下两种切分模式。
垂直切分:最大特点是规则简单,适合各业务之间的的耦合度非常低、相互影响小、业务逻辑非常清晰的系统。在这种系统中,可以很容易 将不同业务模块所使用的的表切到不同的数据库中。
水平切分:相对来说复杂一些,因为要 将同一个表中的不同数据切分到不同的数据库中,后期的数据维护也更为复杂一些。
一个数据库由很多表构成,每个表对应着不同的业务,垂直切分就是按照业务将表进行分类,从而分布到不同的数据库上面,这样也就将压力分担到不同的数据库上,如图。
一个架构设计好的系统其总体功能通常是由多个功能模块所组成的,而每一个功能模块的数据对应到数据库中就是一个或多个表。而在架构设计中,各个功能模块相互之间的交互点越少和越统一,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好,这样的系统也就越容易实现垂直切分。
但是往往系统中有些表难以做到完全的独立,存在跨库 join
的情况,对于这类分库,可以共用一个数据源,业务之间通过接口来调用。
优点:规则明确、业务清晰、更易于整合和扩展、维护简单。
缺点:部分业务表无法 join
,需要通过业务接口方式解决,提高系统复杂度;各业务存在单库性能瓶颈,不易于数据扩展和性能提高;事务处理复杂问题。
由于垂直切分是将表按照业务分类切分到不同的单库中,所有导致某些业务表过于庞大,存在单库读写与存储瓶颈,则需要水平切分来解决。
水平切分不是将表按照业务分类,而是按照某个字段的某种规则分散到多个库中,每个表中包含一部分数据,如图。
拆分数据需要定义分片规则,拆分的第一原则是找到 拆分维度。比如:从会员的角度来分析,需要查询会员某天某月某个订单,那么就需要按照日期来拆分,不同的数据按照会员 ID 做分组。
优点:拆分规则抽象好;不存在单库数据瓶颈问题;提高系统稳定性和负载能力。
缺点:事务一致性难以解决;数据扩展和维护的难度极大;跨库 join 性能差。
这里向大家简单介绍 5 种规则。
有一些表,数据量不大,也不怎么修改,主要是查询操作,例如系统配置表,这一类表我们可以使用 global 这种分片规则。global 的特点是,该表会在所有的库中都创建,而且每一个库中都保存了该表的完整数据。具体配置方式,就是在 schema.xml 的 table 节点中添加一个 type 属性,值为 global。配置完成后,重启 mycat
$ ./bin/mycat restart
重启完成后,要删除之前已经创建的 t_user
表,然后重新创建表,创建完成后,向表中插入数据,可以看到,db1、db2 以及 db3 中都有数据了。
总结:global 适合于 数据量不大、以查询为主、增删改较少的表。
sharding-by-intfile 这个是枚举分片,就是在数据表中专门设计一个字段,以后根据这个字段的值来决定数据插入到哪个 dataNode 上。
**注意:**在配置 sharding-by-intfile 规则时,一定要删除 schema 节点中的 type=“global” ,否则配置不会生效。
配置完成后,还需要指定枚举的数据。枚举的数据可以在 rule.xml 中查看。
在 rule.xml 文件中,首先找到 tableRule 的名字为 sharding-by-intfile 的节点,这个节点中定义了两个属性,一个是 columns 表示一会在数据表中定义的枚举列的名字(数据表中一会需要创建一个名为 sharding_id 的列,这个列的值决定了该条数据保存在哪个数据库实例中),这个名字可以自定义;另外一个属性叫做 algorithm ,这是指 sharding-by-intfile 所对应的算法名称。根据这个名称,可以找到具体的算法:
还是在 rule.xml 文件中,我们找到了 hash-int ,class 表示这个算法对应的 Java 类的路径。第一个属性 mapFile 表示相关的配置文件,从这个文件名可以看出,这个文件 就在 conf 目录下。
打开 conf 目录下的 partition-hash-int.txt 文件,内容如下:
0=0
1=1
2=2
前面的数字表示枚举的值 ,后面的数字表示 dataNode 的下标,所以前面的数字可以自定义,后面的数字不能随意定义。
配置完成后,重启 MyCat ,然后进行测试:
drop table if exists t_user;
create table t_user (id integer primary key,username varchar(255),sharding_id integer);
insert into t_user(id,username,sharding_id) values(1,'www.antoniopeng.com',0);
insert into t_user(id,username,sharding_id) values(1,'www.antoniopeng.com',1);
insert into t_user(id,username,sharding_id) values(1,'www.antoniopeng.com',2);
select * from t_user;
执行完后,sharding_id 对应值分别为 0 、1 、2 的记录分别插入到 db1 、db2 以及 db3 中。
auto-sharding-long 表示按照既定的范围去存储数据。就是提前规划好某个字段的值在某个范围时,相应的记录存到某个 dataNode 中。
配置方式,首先修改 schema 节点中的 rule 属性值为 auto-sharding-long,然后去 rule.xml 中查看对应的算法了规则相关的配置:
可以看到,默认是按照 id 的范围来划分数据的存储位置的,对应的算法就是 rang-long 。
继续查看,可以找到算法对应的类,以及相关的配置文件,这个配置文件也在 conf 目录下,打开该文件:
如上配置,表示 当 id 的取值在 0-5之间时,将数据存储到 db1 中,当 id 在 5-10 之间时,存储到 db2 中,当 id 的取值在 10-1500W 之间时,存储到 db3 中。
配置完成后,重启 MyCat ,测试即可。
取模:根据表中的某一个字段,做取模操作。根据取模的结果将记录存放在不同的 dataNode 上。这种方式不需要再添加额外字段。 schema 节点中的 rule 属性值为 mod-long,然后去 rule.xml 中配置一下 dataNode 的个数。
可以看到,取模的字段是 id ,取模的算法名称是 mod-long ,再看具体的算法:
在具体的算法中,配置了 dataNode 的个数为 3。然后保存退出,重启 MyCat,进行测试即可。
前面介绍的几种方式,都存在一个问题,如果数据库要扩容,之前配置会失效,可能会出现数据库查询紊乱。因此我们要引入一致性 hash 这样一种分片规则,可以解决这个问题。具体配置和前面一样,schema 节点中的 rule 属性值为 sharding-by-murmur。
另外需要注意,在 rule.xml 中修改默认 dataNode 的数量:
修改完后,重启 MyCat ,进行测试。
更多干货请移步:https://antoniopeng.com