主从切换:顾名思义,就是MySQL写节点出现宕机后,会自动切换到备用节点(也就是把从机也配置成writeHost),这样的话,第一个writeHost故障后,会自动切换到第二个,第二个故障后自动切换到第三个…以此类推;
如果当是1主3从模式,可以把第1个从节点配置为writeHost2,第2个和第3个从节点则配置为writeHost1的readHost;
一般情况下,都会结合读写分离一起实现,本文也是接着上一篇读写分离的文章的示例改造,如果没有查看的话可以先看https://blog.csdn.net/BruceLiu_code/article/details/104727028【MyCat基于MySQL实现读写分离】
要实现mysql主从切换,主要有以下几点:
【a】修改schema.xml,配置主从切换switchType=”2” 与心跳show slave status
:
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="user" primaryKey="id" rule="mod-long" dataNode="dn1,dn2" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="septwriteread" />
<dataNode name="dn2" dataHost="localhost1" database="septwriteread02" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave statusheartbeat>
<writeHost host="hostM1" url="192.168.70.128:3306" user="root"
password="123">
<readHost host="hostS1" url="192.168.70.130:3306" user="root" password="123" />
writeHost>
<writeHost host="hostM2" url="192.168.70.130:3306" user="root"
password="123">
writeHost>
dataHost>
mycat:schema>
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主从复制时延,当Seconds_Behind_Master>slaveThreshold时,读写分离筛选器会过滤掉此Slave机器,防止读到很久以前的旧数据,当主节点宕机后,切换逻辑会检查Slave上的Seconds_Behind_Master是否为0,为0时则表示主仅同步,可安全切换,否则不会切换。
【b】关闭主服务器192.168.70.128的mysql服务
systemctl stop mariadb.service
查看日志可见,主MySQL已经与从服务器失去了连接。
java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[?:1.8.0_144]
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) ~[?:1.8.0_144]
at io.mycat.net.NIOConnector.finishConnect(NIOConnector.java:164) ~[Mycat-server-1.6.7.1-release.jar:?]
at io.mycat.net.NIOConnector.finishConnect(NIOConnector.java:143) ~[Mycat-server-1.6.7.1-release.jar:?]
at io.mycat.net.NIOConnector.run(NIOConnector.java:98) ~[Mycat-server-1.6.7.1-release.jar:?]
2019-12-26 13:55:58.402 INFO [$_NIOConnector] (io.mycat.net.AbstractConnection.close(AbstractConnection.java:520)) - close connection,reason:java.net.ConnectException: Connection refused ,MySQLConnection [id=0, lastTime=1577339758387, user=root, schema=septwriteread02, old shema=septwriteread02, borrowed=false, fromSlaveDB=false, threadId=0, charset=utf8, txIsolation=3, autocommit=true, attachment=null, respHandler=null, host=192.168.70.128, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
2019-12-26 13:55:58.402 INFO [$_NIOConnector] (io.mycat.sqlengine.SQLJob.connectionError(SQLJob.java:125)) - can't get connection for sql :show slave status
2019-12-26 13:55:58.402 ERROR [$_NIOConnector] (io.mycat.backend.heartbeat.MySQLHeartbeat.nextDector(MySQLHeartbeat.java:215)) - set Error 2 DBHostConfig [hostName=hostM1, url=192.168.70.128:3306]
【c】登录mycat,执行如下查询:
select * from user;
查看mycat日志,看下查询请求被分发到哪一个节点上执行
2019-12-26 13:58:43.432 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.backend.datasource.PhysicalDBPool.getRWBanlanceCon(PhysicalDBPool.java:551)) - select read source hostM2 for dataHost:localhost1
2019-12-26 13:58:43.432 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.backend.mysql.nio.MySQLConnection.synAndDoExecute(MySQLConnection.java:463)) - con need syn ,total syn cmd 2 commands SET names utf8mb4;schema change:true con:MySQLConnection [id=14, lastTime=1577339923432, user=root, schema=septwriteread, old shema=septwriteread02, borrowed=true, fromSlaveDB=false, threadId=45, charset=utf8, txIsolation=3, autocommit=true, attachment=dn1{SHOW STATUS}, respHandler=SingleNodeHandler [node=dn1{SHOW STATUS}, packetId=0], host=192.168.70.130, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
2019-12-26 13:58:43.437 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:386)) - release connection MySQLConnection [id=14, lastTime=1577339923408, user=root, schema=septwriteread, old shema=septwriteread, borrowed=true, fromSlaveDB=false, threadId=45, charset=utf8, txIsolation=3, autocommit=true, attachment=dn1{SHOW STATUS}, respHandler=SingleNodeHandler [node=dn1{SHOW STATUS}, packetId=-95], host=192.168.70.130, port=3306, statusSync=io.mycat.backend.mysql.nio.MySQLConnection$StatusSync@7911636, writeQueue=0, modifiedSQLExecuted=false]
2019-12-26 13:58:43.437 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.backend.datasource.PhysicalDatasource.releaseChannel(PhysicalDatasource.java:633)) - release channel MySQLConnection [id=14, lastTime=1577339923408, user=root, schema=septwriteread, old shema=septwriteread, borrowed=true, fromSlaveDB=false, threadId=45, charset=utf8, txIsolation=3, autocommit=true, attachment=null, respHandler=null, host=192.168.70.130, port=3306, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
可见,查询请求被分发到M2节点上,即备用的writeHost。
【d】接着,我们执行插入操作
insert into user(id,name ) values(6666666,database());
插入成功,然后我们查看 dnindex.properties,可见当前writeHost为第二个writeHost(备用写节点192.168.8.131),Mycat的dnindex属性文件中writeHost顺序是从0开始,即0代表第一个
cat dnindex.properties
(1) MySQL主从复制配置中,如果涉及到函数或存储过程的同步复制,需要在/etc/my.cnf中的[mysqld]段中增加配置log_bin_trust_function_creators=true 或在客户端中设置 set global log_bin_trust_function_creators = 1;
(2) 如果要做读写分离下的主从切换,那么从节点也有可能会变为写节点,因此从节点就不能设置为只读 read_only=1 ;