Удаление подключений к узлу кластера, доступному только для чтения, из пула подключений


Мое приложение подключается к отказоустойчивому кластеру из двух экземпляровMySQL 5.6 (фактически, Amazon Aurora ). Активный узел всегда доступен для записи, в то время как пассивный работает в read_only режим (это отличается от канонического кластера MySQL fail-over, где все подчиненные узлы доступны для записи по умолчанию). Amazon RDS предоставляет символическое DNS-имя, которое всегда указывает на IP-адрес активного MySQL узел.

Во время процесса аварийного переключения прежний ведущий узел перезапускается в режиме read_only, в то время как прежний пассивный узел становится доступным для записи и повышается до ведущего. Кроме того, записи DNS изменяются, так что DNS-имя кластера теперь указывает на новый главный узел.

Даже если я полностью отключаю кэширование DNS на стороне Java (через sun.net.inetaddr.ttl или networkaddress.cache.ttl), специфичное для ОС кэширование DNS все еще эффективно, поэтому после сбоя базы данных я в конечном итоге получаю свой пул DBCP, полный соединений только для чтения MySQL экземпляр. Эти связи таковы:valid, то есть они были получены после завершения отказа, но до истечения срока действия кэша DNS. Кроме того, ни одно из таких соединений не имеет readOnly флаг установлен, поэтому я не могу сказать, говорю ли я с экземпляром только для чтения, пока не выполню некоторый DML, который является когда ER_OPTION_PREVENTS_STATEMENT приходит во всей своей красе. Даже если я явно поставил соединение в режим чтения-записи, вызвав setReadOnly(false) и установить readOnlyPropagatesToServer флаг, это приводит только к отправке драйвера SET SESSION TRANSACTION READ WRITE на сервер, что не приводит ни к какому исключению.

Я хотел бы решить эту проблему с наименьшим влиянием логики приложения, насколько это возможно. Это можно было бы сделать, если бы существовал способ рассматривать соединение с экземпляром, доступным только для чтения, как недопустимое/закрытое соединение (т. е. исключить его из пула).

Могу ли я получить запрос проверки например, SHOW GLOBAL VARIABLES LIKE 'read_only' с дополнительной логикой, связанной с этим? Можно ли повлиять на поведение пула w.r. t соединение, на основе которого скалярное значение возвращает запрос проверки?

1 3

1 ответ:

Можно использовать следующий запрос проверки:

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`

Вдохновленныйэтим ответом.