Mycat是什么?从定义和分类来看,它是一个开源的分布式数据库系统,是一个实现了MySQL协议的的Server,前端用户可以把 它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生(Native)协议与多个MySQL服务 器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储 在后端MySQL服务器里或者其他数据库里。 Mycat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、 PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看 来,无论是那种存储方式,在Mycat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业 务系统来说,可以大幅降低开发难度,提升开发速度,在测试阶段,可以将一个表定义为任何一种Mycat支持的存储方式,比如 MySQL的MyASIM表、内存表、或者MongoDB、LevelDB以及号称是世界上最快的内存数据库MemSQL上。试想一下,用户表 存放在MemSQL上,大量读频率远超过写频率的数据如订单的快照数据存放于InnoDB中,一些日志数据存放于MongoDB中, 而且还能把Oracle的表跟MySQL的表做关联查询,你是否有一种不能呼吸的感觉?而未来,还能通过Mycat自动将一些计算分析 后的数据灌入到Hadoop中,并能用Mycat+Storm/Spark Stream引擎做大规模数据分析,看到这里,你大概明白了,Mycat是 什么?Mycat就是BigSQL,Big Data On SQL Database。
对于DBA来说,可以这么理解Mycat:Mycat就是MySQL Server,而Mycat后面连接的MySQL Server,就好象是MySQL的存储引擎,如InnoDB,MyISAM等,因 此,Mycat本身并不存储数据,数据是在后端的MySQL上存储的,因此数据可靠性以及事务等都是MySQL保证的,简单的 说,Mycat就是MySQL最佳伴侣,它在一定程度上让MySQL拥有了能跟Oracle PK的能力。
对于软件工程师来说,可以这么理解Mycat: Mycat就是一个近似等于MySQL的数据库服务器,你可以用连接MySQL的方式去连接Mycat(除了端口不同,默认的Mycat端 口是8066而非MySQL的3306,因此需要在连接字符串上增加端口信息),大多数情况下,可以用你熟悉的对象映射框架使用 Mycat,但建议对于分片表,尽量使用基础的SQL语句,因为这样能达到最佳性能,特别是几千万甚至几百亿条记录的情况下。
对于架构师来说,可以这么理解Mycat: Mycat是一个强大的数据库中间件,不仅仅可以用作读写分离、以及分表分库、容灾备份,而且可以用于多租户应用开发、云平 台基础设施、让你的架构具备很强的适应性和灵活性,借助于即将发布的Mycat智能优化模块,系统的数据访问瓶颈和热点一目 了然,根据这些统计分析数据,你可以自动或手工调整后端存储,将不同的表映射到不同存储引擎上,而整个应用的代码一行也 不用改变。
当前是个大数据的时代,但究竟怎样规模的数据适合数据库系统呢?对此,国外有一个数据库领域的权威人士说了一个结论:千 亿以下的数据规模仍然是数据库领域的专长,而Hadoop等这种系统,更适合的是千亿以上的规模。所以,Mycat适合1000亿条 以下的单表规模,如果你的数据超过了这个规模,请投靠Mycat Plus吧!
Mycat原理
Mycat的原理并不复杂,复杂的是代码,如果代码也不复杂,那么早就成为一个传说了。 Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分 片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再 返回给用户。
上述图片里,Orders表被分为三个分片datanode(简称dn),这三个分片是分布在两台MySQL Server上(DataHost),即 datanode=database@datahost方式,因此你可以用一台到N台服务器来分片,分片规则为(sharding rule)典型的字符串枚举 分片规则,一个规则的定义是分片字段(sharding column)+分片函数(rule function),这里的分片字段为prov而分片函数为字符串枚举方式。
当Mycat收到一个SQL时,会先解析这个SQL,查找涉及到的表,然后看此表的定义,如果有分片规则,则获取到SQL里分片字 段的值,并匹配分片函数,得到该SQL对应的分片列表,然后将SQL发往这些分片去执行,最后收集和处理所有分片返回的结果 数据,并输出到客户端。以select * from Orders where prov=?语句为例,查到prov=wuhan,按照分片函数,wuhan返回 dn1,于是SQL就发给了MySQL1,去取DB1上的查询结果,并返回给用户。 如果上述SQL改为select * from Orders where prov in (‘wuhan’,‘beijing’),那么,SQL就会发给MySQL1与MySQL2去 执行,然后结果集合并后输出给用户。但通常业务中我们的SQL会有Order By 以及Limit翻页语法,此时就涉及到结果集在 Mycat端的二次处理,这部分的代码也比较复杂,而最复杂的则属两个表的Jion问题,为此,Mycat提出了创新性的ER分片、全 局表、HBT(Human Brain Tech)人工智能的Catlet、以及结合Storm/Spark引擎等十八般武艺的解决办法,从而成为目前业界 最强大的方案,这就是开源的力量!
Mycat发展到现在,适用的场景已经很丰富,而且不断有新用户给出新的创新性的方案,以下是几个典型的应用场景:
由于是基于海量数据,所以数据库版本尽量选择5.7及以上(我之前用5.5版本的时候会遇上前缀索引不够长等问题)
可以选择本机环境或者虚拟机环境,这里演示docker的Mysql环境部署
1. 拉取mysql:5.7镜像
docker pull mysql:5.7
2. 创建docker挂载文件夹(路径自己选择),方便之后自定义Mysql配置
mkdir -p /root/mysqletc/mysql(存储配置文件)
mkdir -p /root/mysqletc/data(存储数据部分)
3. 创建一个临时的msyql容器,复制Mysql容器中的配置
docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root mysql:5.7
4. 复制容器中的配置文件到指定的挂载位置
docker cp mysql:/etc/mysql /root/mysqletc
5. 停止并删除临时容器
docker stop mysql
docker rm mysql
6. 创建并启动mysql:5.7容器
docker run -d --name mysql -p 3306:3306 --restart always --privileged=true -v /root/mysqletc/mysql:/etc/mysql -v /root/mysqletc/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD="root" mysql:5.7
1. 允许远程访问
进入容器终端
docker exec -it Mysql容器ID /bin/bash
登录mysql
mysql -uroot -proot
允许远程访问
GRANT ALL PRIVILEGES ON *.* TO root@"%" IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
2.修改其他配置
找到挂载的目录(/root/mysqletc/mysql),可以看到mysql.cnf文件,修改这个文件,在结尾处添加如下内容
[mysqld]
max_allowed_packet=100M
max_connections=1000
max_user_connections=500
default-time_zone = '+8:00'
max_allowed_packet: 一次性允许导入的最大数据量
max_connections: 最大数据库连接数
max_user_connections: 最大用户连接数
default-time_zone: 数据库默认时区
其中连接数的修改是为了之后的Springboot项目可以连接上分好片的数据库,由于分片后的数据库数量比较多,因此可能会由于默认连接数不符合要求而导致的数据库操作超时问题
3.重新启动Mysql
docker restart mysql
下载地址:http://dl.mycat.io/
这里用windows版本来演示,下图是下载好的目录结构
进入conf文件夹
MYCAT常用配置文件为一下4个:
这里我们主要配置了连接信息:
<user name="root">
<property name="password">rootproperty>
<property name="schemas">yudachiproperty>
user>
这里的信息可以随便填
对应server.xml中连接信息中的schemas:
<schema name="yudachi" checkSQLschema="true" sqlMaxLimit="100">
这里的约束名最终会成为数据库的库名
定义数据节点:
<dataNode name="DNAP_0" dataHost="HOST0" database="info_0" />
定义主机节点:
<dataHost name="HOST0" maxCon="600" minCon="200" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()heartbeat>
<writeHost host="HOST0_M" url="192.168.202.200:3306" user="root" password="root"/>
dataHost>
定义表信息:
<table name="table1" dataNode="DNAP_$0-39" autoIncrement="true" primaryKey="id" rule="mod-long40"/>
该文件主要定义分表策略:
示例:
主键求余策略:
<function name="mod-long40" class="io.mycat.route.function.PartitionByMod">
<property name="count">40property>
function>
<tableRule name="mod-long40">
<rule>
<columns>idcolumns>
<algorithm>mod-long40algorithm>
rule>
tableRule>
该文件为全局自增主键配置对于table定义了autoIncrement=“true” primaryKey="id"的表,需要配置全局自增序号(注意全大写)。
表名=DNSQ
进入bin目录
双击运行startup_nowrap.bat
等待一段时候后显示启动成功
通过Navicat进行连接测试(端口号8066)
application.yml中设置
url:
jdbc:mysql://localhost:8066/yudachi-leadnews?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username:
root
password:
root
开发Mycat的分片策略,需要依赖Mycat-server-1.6-RELEASE.jar文件。在项目中以本地文件方式进行导入,操作步骤如下:
在项目下新建文件夹libs
拷贝Mycat-server-1.6-RELEASE.jar到libs中
在service-mycat/pom.xml中做以下依赖配置
<dependencies>
<dependency>
<groupId>com.mycatgroupId>
<artifactId>mycat-serverartifactId>
<version>1.0.0version>
<scope>systemscope>
<systemPath>${basedir}/libs/Mycat-server-1.6-RELEASE.jarsystemPath>
dependency>
dependencies>
批量插入且自动填充主键(集成Mycat之后,需要使用注解,以便实现注解的托管生成。)
/*!mycat:catlet=io.mycat.route.sequence.BatchInsertSequence */
<insert id="方法名">
/*!mycat:catlet=io.mycat.route.sequence.BatchInsertSequence */
insert into 表名 ( 字段1, 字段2, 字段3, 字段4, 字段5) values
<foreach item="item" collection="list" separator=",">
(#{值1}, #{item}, 值3, 值4, 值5)
foreach>
insert>
在实现该算法的项目下创建config文件夹和libs文件夹,将之前的Mycat-server-1.6-RELEASE.jar和4个主要的配置文件拷贝过来,目录结构如下:
其中自定义算法
public class YudachiBurstRuleAlgorithm extends AbstractPartitionAlgorithm implements RuleAlgorithm
要继承AbstractPartitionAlgorithm类, 实现RuleAlgorithm接口,然后实现其中的方法
//单值计算
public Integer calculate(String columnValue)
//范围计算
public Integer[] calculateRange(String beginValue, String endValue)
其中固定三个变量
// 单组数据容量
Long volume;
// 单组DN节点数量
Integer step;
// 分片模
Integer mod;
对应了Mycat常用配置文件的rule.xml文件中的自定义配置
<tableRule name="myburst">
<rule>
<columns>burstcolumns>
<algorithm>myburstalgorithm>
rule>
tableRule>
<function name="myburst" class="com.yudachi.YudachiBurstRuleAlgorithm">
<property name="volume">400000000property>
<property name="step">40property>
<property name="mod">40property>
function>
方法写完后进行打包操作
打包好的Jar包在target目录中
将该jar包复制到Mycat中的lib文件夹中
最后重启Mycat即可