java - 从连接池中逐出到集群中只读节点的连接

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

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

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

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

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

我可以要一个validation query吗?例如 SHOW GLOBAL VARIABLES LIKE 'read_only' 有附加的逻辑吗?是否有可能根据验证查询返回的标量值影响池的行为 w.r.t 连接?

最佳答案

可以使用以下验证查询:

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回答。

关于java - 从连接池中逐出到集群中只读节点的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39552146/

相关文章:

java - 在网格布局中垂直和水平缩放图像

java - 如何动态更改 ImageView (JavaFX) 中的图像?

java - 无法以编程方式滚动到 JList 中的最后一项

java - Spring 和 Hibernate 配置错误无法从 URL 位置导入 bean 定义

java - 为多个 Web 服务请求保持连接打开

java - c3p0中的资源无法 check out 的原因是什么?

php - 新闻脚本插入新闻数据,但不编辑新闻

mysql - 如何从列值匹配的表中查找特定的列名?

Java 插入到 mySQL 工作台

activemq - ActiveMQ的连接池