MyCAT读写分离后数据丢失问题

本文介绍了读写分离方案,在dataHost上配置禁用读写分离,通过hint语句分发读流量。测试发现部分MyCAT事务会丢失记录,经分析是MyCAT处理逻辑与应用程序用法问题导致,且debug日志不利于排查。还总结了MyCAT前后端连接管理策略。

在做读写分离时,我们采用了以下方案,在dataHost上配置了balance=0, 默认禁用读写分离。然后只有带有/*#mycat:db_type=slave*/这样hint的语句才会被分发到readHost,后续会逐渐通过添加hint到新的hint语句来来放开更多的流量,希望这样逐步放开读流量可以避免一次性全部迁移带来的影响。

 <dataHost name="masterFirst" maxCon="100" minCon="50" balance="0" tempReadHostAvailable="1"
            writeType="0" dbType="mysql" dbDriver="native" switchType="-1"  slaveThreshold="10">
      <writeHost host=mysqla>
            <readHost host=mysqlb/>
      </writeHost>
....

但是测试发现部分事务会丢失记录,通过分析发现部分经过MyCAT的事务会被一条rollback回滚。经过分析,是以下模式的事务会被回滚:

set autocommit=0;
INSERT INTO tablea ...
/*#mycat:db_type=slave*/SELECT xx from tableb
COMMIT

在MySQL端看到以上序列会变为以下模式,在writeHost上

set autocommit=0;INSERT INTO tablea ...
ROLLBACK

在readHost上

SELECT xx from tableb

这样,插入到表tablea的数据就丢了。而此时,业务服务器,MyCAT服务器和MySQL端都无任何错误日志。
经过分析,发现是MyCAT对以上场景的处理逻辑如下

  • MyCAT在一个连接到MySQL writeHost的连接内碰到一个到readHost的语句
  • MyCAT释放writeHost连接回连接池,而释放连接会发起rollback(这是为什么会多一个rollback的原因)
  • MyCAT新建到readHost的连接,并执行到readHost的语句

这个逻辑应该是没有问题的,因为MyCAT要保证在一个前端事务边界内(面向应用)任一时刻只能关联同一个后端连接(到MySQL)。而根源是应用程序做读写分离用法上的问题。但是NonBlockingSession.java代码在释放并切换连接只产生了一行debug日志,导致我们在丢失数据的时候在所有地方都找不到错误日志。所以debug级别明显不利于排查。已经在MyCAT GitHub提醒进行改正。

总结MyCAT的前后端连接管理策略。

  1. MyCAT以事务为单元来请求和使用后端MySQL连接池
  2. 开始事务即可从MySQL连接池中拿连接(后端连接),关闭事务即释放连接到后端连接池
  3. 释放MySQL连接回连接池前会在MySQL连接上发一个rollback指令。这会使在应用发一个commit时,经过MyCAT,MySQL收到commit和rollback两条语句。而应用发一个rollback,经过MyCAT,MySQL会收到rollback和rollback两条语句
  4. 一个后端MySQL连接上出现事务内的SQL错误(比如主键冲突)后,应用如果不进行rollback就在别的线程复用前端MyCAT连接,那么应用新的SQL全部都会失败。
  5. 如果MySQL连接所在事务处于异常状态,前端关闭连接,对应MySQL连接会被关闭

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值