我的应用程序连接到由两个MySQL 5.6 (实际上是Aurora)实例组成的故障转移集群。主动节点总是可写访问的,而被动节点则运行在read_only
模式下(这不同于规范的MySQL故障转移集群,默认情况下,所有从节点都是可写访问的)。Amazon提供了一个符号DNS名称,它总是指向active MySQL节点的IP地址。
在故障转移过程中,前主节点在read_only
模式下重新启动,而以前的被动节点变为写访问节点,并提升为主节点。另外,DNS记录被更改,因此集群的DNS名称现在指向新的主节点。
即使我在Java端(通过sun.net.inetaddr.ttl
或networkaddress.cache.ttl
)完全禁用DNS缓存,但特定于操作系统的DNS缓存仍然有效,因此在数据库失效后,我的DBCP池将充满到只读MySQL实例的连接。这些连接是valid
,即它们是在故障转移完成后获得的,但是在之前DNS缓存过期。此外,这些连接都没有设置readOnly
标志,所以在执行某些DML之前,我无法判断是否在与只读实例对话,而这正是ER_OPTION_PREVENTS_STATEMENT
出现的时候。即使我通过调用setReadOnly(false)
并设置readOnlyPropagatesToServer
标志显式地将连接放置到读写模式,这也只会导致驱动程序将SET SESSION TRANSACTION READ WRITE
发送到服务器,这不会导致引发任何异常。
我想用尽可能少的应用程序逻辑来解决这个问题。如果有一种方法将指向只读实例的连接视为无效/关闭连接(即将其从池中驱逐),则可以实现这一点。
我能有一个http://commons.apache.org/proper/commons-dbcp/api-1.4/org/apache/commons/dbcp/BasicDataSource.html#validationQuery,如SHOW GLOBAL VARIABLES LIKE 'read_only'
,并附加一个逻辑吗?是否有可能影响池的行为w.r.t --基于验证查询返回哪个标量值的连接?
发布于 2016-09-19 00:01:07
可以使用以下验证查询:
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
由于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的答案。
https://stackoverflow.com/questions/39552146
复制相似问题