Удаление подключений к узлу кластера, доступному только для чтения, из пула подключений
Мое приложение подключается к отказоустойчивому кластеру из двух экземпляров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 ответ:
Можно использовать следующий запрос проверки:
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`
Вдохновленныйэтим ответом.