Oracle: Соединение URL JSBC TNS не будет переключаться при сбое, потому что слушатель все еще отвечает
Я сталкиваюсь с глупой проблемой, но через некоторое время поиска в Интернете и экспериментов, я начинаю терять надежду.
У меня есть две базы данных Oracle, которые настроены на реплики, благодаря Dataguard.
Я использую URL-адрес JDBC TNS для подключения к моим базам данных, например:
jdbc: oracle: thin: @ (DESCRIPTION_LIST = (FAILOVER = on) (LOAD_BALANCE = off) (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST =DB1) основной (PORT=1521)) (CONNECT_DATA= (SERVER=DEDICATED)) (SID=MySID))) (ОПИСАНИЕ = (АДРЕС = (PROTOCOL = TCP) (HOST =DB2) вторичный (PORT = 1521)) (CONNECT_DATA = (SERVER = ВЫДЕЛЕНО) (SID=MySID))))
Когда я выполняю переключение, роли меняются: DB1 становится вторичным, а DB2 становится первичным. DB1 находится в состоянии монтирования.
Все идет нормально.
Но с моим URL-адресом соединения я ожидаю получить соединение от DB2, которое стало основным, но поскольку прослушиватель DB1 все еще работает, он действует так, как будто все в порядке, и я в итоге пытаюсь установить соединение с DB1, что приводит к следующей ошибке:
ORA-01033: инициализация или завершение работы ORACLE
Если я убью слушателя, аварийное переключение сработает, и я получу соединение от DB2.
Но весь смысл DataGuard в том, чтобы выполнить автоматический переход на другой ресурс.
Но если я вынужден убить слушателя
- Это не то, что я ожидал:)
- Переключение может не работать, так как для этого используются слушатели
Если у кого-то есть подсказка относительно правильной конфигурации, мне интересно!
Заранее спасибо.
2 ответа
После долгих часов попыток найти правильное решение, я почти уверен, что этот механизм сильно зависит от слушателя: механизм восстановления после сбоев работает нормально, только если слушатель остановлен.
Зная это, я, наконец, решил реализовать собственное решение, не касаясь кода приложения.
Поскольку я не могу играть с оригинальными слушателями, поскольку Dataguard использует их для выполнения своих операций, я продублировал всех слушателей. Например, для LISTENER_DB1 на порту 1521 я создал LISTENER_DB1_FO (FO означает FailOver, как вы могли догадаться) на порту 1531.
Моя конфигурация с точки зрения приложения становится:
JDBC: оракул: тонкий:@ (DESCRIPTION_LIST= (FAILOVER= вкл) (LOAD_BALANCE= OFF) (ОПИСАНИЕ = (ADDRESS = (ПРОТОКОЛ =TCP) (HOST=DB1) первичный (ПОРТ =1531) (CONNECT_DATA= (SERVER= ПОСВЯЩЕННЫЙ) (SID = мизиды))) (ОПИСАНИЕ = (ADDRESS = (ПРОТОКОЛ =TCP) (HOST=DB2) вторичный (ПОРТ =1531) (CONNECT_DATA= (SERVER= ПОСВЯЩЕННЫЙ) (SID = мизиды))))
Благодаря коллеге, который немного помог мне в этом, я написал скрипт, который проверяет, является ли роль базы данных основной или нет (работает, даже если БД находится в состоянии монтирования). И из этого ответа мой скрипт запустит или остановит связанный слушатель.
#! /bin/bash
export ORACLE_HOME=<YOUR_HOME>
export ORACLE_BIN=$ORACLE_HOME/bin/
DATABASE_ROLE() {
export ORACLE_SID=$1
request='SELECT DATABASE_ROLE FROM V$DATABASE'
result=`$ORACLE_BIN/sqlplus -silent / as sysdba << EOF
set pages 0 feedback off
${request};
exit
EOF`
echo ${result}
}
for DBNAME in DB1 DB2 DB3
do
$ORACLE_BIN/lsnrctl status LISTENER_${DBNAME}_FO > /dev/null
return_status=$?
if [ "$(DATABASE_ROLE ${DBNAME})" != 'PRIMARY' ];then
echo "DB ${DBNAME} is secondary"
if [ $return_status -eq 0 ];then
$ORACLE_BIN/lsnrctl stop LISTENER_${DBNAME}_FO
fi
else
echo "DB ${DBNAME} is primary"
if [ $return_status -eq 1 ];then
$ORACLE_BIN/lsnrctl start LISTENER_${DBNAME}_FO
fi
fi
done
Затем я создал этот сценарий. Единственный "недостаток" заключается в том, что минимальный интервал между двумя выполнениями cron составляет одну минуту. Ваше обнаружение FailOver может занять 59 секунд, если вам не повезло.
Но мы тестировали его в течение нескольких дней, и он работает как шарм.
Если у кого-то есть правильное решение или лучшая идея, не стесняйтесь! Благодарю.
Служба может быть создана с одинаковым именем как в основном, так и в режиме ожидания. Соединение можно изменить с помощью имени службы. Поддерживайте сервис только на текущем первичном.