mysql异常 主主一台down后 JDBC操作MySQL产生的read-only连接异常

mysql 主主一台down后 JDBC操作MySQL产生的read-only连接异常
对于Java(JEE)的攻城师来说,使用JDBC操作MySQL数据库是再平常不过的事儿了,但是你知道吗?在MySQL的JDBC驱动里还要很多配置参数,例如:autoReconnectForPools/failOverReadOnly/queriesBeforeRetryMaster/secondsBeforeRetryMaster 这些参数对双机或者集群环境是很有用的,昨天在就发生了一些MySQL运维的事儿,而这几个参数也引起了我们的关注。
我的废话:MySQL的JDBC参数加起来有百来个,分为6大类,更多详情请查阅,《MySQL-JDBC连接器使用手册》。
我们有一个生产环境的数据库是MySQL双主,12台JEE应用服务器对MySQL先读再写的轮训操作。昨天运维的人员需要对数据库机器添加内存,添加内存的事儿显然是需要对数据库服务器进行开关机,一拨人负责一台,两台服务器很快内存升级完毕,MySQL服务器也正常工作了。
但回头发现无法执行业务操作,12台应用服务器抛出全部Cause: java.sql.SQLException: Connection is read-only 异常。之前我们没有动应用服务器啊,只是重启数据库服务器按理说应该等数据库服务器重启完毕以后应用服务器会自动重连正常工作了。
由于时间紧迫需要立即恢复,没有办法,我们对12台应用服务器重启了一下,天下太平,世界又恢复平静了。当时没时间去研究个究竟到底是什么原因导致,但我知道如果再次遇到这样的类似场景还是出现同样的问题,所以需要找出问题的根本原因,给自己一个解释。
在MySQL的官方网站上找了一些可能性的依据,原因是设置了autoReconnectForPools=true参数,导致failOverReadOnly参数默认生效。原来failOverReadOnly的默认值是true,导致失效重新连接后出现  Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed 的错误。
“Starting with Connector/J 3.1.7, we've made available a variant of the driver that will automatically send queries to a read/write master,or a failover or round-robin loadbalanced set of slaves based on the state of Connection.getReadOnly() .”
看了官方文档中的上面这段话为何是ReadOnly的状态也很能理解是为什么了,其实MySQL官方倡导的是Master-To-Slave的数据库备份方案,而我们的运行环境是Master-To-Master,如果前一个Master挂掉的话 往Slave中去写,等到Master恢复再对Master操作的时候数据就沉于大海,那么数据就不一致了,恢复起来会非常的麻烦,当前一个挂掉的时候,MySQL驱动会认为你的Master挂了,如果继续写将会写入Slave,所以默认的状态是ReadOnly=true,失败后重连,但重连后对下一台操作的是只读(ReadOnly)。
后来我们在测试环境中也重现了这个错误,然后加上failOverReadOnly=false,并且加上了queriesBeforeRetryMaster 和secondsBeforeRetryMaster 配置参数缩短切换和重试之间的时间长度。这两个参数是表示如果出现故障切换(使用多主机故障切换)并返回主机之前发出的查询数。无论首先满足了哪个条件,“queriesBeforeRetryMaster”或“secondsBeforeRetryMaster”,均会再次与主机进行连接,secondsBeforeRetryMaster是表示 出现故障切换后,在尝试再次连接到主服务器。
在测试环境中无论怎么重试、重启或者重连,世界很平静,哥很淡定,才能现在有空写这个blog,将整个过程记录下来。等下次需要停机或者重启的时候将这个参数加上,现已经记录在下个版本的发布计划中了。另外,我整理了一份JDBC操作MySQL的文档,方面日后查阅,下载地址。

你可能感兴趣的:(mysql异常 主主一台down后 JDBC操作MySQL产生的read-only连接异常)