4

我的应用程序连接到两个MySQL 5.6(实际上是Amazon Aurora)实例的故障转移集群。主动节点始终是可写访问的,而被动节点则在read_only模式下运行(这与规范的MySQL故障转移集群不同,默认情况下所有从节点都是可写访问的)。Amazon RDS提供了一个符号 DNS 名称,该名称始终指向活动MySQL节点的 IP 地址。

在故障转移过程中,前一个主节点以read_only模式重新启动,而前一个被动节点变为可写访问并提升为主节点。此外,DNS 记录已更改,因此集群的 DNS 名称现在指向新的主节点。

即使我完全禁用了 Java 端的 DNS 缓存(通过sun.net.inetaddr.ttlnetworkaddress.cache.ttl),特定于操作系统的 DNS 缓存仍然有效,因此在数据库故障转移后,我的 DBCP 池最终会充满与只读MySQL实例的连接。这些连接是valid,即它们是故障转移完成后但DNS 缓存过期之前获得的。此外,这些连接都没有readOnly设置标志,所以在我执行一些 DML 之前,我无法判断我是否正在与只读实例交谈,这是ER_OPTION_PREVENTS_STATEMENT它的全部荣耀。setReadOnly(false)即使我通过调用和设置标志明确地将连接设置为读写模式readOnlyPropagatesToServer,这也只会导致驱动程序发送SET SESSION TRANSACTION READ WRITE到服务器,这不会导致抛出任何异常。

我想尽可能少地影响应用程序逻辑来解决这个问题。如果有办法将与只读实例的连接视为无效/关闭的连接(即将其从池中逐出),则可以实现这一点。

我可以有一个验证查询,例如SHOW GLOBAL VARIABLES LIKE 'read_only'与之相关的附加逻辑吗?是否可以根据验证查询返回的标量值来影响池的行为?

4

1 回答 1

4

可以使用以下验证查询:

select case when @@read_only = 0 then 1 else (select table_name from information_schema.tables) end as `1`

如果数据库以只读模式运行,则查询将失败

ERROR 1242 (21000): Subquery returns more than 1 row

由于Amazon Aurora设置innodb_read_only但不在read_only集群中的读取器终端节点上,因此验证查询可以重写为

select case when @@read_only + @@innodb_read_only = 0 then 1 else (select table_name from information_schema.tables) end as `1`

受到这个答案的启发。

于 2016-09-19T00:01:07.497 回答