java-从连接池移出到群集中只读节点的连接
作者:互联网
我的应用程序连接到两个MySQL 5.6(实际上是Amazon Aurora)实例的故障转移群集.主动节点始终是可写访问的,而被动节点则以read_only
模式运行(这与规范的MySQL故障转移群集不同,在MySQL故障转移群集中,所有从属节点默认都是可写访问的). Amazon RDS提供了一个符号DNS名称,该名称始终指向活动MySQL节点的IP地址.
在故障转移过程中,先前的主节点以只读模式重新启动,而先前的被动节点变为可写访问并被提升为主节点.同样,DNS记录也被更改,因此群集的DNS名称现在指向新的主节点.
即使我完全禁用了Java端的DNS缓存(通过sun.net.inetaddr.ttl或networkaddress.cache.ttl),特定于操作系统的DNS缓存仍然有效,因此在数据库故障转移之后,我最终还是拥有了DBCP池与只读MySQL实例的连接已满.这些连接是valid
,i. e.它们是在故障转移完成之后但在DNS缓存过期之前获得的.此外,这些连接都没有设置readOnly
标志,因此我无法确定我是否在与只读实例通信,直到执行一些DML,这才是ER_OPTION_PREVENTS_STATEMENT
的辉煌.即使我通过调用setReadOnly(false)
并设置readOnlyPropagatesToServer
标志将连接明确地设置为读写模式,这也只会导致驱动程序将SET SESSION TRANSACTION READ WRITE发送到服务器,而不会引发任何异常.
我想以尽可能少的应用程序逻辑影响来解决此问题.如果有一种方法可以将与只读实例的连接视为无效/关闭连接(即从池中驱逐它),则可以完成此操作.
我是否可以将validation query(例如SHOW GLOBAL VARIABLES LIKE’read_only)与其他逻辑绑定在一起?根据验证查询返回的标量值,是否有可能通过连接而影响池的行为?
解决方法:
可以使用以下验证查询:
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答案的启发.
标签:connection-pooling,apache-commons-dbcp,amazon-rds-aurora,java,mysql 来源: https://codeday.me/bug/20191026/1938365.html