手把手教你实现MySQL读写分离+故障转移,不信你学不会!(下)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 手把手教你实现MySQL读写分离+故障转移,不信你学不会!(下)

配置文件说明


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


image.png


可以正确看到MyCat中存在一个数据库,名字叫MyCat,而这个数据库是我们虚拟出来的,并不真实存在,实际上就是我们配置的<schema name="MyCat"></schema>起了作用。



在MyCat库中创建一张表


CREATE TABLE student(student_id VARCHAR(32),student_name VARCHAR(32));


image.png


这样就可以证明我们的mycat连接真实数据库成功。那么我们下面就要开始证明读写分离,何谓读写分离呢?就是读数据操作从从库中读取,而主库只负责写操作,下面我们开始进行验证。


在验证之前,我们需要将MyCat的日志设置为debug模式,因为在info模式下,是不能在日志中显示SQL语句转发到哪一个数据库中进行查询的。


如何设置:


打开conf/log4j2.xml


image.png


执行一条插入语句:

INSERT INTO student(student_id,student_name) VALUES('20191130','Object');


image.png


查看日志:


image.png


可以看到,INSERT语句是在201中写入的,201是Master库,也就是写库。


写在我们来执行一条读语句:


SELECT * FROM student;


image.png


可以看到,SELECT 语句是在202中执行的,202是Slave库,也就是读库。

再执行一次:


image.png


这个时候读语句在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日志:


image.png


执行


INSERT INTO student(student_id,student_name)VALUES('test','testdown');


MyCat日志


image.png


可以看到,现在当我们执行完这个语句时,他自动切换到202数据库进行写入,而202是Slave而非master,这就说明MyCat对写库进行了自动切换,我们的MySQL集群依旧可以提供写的功能。


当然,此时我们MySQL的主从架构已经被破坏,如果需要恢复主从结构,就需要手动地重新去恢复我们的主从架构。我们需要将201和203作为Slave,202作为Master,因为Master拥有最完整的数据。


优劣分析


关于这两种方式的优劣,相信如果仔细看完这篇文章的同学都会有一个深刻的体会。


代码层实现读写分离,主要的优点就是灵活,可以自己根据不同的需求对读写分离的规则进行定制化开发,但其缺点也十分明显,就是当我们动态增减主从库数量的时候,都需要对代码进行一个或多或少的修改。并且当主库宕机了,如果我们没有实现相应的容灾逻辑,那么整个数据库集群将丧失对外的写功能。


使用MyCat中间件实现读写分离,优点十分明显,我们只需要进行配置就可以享受读写

分离带来的效率的提升,不用写一行代码,并且当主库宕机时,我们还可以通过配置的方式进行主从库的自动切换,这样即使主库宕机我们的整个集群也不会丧失写的功能。其缺点可能就是我们得多付出一台服务器作为虚拟节点了吧,毕竟服务器也是需要成本的。


两种方式如何抉择:如果你目前的项目比较小,或者干脆是一个毕业设计、课程设计之类的,不会有动态增减数据库的需求,那么自己动手实现一个数据库的读写分离会比较适合你,毕竟答辩的时候,可以一行一行代码跟你的导师和同学解(zhuang)释(bi)。如果项目比较大了,数据库节点有可能进行增减,并且需要主从切换之类的功能,那么就使用第二种方式吧。这种配置化的实现可以降低第二天洗头时候下水管堵塞的几率。

END


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
27天前
|
负载均衡 监控 关系型数据库
MySQL 官宣:支持读写分离了!!
【10月更文挑战第8天】MySQL的读写分离功能显著提升了数据库性能、可用性和可靠性。通过将读写操作分配至不同服务器,有效减轻单个服务器负载,提高响应速度与吞吐量,并增强系统稳定性。此外,它还支持便捷的扩展方式,可通过增加只读服务器提升读操作性能。实现读写分离的方法包括软件层面(如使用数据库中间件)和硬件层面(使用独立服务器)。使用时需注意数据一致性、负载均衡及监控管理等问题。
|
2月前
|
关系型数据库 MySQL Java
MySQL主从复制实现读写分离
MySQL主从复制(二进制日志)、 Sharding-JDBC实现读写分离
MySQL主从复制实现读写分离
|
3月前
|
SQL 关系型数据库 MySQL
(二十五)MySQL主从实践篇:超详细版读写分离、双主热备架构搭建教学
在上篇《主从原理篇》中,基本上把主从复制原理、主从架构模式、数据同步方式、复制技术优化.....等各类细枝末节讲清楚了,本章则准备真正对聊到的几种主从模式落地实践,但实践的内容通常比较枯燥乏味,因为就是调整各种配置、设置各种参数等步骤。
464 2
|
3月前
|
关系型数据库 MySQL PHP
开发者必看:MySQL主从复制与Laravel读写分离的完美搭配
开发者必看:MySQL主从复制与Laravel读写分离的完美搭配
67 2
|
3月前
|
SQL 关系型数据库 MySQL
mysql读写分离,主从同步
本文介绍了如何在Laravel项目中配置数据库读写分离,并实现MySQL主从同步。主要步骤包括:在`config/database.php`中设置读写分离配置;为主机授予从机访问权限;配置各MySQL服务器的`/etc/my.cnf`文件以确保唯一的`server-id`;以及通过SQL命令设置主从关系并启动从服务。文章还针对一些常见错误提供了排查方法。最后通过验证确认主从同步是否成功。[原文链接](https://juejin.cn/post/6901581801458958344)。版权所有者为作者佤邦帮主,转载请遵循相关规定。
|
3月前
|
cobar 关系型数据库 MySQL
使用MyCat实现MySQL主从读写分离(一)概述
【8月更文挑战第11天】MySQL读写分离通过主从复制分散负载,主库负责写操作,从库承担读查询,以复制技术确保数据一致性。此策略有效缓解锁竞争,提升查询效能并增强系统可用性。实现方式包括应用层处理,简便快捷但灵活性受限;或采用中间件如MyCAT、Vitess等,支持复杂场景但需专业团队维护。
87 0
|
3月前
|
SQL 关系型数据库 MySQL
基于proxysql实现MySQL读写分离
基于proxysql实现MySQL读写分离
|
5月前
|
SQL 关系型数据库 MySQL
使用mysql数据库的binlog应对故障
【6月更文挑战第1天】本文介绍`mysql的 binlog`工具用于解析MySQL的二进制日志,转换为可执行的SQL语句,主要用于数据库主从复制和增量恢复。定期备份和binlog推送能实现故障时的数据恢复。
195 9
使用mysql数据库的binlog应对故障
|
5月前
|
关系型数据库 MySQL
mysql-proxy实现mysql的读写分离
mysql-proxy实现mysql的读写分离
|
6月前
|
SQL 关系型数据库 MySQL
mysql 故障排除与优化
mysql 故障排除与优化