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 в том, чтобы выполнить автоматический переход на другой ресурс.
Но если я вынужден убить слушателя

  1. Это не то, что я ожидал:)
  2. Переключение может не работать, так как для этого используются слушатели

Если у кого-то есть подсказка относительно правильной конфигурации, мне интересно!

Заранее спасибо.

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 секунд, если вам не повезло.

Но мы тестировали его в течение нескольких дней, и он работает как шарм.

Если у кого-то есть правильное решение или лучшая идея, не стесняйтесь! Благодарю.

Служба может быть создана с одинаковым именем как в основном, так и в режиме ожидания. Соединение можно изменить с помощью имени службы. Поддерживайте сервис только на текущем первичном.

Другие вопросы по тегам