本文作者:蓝雄威,叩丁狼高级讲师。原创文章,转载请注明出处。
在上一篇文章中,我们基于CentOS7实现了MySQL的主从复制,我们需要把DML操作放在MySQL的主节点执行,需要把DQL操作放在MySQL的从节点执行.那在应用程序中我们怎么控制这个逻辑呢?
下面是一种可行的方案:
1.在项目中配置两个数据源(一主一从),分别是A(主)和B(从)。
2.在程序中判断是不是select操作,如果是就把数据源更换成B,如果不是select操作就更换成A,这样就可以实现程序中的读写分离了.
3.关于步骤2的更换数据源,Spring中是提供了AbstarctRoutingDataSource
这个类在程序中实现数据源的切换的.
这种方案可行是可行,但是在应用程序端需要写挺多代码的,而且这些属于非业务层面的东西,写在项目中对项目来说是代码侵入了.
所以对于读写分离我们可以使用Mycat数据库中间件来完成.
关于MyCat的详细简介,同学们可以去Mycat官网.下载Mycat权威指南.pdf
来看,文章中的前世今生写得幽默有趣,挺有意思的,从描述来看都感觉看的不是本技术书,而是本小说哈.在这里我简单的介绍一下Mycat:
2008年阿里开源了一款数据库中间件Amoeba,随着业务的增长,这块产品不能支持目前已有的业务.阿里又开源了Cobar这款中间件,这款产品在阿里内部得到了很广泛的应用.(应用在了3000多台服务器,每天超过10亿次的数据库访问),当时一开源就得到了开发者和运维人员的追捧. 开源之后,阿里就没有对这款产品维护了,这款产品在生产环境中还是存在挺多问题的.在这样的场景下MyCat诞生了,2013年MyCat社区在Cobar的基础上进行了很大的改造和升级.
优势这个我就从官网上给同学们摘抄下来了:
基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得MYCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,我们能看到更远。业界优秀的开源项目和创新思路被广泛融入到MYCAT的基因中,使得MYCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。
MYCAT背后有一支强大的技术团队,其参与者都是5年以上软件工程师、架构师、DBA等,优秀的技术团队保证了MYCAT的产品质量。
MYCAT并不依托于任何一个商业公司,因此不像某些开源项目,将一些重要的特性封闭在其商业产品中,使得开源项目成了一个摆设。
目前也有挺多公司在生产环境上使用Mycat的,使用案例,所以来说还是一款很不错,很稳定的产品.
主要作为分布式数据库系统的中间层
1.可以实现数据库的读写分离
2.支持负载均衡
3.支持后端MySQL高可用
4.数据库的垂直拆分
5.数据库水平拆分
关于Mycat如何实现数据库的分库分表,我在之前的简书中已经写了案例,数据库中间件Mycat+SpringBoot完成分库分表.
从上图可以看到,我们应用程序不是直接连接真实数据库的的,而是连接Mycat的.所以在Mycat的配置文件中我们就需要去定义逻辑库
、逻辑表
和真实库
、真实表
的映射关系
0.我们Mycat的安装是基于CentOS7环境来安装的,所以同学们先把基础环境搭建好哈.
1.Mycat是基于Java开发的一款中间件产品,所以要使用Mycat前需要把JDK的环境装上.JDK1.8安装包.
2.下载好jdk1.8安装包后,通过工具上传到服务器上.我们通常会把文件上传到/usr/local/software
目录下
3.然后使用解压命令解压到/usr/local
目录下
tar -zxvf jdk-8u161-linux-x64.tar.gz -C /usr/local
但是名字有些长,不方便我们设置环境变量,所以我们可以对这个文件夹重命名
mv jdk1.8.0_161/ jdk1.8
vi /etc/profile
export JAVA_HOME=/usr/local/jdk1.8
export PATH=.:$JAVA_HOME/bin:$PATH
编辑后如下图所示:
然后保存退出即可.
然后需要通过这个命令来重新加载配置文件:
source /etc/profile
设置好之后,通过这个命令查看环境变量是否配置好了.
java -version
###07安装Mycat
我们这次使用的是Mycat-server-1.6.7版本,下载好之后上传到服务器上.
然后使用命令进行解压
tar -zxvf Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz -C /usr/local/
这样我们就已经装好Mycat了,下一步就需要去配置Mycat的配置文件了.
###08配置读写分离
我们可以先看看Mycat的文件目录结构
bin目录
:存放Mycat运行的脚本
conf目录
:存放Mycat的配置文件
logs目录
:存放Mycat启动及运行的日志文件
我们现在需要进入到conf目录
,修改配置文件.
目前来说,我们只需要关心server.xml
、schema.xml
、rule.xml
这三个文件.
server.xml
:主要配置Mycat的启动参数,连接密码,白名单,黑名单,访问权限控制等参数,我们暂时不修改,用默认的就可以了.
schema.xml
:主要配置逻辑库、逻辑表和真实库、真实表之间的映射关系.
rule.xml
:主要配置分库分表时的分片规则,此次试验中我们并不需要修改到.
目前我们的环境是这样的:
主机IP | 角色 |
---|---|
192.168.142.128 | MySQL主节点 |
192.168.142.129 | MySQL从节点 |
192.168.142.130 | MyCat服务器 |
然后我们需要修改schema.xml
文件,修改内容如下(建议直接复制我的,然后把Ip换一下就好了.):
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_order" dataNode="dn01"/>
schema>
<dataNode name="dn01" dataHost="dh01" database="hello" />
<dataHost name="dh01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()heartbeat>
<writeHost host="192.168.142.128" url="192.168.142.128:3306" user="root" password="WolfCode_2017">
<readHost host="192.168.142.129" url="192.168.142.129:3306" user="root" password="WolfCode_2017">readHost>
writeHost>
<writeHost host="192.168.142.129" url="192.168.142.129:3306" user="root" password="WolfCode_2017">writeHost>
dataHost>
mycat:schema>
name属性
:表示的是逻辑库的名字,是应用程序连接的时候的数据库名称.
checkSQLschema属性
:当该值设置为 true 时,如果我们执行语句select * from TESTDB.travelrecord;则 MyCat 会把语句修改
为select * from travelrecord;。即把表示 schema 的字符去掉,避免发送到后端数据库执行时报**(ERROR
1146 (42S02): Table ‘testdb.travelrecord’ doesn’t exist)。**
不过,即使设置该值为 true ,如果语句所带的是并非是 schema 指定的名字,例如:select * from
db1.travelrecord; 那么 MyCat 并不会删除 db1 这个字段,如果没有定义该库的话则会报错,所以在提供 SQL
语句的最好是不带这个字段。
sqlMaxLimit属性
:当该值设置为某个数值时。每条执行的 SQL 语句,如果没有加上 limit 语句,MyCat 也会自动的加上所对应
的值。例如设置值为 100,执行**select * from TESTDB.travelrecord;的效果为和执行select * from
TESTDB.travelrecord limit 100;**相同。
设置该值的话,MyCat 默认会把查询到的信息全部都展示出来,造成过多的输出。所以,在正常使用中,还
是建议加上一个值,用于减少过多的数据返回。
当然 SQL 语句中也显式的指定 limit 的大小,不受该属性的约束。
需要注意的是,如果运行的 schema 为非拆分库的,那么该属性不会生效。需要手动添加 limit 语句
Table 标签定义了 MyCat 中的逻辑表,所有需要拆分的表都需要在这个标签中定义。
name 属性
:定义逻辑表的表名,这个名字就如同我在数据库中执行 create table 命令指定的名字一样,同个 schema 标
签中定义的名字必须唯一。
dataNode属性
:定义这个逻辑表所属的 dataNode, 该属性的值需要和后面 dataNode 标签中 name 属性的值相互对应。
dataNode 标签定义了 MyCat 中的数据节点,也就是我们通常说所的数据分片。一个 dataNode 标签就是一个独立的数据分片。
name 属性
:定义数据节点的名字,这个名字需要是唯一的,我们需要在 table 标签上应用这个名字,来建立表与分片对
应的关系。
dataHost 属性
:该属性用于定义该分片属于哪个数据库实例的,属性值是引用 dataHost 标签上定义的 name 属性。
database 属性
:该属性用于定义该分片属性哪个具体数据库实例上的具体库,因为这里使用两个纬度来定义分片,就是:实例+具体的库。因为每个库上建立的表和表结构是一样的。所以这样做就可以轻松的对表进行水平拆分。
作为 Schema.xml 中最后的一个标签,该标签在 mycat 逻辑库中也是作为最底层的标签存在,直接定义了具
体的数据库实例、读写分离配置和心跳语句。
name 属性
:唯一标识 dataHost 标签,供上层的标签使用
maxCon 属性
:指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的 writeHost、readHost 标签都会使用这个属
性的值来实例化出连接池的最大连接数
minCon 属性
:指定每个读写实例连接池的最小连接,初始化连接池的大小
balance 属性
:
负载均衡类型,目前的取值有 3 种:
writeType 属性
:
负载均衡类型,目前的取值有 3 种:
2.writeType=“1”,所有写操作都随机的发送到配置的 writeHost,1.5 以后废弃不推荐。switchType 属
性
dbType 属性
:指定后端连接的数据库类型,目前支持二进制的 mysql 协议,还有其他使用 JDBC 连接的数据库。例如:
mongodb、oracle、spark 等。
dbDriver 属性
:指定连接后端数据库使用的 Driver,目前可选的值有 native 和 JDBC。使用 native 的话,因为这个值执行的
是二进制的 mysql 协议,所以可以使用 mysql 和 maridb。其他类型的数据库则需要使用 JDBC 驱动来支持。
从 1.6 版本开始支持 postgresql 的 native 原始协议。
如果使用 JDBC 的话需要将符合 JDBC 4 标准的驱动 JAR 包放到 MYCAT\lib 目录下,并检查驱动 JAR 包中
包括如下目录结构的文件:META-INF\services\java.sql.Driver。在这个文件内写上具体的 Driver 类名,例如:
com.mysql.jdbc.Driver。
这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL 可以使用 select user(),Oracle 可以
使用 select 1 from dual 等。
####六、writeHost 标签、readHost 标签解释
这两个标签都指定后端数据库的相关配置给 mycat,用于实例化后端连接池。唯一不同的是,writeHost 指定写实例、readHost 指定读实例,组着这些读写实例来满足系统的要求。在一个 dataHost 内可以定义多个 writeHost 和 readHost。但是,如果 writeHost 指定的后端数据库宕机,那么这个 writeHost 绑定的所有 readHost 都将不可用。另一方面,由于这个 writeHost 宕机系统会自动的检测到,并切换到备用的 writeHost 上去。
host 属性
:用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1。
url 属性
:后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式。用 JDBC 或其他的
dbDriver,则需要特殊指定。当使用 JDBC 时则可以这么写jdbc:mysql://localhost:3306/。
user 属性
:后端存储实例需要的用户名字。
password 属性
:后端存储实例需要的密码。
使用命令
/usr/local/mycat/bin/mycat start
然后观察wrapper.log文件看是否已经启动成功.
出现这样的界面说明已经启动成功.可以通过Navicat客户端连接Mycat,或者通过应用程序连接也是可以的.
如果需要修改默认端口或者默认密码的话需要修改server.xml文件.在应用程序中连接的时候,和之前连接MySQL一样的.只是URL地址不一样而已,代码还是一样的.
目前我们连接Mycat之后,所有的读操作都是走从节点的,如果有需求需要读走主节点的话,可以使用Mycat中的注解,强制让读操作走主节点.
/*#mycat:db_type=master*/ 真实SQL