配置文件说明
server.xml
打开mycat安装目录下的/conf/server.xml文件,这个配置文件比较长,看着比较费脑,但其实对于初学者来说,我们需要配置的地方并不多,所以不用太害怕这种长篇幅的配置文件。(其实在上一篇文章的结尾,我也说过,面对一个新技术的时候首先不能懵逼,一步一步地去分析并接受他,扯远了)配置文件简化之后大概是这样的一个结构。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <system> </system> <user name="MyCat" defaultAccount="true"> </user> </mycat:server>
这样看起来是不是简单多了,其实对于Server.xml,我们主要配置的就是下面的user模块,我们把它展开,着重讲讲这部分的配置。
<user name="这里写MyCat的用户名 可以自定义" defaultAccount="true"> <property name="password">这里写MyCat的密码</property> <property name="schemas">这里配置MyCat的虚拟database</property> <!-- 表级 DML 权限设置 --> <!-- 这里是我们配置的mycat用户对某张表的权限配置,我们这里暂不配置但是还是说一 下。下文中的0000 1111 每一位 代表CRUD 1111就是有增删改查的权限,0000就 是没有这些权限。以此类推 <privileges check="false"> <schema name="TESTDB" dml="0110" > <table name="tb01" dml="0000"></table> <table name="tb02" dml="1111"></table> </schema> </privileges> --> </user>
user代表MyCat的用户,我们在使用MySQL的时候都会有一个用户,MyCat作为一个虚拟节点,我们可以把它想象成它就是一个MySQL,所以自然而然它也需要有一个用户。但是他的用户并不是我们用命令创建的,而是直接在配置文件中配置好的,我们之后登录MyCat,就是用这里的用户名和密码进行登录。至于如何配置,我在上面的配置中都写好啦。跟着做就没有问题。
schema.xml
打开MyCat安装目录的conf/schema.xml,这个配置文件是我们需要关注的一个配置文件,因为我们的读写分离、分库分表、故障转移、都配置在这个配置文件中。但是这个配置文件并不长,我们可以一点一点慢慢分析。
首先是<schema></schema>
标签中的内容。这个标签主要是为MyCat虚拟出一个数据库,我们连接到MyCat上能看到的数据库就是这里配置的,而分库分表也主要在这个标签中进行配置。
这个标签中的name属性,就是为虚拟数据库指定一个名字,也是我们连接MyCat看到的数据库的库名,dataNode是和下文的dataNode标签中的name相对应的,代表这个虚拟的数据库和下面的dataNode进行绑定。
<schema name="MyCatDatabase" checkSQLschema="false" sqlMaxLimit="100" dataNode="这里写节点名,需要和dataNode中的name相对应"> <!-- 分库分表 --> <!--<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />--> </schema>
第二个标签是<dataNode/>
标签,这个标签是和我们真实数据库中的database联系起来的,name属性是我们对这个dataNode自定义的一个名字,要注意的是,这个名字需要和schema标签中的dataNode内容一致,database属性写的是我们真实数据库中的真实database的名字。而dataHost的内容需要和之后<dataHost></dataHost>
标签中的name属性的值相对应。
<dataNode name="这里写节点名,需要和schema中的dataNode相对应" dataHost="这里也是一个自定义名字,需要和dataHost中的name相对应" database="这里填MySQL真实的数据库名" />
第三个标签要说的是<dataHost></dataHost>
标签,这个标签是和我们真实数据库的主从、读写分离联系起来的标签,什么意思呢。这个标签中有这么两个子标签<whiteHost>
和<readHost>
分别代表我们的写库和读库,<whiteHost>
中配置的库可以用于读或者写,而<readHost>
中配置的库只能用于读。
可以看到schema.xml的配置是一环扣一环的,每个标签之间都有相互进行联系的属性。我们最后配置完的schema.xml应该长下面这个样子:
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="这里写虚拟database名,需要和server.xml中的schema相对应" checkSQLschema="false" sqlMaxLimit="100" dataNode="这里写节点名,需要和dataNode中的name相对应"> <!-- 分库分表 --> <!--<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />--> </schema> <dataNode name="这里写节点名,需要和schema中的dataNode相对应" dataHost="这里也是一个自定义名字,需要和dataHost中的name相对应" database="这里填MySQL真实的数据库名" /> <dataHost name="这里写和dataNode中的dataHost相同的名字" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <!-- 心跳语句,证明myCat和mySQL是相互连接的状态--> <heartbeat>show slave status</heartbeat> <!-- 读写分离 --> <writeHost host="节点的名字,随便取" url="数据库的url(IP:PORT)" user="数据库中给MyCat创建的用户名" password="数据库中给MyCat创建的密码"> <readHost host="节点的名字,随便取" url="数据库的url(IP:PORT)" user="数据库中给MyCat创建的用户名" password="数据库中给MyCat创建的密码"> </readHost> <readHost host="节点的名字,随便取" url="数据库的url(IP:PORT)" user="数据库中给MyCat创建的用户名" password="数据库中给MyCat创建的密码"> </readHost> </writeHost> <!-- 主从切换 --> <writeHost host="节点的名字,随便取" url="数据库的url(IP:PORT)" user="数据库中给MyCat创建的用户名" password="数据库中给MyCat创建的密码"></writeHost> <writeHost host="节点的名字,随便取" url="数据库的url(IP:PORT)" user="数据库中给MyCat创建的用户名" password="数据库中给MyCat创建的密码"></writeHost> </dataHost> </mycat:schema>
MyCat配置读写分离
上文中我们对MyCat的两个配置文件进行了基本的解读,那么现在就开始搭建一个基于MyCat的读写分离。我这里有三个数据库,一主二从,再说一遍环境吧:
192.168.43.201 master库
192.168.43.202 slave库
192.168.43.203 slave库
那么对于server.xml和schema.xml的配置如下:
server.xml:
<user name="MyCat" defaultAccount="true"> <property name="password">123456</property> <property name="schemas">MyCat</property> </user>
schema.xml:
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="MyCat" checkSQLschema="false" sqlMaxLimit="100" dataNode="mycatdb"></schema> <!-- testcluster是我真实数据库中的名字 --> <dataNode name="mycatdb" dataHost="mycluster" database="testcluster" /> <!-- 开启读写分离必须将balance修改为1--> <dataHost name="mycluster" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>show slave status</heartbeat> <!-- 读写分离 --> <writeHost host="Master201" url="192.168.43.201:3306" user="MyCat" password="123456"> <readHost host="Slave202" url="192.168.43.202:3306" user="MyCat" password="123456"> </readHost> <readHost host="Slave203" url="192.168.43.203:3306" user="MyCat" password="123456"> </readHost> </writeHost> </dataHost> </mycat:schema>
启动MyCat并测试:
启动MyCat:
./mycat start
连接MyCat:
mysql -u MyCat -h 192.168.43.90 -P 8066 -p
可以正确看到MyCat中存在一个数据库,名字叫MyCat,而这个数据库是我们虚拟出来的,并不真实存在,实际上就是我们配置的<schema name="MyCat"></schema>
起了作用。
在MyCat库中创建一张表
CREATE TABLE student(student_id VARCHAR(32),student_name VARCHAR(32));
这样就可以证明我们的mycat连接真实数据库成功。那么我们下面就要开始证明读写分离,何谓读写分离呢?就是读数据操作从从库中读取,而主库只负责写操作,下面我们开始进行验证。
在验证之前,我们需要将MyCat的日志设置为debug模式,因为在info模式下,是不能在日志中显示SQL语句转发到哪一个数据库中进行查询的。
如何设置:
打开conf/log4j2.xml
执行一条插入语句:
INSERT INTO student(student_id,student_name) VALUES('20191130','Object');
查看日志:
可以看到,INSERT语句是在201中写入的,201是Master库,也就是写库。
写在我们来执行一条读语句:
SELECT * FROM student;
可以看到,SELECT 语句是在202中执行的,202是Slave库,也就是读库。
再执行一次:
这个时候读语句在203中执行,还是读库,这两个读库是基于负载均衡规则来进行读取的。
这样就完成了读写分离的配置,当我们需要进行INSERT/UPDATE/DELETE时,会直接到Master中进行写入,然后同步到Slave库,而要进行SELECT操作时,就改为去Slave中读,不影响Master的写入,这种读写分离,拓展了MySQL主从同步的功能,可以在容灾备份的同时,提升数据库的性能。
MyCat配置故障转移
我们在上文中已经完成了MyCat关于读写分离的配置,那么我们大胆假设,假如我们的Master数据库突然宕机了,那么是否整个集群就丧失了写功能呢?
在没有故障转移之前,这个答案是肯定的,当主库宕机时,从库作为读库,是不会有写的功能的,整个集群也就丧失了写的功能,这是我们不希望看到的。
我们希望看到的场景是:当主库宕机,某一个从库自动变为主库,承担写的功能,保证整个集群的可用性。
那么我们开始进行配置,其实思路很简单,MyCat的标签中有一个switchType属性,其决定了切换的条件。
switchType指的是切换的模式,目前的取值也有4种:
- switchType='-1' 表示不自动切换
- switchType='1' 默认值,表示自动切换
- switchType='2' 基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status
- switchType='3'基于MySQL galary cluster的切换机制(适合集群)(1.4.1),心跳语句为 show status like 'wsrep%'。
我们直接将switchType修改为2,然后将两个读库配置为第一个写库同级的写库。
配置文件如下:
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="MyCat" checkSQLschema="false" sqlMaxLimit="100" dataNode="mycatdb"> </schema> <dataNode name="mycatdb" dataHost="mycluster" database="testcluster" /> <dataHost name="mycluster" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100"> <heartbeat>show slave status</heartbeat> <!-- 读写分离 --> <writeHost host="Master201" url="192.168.43.201:3306" user="MyCat" password="123456"> <readHost host="Slave202" url="192.168.43.202:3306" user="MyCat" password="123456"> </readHost> <readHost host="Slave203" url="192.168.43.203:3306" user="MyCat" password="123456"> </readHost> </writeHost> <!-- 主从切换 --> <writeHost host="Slave202" url="192.168.43.202:3306" user="MyCat" password="123456"></writeHost> <writeHost host="Slave203" url="192.168.43.203:3306" user="MyCat" password="123456"></writeHost> </dataHost> </mycat:schema>
重启MyCat
现在我们来停掉Master库,然后执行写操作,看看是什么结果。
service mysqld stop
MyCat日志:
执行
INSERT INTO student(student_id,student_name)VALUES('test','testdown');
MyCat日志
可以看到,现在当我们执行完这个语句时,他自动切换到202数据库进行写入,而202是Slave而非master,这就说明MyCat对写库进行了自动切换,我们的MySQL集群依旧可以提供写的功能。
当然,此时我们MySQL的主从架构已经被破坏,如果需要恢复主从结构,就需要手动地重新去恢复我们的主从架构。我们需要将201和203作为Slave,202作为Master,因为Master拥有最完整的数据。
优劣分析
关于这两种方式的优劣,相信如果仔细看完这篇文章的同学都会有一个深刻的体会。
代码层实现读写分离,主要的优点就是灵活,可以自己根据不同的需求对读写分离的规则进行定制化开发,但其缺点也十分明显,就是当我们动态增减主从库数量的时候,都需要对代码进行一个或多或少的修改。并且当主库宕机了,如果我们没有实现相应的容灾逻辑,那么整个数据库集群将丧失对外的写功能。
使用MyCat中间件实现读写分离,优点十分明显,我们只需要进行配置就可以享受读写
分离带来的效率的提升,不用写一行代码,并且当主库宕机时,我们还可以通过配置的方式进行主从库的自动切换,这样即使主库宕机我们的整个集群也不会丧失写的功能。其缺点可能就是我们得多付出一台服务器作为虚拟节点了吧,毕竟服务器也是需要成本的。
两种方式如何抉择:如果你目前的项目比较小,或者干脆是一个毕业设计、课程设计之类的,不会有动态增减数据库的需求,那么自己动手实现一个数据库的读写分离会比较适合你,毕竟答辩的时候,可以一行一行代码跟你的导师和同学解(zhuang)释(bi)。如果项目比较大了,数据库节点有可能进行增减,并且需要主从切换之类的功能,那么就使用第二种方式吧。这种配置化的实现可以降低第二天洗头时候下水管堵塞的几率。
END