在传统项目为了能快速实现业务系统,一般都采用三层架构(mvc),所有的模块功能集成在一起,所有的数据都放在一个数据库中,如图所示:
当项目不断发展,用户量不断增加,单台应用服务器已经无法承载系统要求(一个tomcat承受访问能力有限),那么就需要引入nginx做反响代理和负载均衡,对外一致提供服务,对内部署两套系统,如下图所示:
配置了nginx貌似解决了单应用部署的性能问题,但是随着部署应用服务器越来越多,单台数据库服务无法承载业务需求,为了缓解数据库的压力,可以在应用和数据库之间搭建一层缓存,典型的NoSql服务redis用于做缓存,可以通过统计查询记录,缓存热点数据从而减小数据库访问压力,如下图所示:
缓存只能缓解数据库访问压力,拦截部分数据库请求,随着用户量增加访问进一步增长,不能根本解决问题,这个时候我们就必须对数据库架构做出改变,通过mycat实现数据库的读写分离和主从切换功能,如下图所示:
Mycat实现Mysql主从复制,其中写操作在master主节点上执行,包括insert,delete,update 语句操作;读操作在slave节点上执行,只有select语句操作,其他操作均由主master的二进制文件决定;MyCat支持双主多从等搭配,多主多从情况需要配置多个writeHost兄弟节点,多个readHost节点即可!
Mycat的架构其实很好理解,Mycat是数据库代理中间件,Mycat后面就是物理数据库。和Web服务器的Nginx类似。对于使用者来说,访问的都是Mycat,不会接触到后端的数据库。如下案例是做一个主从、读写分离的示例。
主机信息 ip地址 说明
itcast-01 192.168.79.130 装载mysql5.7x版本,用于master主服务
itcast-02 192.168.79.131 装载mysql5.7x版本,用于slave从服务
itcast-01 192.168.79.130 安装mycat服务,版本1.4x
Mycat作为主数据库中间件,肯定是与代码弱关联的,所以代码是不用修改的,使用Mycat后,连接数据库是不变的,MyCAT默认端口是8066。连接方式和普通数据库一样,比如:jdbc:mysql://192.168.79.130:8066/database
配置读写分离的schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!--定义主从同步数据库,mycat做读写分离,只能绑定一个dataNota-->
<schema name="KEVINDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="sync1">
</schema>
<!--逻辑节点配置 name节点名称 dataHost节点主机(物理节点) database 节点数据库(物理数据库名) -->
<!--独写分离的dataNode database为mysql配置主从同步指定的数据库 kevin-->
<dataNode name="sync1" dataHost="sync01" database="kevin" />
<!--
Balance参数设置:
1. balance=“0”, 所有读操作都发送到当前可用的writeHost上。
2. balance=“1”,所有读操作都随机的发送到readHost。
3. balance=“2”,所有读操作都随机的在writeHost、readhost上分发
WriteType参数设置:
1. writeType=“0”, 所有写操作都发送到可用的writeHost上。
2. writeType=“1”,所有写操作都随机的发送到readHost。
3. writeType=“2”,所有写操作都随机的在writeHost、readhost分上发。
switchType 目前有三种选择:
-1:表示不自动切换
1 :默认值,自动切换
2 :基于MySQL主从同步的状态决定是否切换
“Mycat心跳检查语句配置为 show slave status ,dataHost 上定义两个新属性: switchType="2" 与slaveThreshold="100",此时意味着开启MySQL主从复制状态绑定的读写分离与切换机制。Mycat心跳机制通过检测 show slave status 中的 "Seconds_Behind_Master", "Slave_IO_Running", "Slave_SQL_Running" 三个字段来确定当前主从同步的状态以及Seconds_Behind_Master主从复制时延。“
-->
<!--配置独写分离的 数据库配置 -->
<dataHost name="sync01" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<!-- can have multi write hosts -->
<!-- itcast-01 -->
<writeHost host="hostM1" url="192.168.79.130:3306" user="root"
password="root123">
<!-- itcast-02 -->
<readHost host="hostS1" url="192.168.79.131:3306" user="root" password="root123"/>
</writeHost>
<!--备用master节点,当默认master宕机,会自动切换 -->
<writeHost host="hostM2" url="192.168.79.13x:3306" user="root"
password="root123"/>
</dataHost>
</mycat:schema>
schema.xml定义了MyCAT逻辑和物理逻辑信息如果对schema.xml配置标签不了解,请看MyCAT安装及配置说明
示例配置一主一从结构是最简单的配置:
MyCat支持双主多从,如果有N个主,那么就配置N个writeHost兄弟节点;如果有M个从节点,那么就配置M个readHost节点即可。
注:
数据测试:
查看MyCAT运行日志:
tail -f mycat.log
02/26 10:39:52.053 INFO [Timer1] (AbstractConnection.java:452) -close connection,reason: idle ,ServerConnection [id=9, schema=MYCATDB, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=MYCATDB]
02/26 10:44:02.710 INFO [Timer0] (PhysicalDatasource.java:269) -create connections ,because idle connection not enough ,cur is 7, minCon is 10 for hostM1
02/26 10:44:02.717 INFO [$_NIOREACTOR-1-RW] (NewConnectionRespHandler.java:44) -connectionAcquired MySQLConnection [id=2536, lastTime=1582685042709, schema=db3, old shema=db3, borrowed=false, fromSlaveDB=false, threadId=10707, charset=latin1, txIsolation=0, autocommit=true, attachment=null, respHandler=null, host=192.168.79.131, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
02/26 14:51:38.732 INFO [$_NIOREACTOR-2-RW] (FrontendAuthenticator.java:164) -ServerConnection [id=10, schema=null, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=null]'root' login success
02/26 14:52:59.512 INFO [$_NIOREACTOR-3-RW] (FrontendAuthenticator.java:164) -ServerConnection [id=11, schema=null, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=null]'root' login success
02/26 14:53:07.468 INFO [$_NIOREACTOR-0-RW] (FrontendAuthenticator.java:164) -ServerConnection [id=12, schema=null, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=null]'root' login success
02/26 14:53:07.860 INFO [$_NIOREACTOR-0-RW] (AbstractConnection.java:452) -close connection,reason:quit cmd ,ServerConnection [id=12, schema=KEVINDB, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=KEVINDB]
02/26 14:53:28.498 INFO [$_NIOREACTOR-1-RW] (FrontendAuthenticator.java:164) -ServerConnection [id=13, schema=null, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=null]'root' login success
02/26 14:53:28.611 INFO [$_NIOREACTOR-1-RW] (AbstractConnection.java:452) -close connection,reason:quit cmd ,ServerConnection [id=13, schema=KEVINDB, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=KEVINDB]
02/26 14:53:32.613 INFO [$_NIOREACTOR-2-RW] (FrontendAuthenticator.java:164) -ServerConnection [id=14, schema=null, host=192.168.79.1, user=root,txIsolation=3, autocommit=true, schema=null]'root' login success
02/26 15:22:06.370 WARN [$_NIOREACTOR-2-RW] (SingleNodeHandler.java:189) -execute sql err : errno:1054 Unknown column 'KEVINup' in 'field list' con:MySQLConnection [id=14, lastTime=1582701725697, schema=kevin, old shema=kevin, borrowed=true, fromSlaveDB=false, threadId=9306, charset=utf8, txIsolation=3, autocommit=true, attachment=sync1{update TB_KEVIN set KEVIN=KEVINup where id=5}, respHandler=SingleNodeHandler [node=sync1{update TB_KEVIN set KEVIN=KEVINup where id=5}, packetId=1], host=192.168.79.130, port=3306, statusSync=org.opencloudb.mysql.nio.MySQLConnection$StatusSync@7446fdae, writeQueue=0, modifiedSQLExecuted=true]
从日志看出,select * …查询通过192.168.79.131从机执行,update …修改语句通过192.168.79.130主机执行,从而实现的mycat读写分离!!!