从连接池中逐出到集群中只读节点的连接
Evicting connections to a read-only node in a cluster from the connection pool
我的应用程序连接到两个 MySQL 5.6(实际上,Amazon Aurora)实例的故障转移集群。主动节点始终是可写访问的,而被动节点在 read_only
模式下是 运行(这不同于规范的 MySQL 失败-在集群上,默认情况下所有从节点都是可写访问的)。 Amazon RDS 提供一个符号 DNS 名称,它始终指向活动 MySQL 节点的 IP 地址。
在故障转移过程中,之前的主节点以read_only
模式重新启动,而之前的被动节点变为可写访问并提升为主节点。此外,DNS 记录已更改,因此集群的 DNS 名称现在指向新的主节点。
即使我在 Java 端完全禁用 DNS 缓存(通过 sun.net.inetaddr.ttl
或 networkaddress.cache.ttl
),OS 特定的 DNS 缓存仍然有效,所以在数据库故障转移 我最终让我的 DBCP 池充满了到只读 MySQL 实例的连接。这些连接是 valid
, i. e. they have been obtained after the fail-over completed but before the DNS cache expired. Additionally, none of such connections has readOnly
flag set, so I can't tell whether I'm talking to a read-only instance until I execute some DML, which is when ER_OPTION_PREVENTS_STATEMENT
comes in all its glory. Even if I explicitly put a connection to a read-write mode by calling setReadOnly(false)
and set the readOnlyPropagatesToServer
标志,这只会导致驱动程序向服务器发送 SET SESSION TRANSACTION READ WRITE
,这不会导致抛出任何异常。
我希望尽可能少地影响应用程序逻辑来解决这个问题。如果有一种方法可以将与只读实例的连接视为 invalid/closed 连接(即将其从池中逐出)。
我可以有一个 validation query 例如 SHOW GLOBAL VARIABLES LIKE 'read_only'
附加逻辑吗?是否有可能影响池的行为 w.r.t 连接基于验证查询的标量值 returns?
可以使用以下验证查询:
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 在集群的 reader 端点上设置了 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 回答的启发。
我的应用程序连接到两个 MySQL 5.6(实际上,Amazon Aurora)实例的故障转移集群。主动节点始终是可写访问的,而被动节点在 read_only
模式下是 运行(这不同于规范的 MySQL 失败-在集群上,默认情况下所有从节点都是可写访问的)。 Amazon RDS 提供一个符号 DNS 名称,它始终指向活动 MySQL 节点的 IP 地址。
在故障转移过程中,之前的主节点以read_only
模式重新启动,而之前的被动节点变为可写访问并提升为主节点。此外,DNS 记录已更改,因此集群的 DNS 名称现在指向新的主节点。
即使我在 Java 端完全禁用 DNS 缓存(通过 sun.net.inetaddr.ttl
或 networkaddress.cache.ttl
),OS 特定的 DNS 缓存仍然有效,所以在数据库故障转移 我最终让我的 DBCP 池充满了到只读 MySQL 实例的连接。这些连接是 valid
, i. e. they have been obtained after the fail-over completed but before the DNS cache expired. Additionally, none of such connections has readOnly
flag set, so I can't tell whether I'm talking to a read-only instance until I execute some DML, which is when ER_OPTION_PREVENTS_STATEMENT
comes in all its glory. Even if I explicitly put a connection to a read-write mode by calling setReadOnly(false)
and set the readOnlyPropagatesToServer
标志,这只会导致驱动程序向服务器发送 SET SESSION TRANSACTION READ WRITE
,这不会导致抛出任何异常。
我希望尽可能少地影响应用程序逻辑来解决这个问题。如果有一种方法可以将与只读实例的连接视为 invalid/closed 连接(即将其从池中逐出)。
我可以有一个 validation query 例如 SHOW GLOBAL VARIABLES LIKE 'read_only'
附加逻辑吗?是否有可能影响池的行为 w.r.t 连接基于验证查询的标量值 returns?
可以使用以下验证查询:
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 在集群的 reader 端点上设置了 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 回答的启发。