从连接池

时间:2016-09-17 22:05:28

标签: java mysql connection-pooling apache-commons-dbcp amazon-rds-aurora

我的应用程序连接到两个 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,i。即已完成故障转移 ,但 DNS缓存已过期 。此外,这些连接都没有设置readOnly标志,所以在我执行某些DML之前,我无法判断我是否正在与只读实例通信,这是ER_OPTION_PREVENTS_STATEMENT尽其所能。即使我通过调用setReadOnly(false)并设置readOnlyPropagatesToServer标志明确地将连接置于读写模式,这只会导致驱动程序向服务器发送SET SESSION TRANSACTION READ WRITE,而不是; t导致抛出任何异常。

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

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

1 个答案:

答案 0 :(得分: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`

受到this回答的启发。