CascadiaPHP 2024

Поддержка прозрачного для приложений восстановления после отказа (Transparent Application Failover или TAF) для OCI8

TAF — функция базы данных Oracle, которая обеспечивает высокую доступность. TAF помогает OCI8-приложениям PHP автоматически переподключаться к предварительно настроенной базе данных при сбое подключения к базе данных из-за сбоя экземпляра или сети.

В сконфигурированной системе базы данных Oracle TAF-обработка происходит, когда PHP-приложение обнаруживает, что экземпляр базы данных не работает или недоступен. Он устанавливает соединение с другим узлом в конфигурации Oracle » RAC, базой данных горячего резерва или самим экземпляром базы данных. Подробнее об OCI TAF рассказывает краткое руководство » Oracle Call Interface Programmer's Guide.

Callback-функцию приложения регистрируют функцией oci_register_taf_callback(). В процессе восстановления после отказа исполнение приложения приостанавливается и вызывается зарегистрированная callback-функция. Эта функция будет оповещать приложение о событиях процесса восстановления. Если восстановление завершилось успешно, управление возвращается приложению. Если восстановление завершилось неудачно, то очередные обращения к базе данных завершаются с ошибкой, поскольку отсутствует подключение.

Когда соединение переходит к другой базе данных, обратный вызов может сбросить любое необходимое состояние соединения, например, перевыполнить необходимую команду ALTER SESSION, если для сервиса базы данных не включили параметр -failover_restore.

Регистрацию callback-функции приложения удаляют вызовом функции oci_unregister_taf_callback().

настройка TAF

TAF настраивают на стороне PHP-модуля OCI8 или в конфигурации базы данных. Если настроено и там, и там, предпочтение отдаётся настройкам на стороне базы данных.

Настроить TAF в PHP-модуле OCI8 (на стороне клиента) можно через параметр FAILOVER_MODE в части CONNECT_DATA дескриптора соединения. Подробнее о настройке TAF на стороне клиента рассказывает секция «Настройка прозрачного переключения приложений при отказе» (Configuring Transparent Application Failover) краткого руководства »  Oracle Database Net Services Administrator's Guide.

Пример настройки TAF в файле tnsnames.ora для переподключения к той же самой БД:

    ORCL =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
        (CONNECT_DATA =
          (SERVICE_NAME = orclpdb1)
          (FAILOVER_MODE =
            (TYPE = SELECT)
            (METHOD = BASIC)
            (RETRIES = 20)
            (DELAY = 15))))

TAF также настраивается на стороне базы данных путём изменения целевой службы утилитой » srvctl (для RAC) или через пакетную процедуру »  DBMS_SERVICE.MODIFY_SERVICE (для одиночных экземпляров баз данных).

Callback-функции TAF в модуле OCI8

Callback-функция TAF — функция приложения, которую можно зарегистрировать для вызова во время аварийного переключения. При восстановлении соединения функция вызывается несколько раз.

Первый раз функция запускается в момент обнаружения проблем с соединением. Это позволяет приложению корректно подготовиться к задержке выполнения на время восстановления после сбоя. Если восстановление завершилось успешно, функция вызывается сразу после восстановления подключения. Этот запуск приложение может использовать для пересинхронизации настроек сессии и оповещения пользователя о восстановлении после сбоя. Если восстановление не удалось, callback-функция запускается ещё раз, чтобы сообщить приложению, что восстановление не произошло и соединение невозможно использовать.

Интерфейс callback-функции модуля TAF:

userCallbackFn(resource $connection, int $event, int $type): int

connection

Идентификатор соединения Oracle, на котором функцией oci_register_taf_callback() зарегистрировали callback-функцию TAF. Соединение недействительно, пока восстановление не завершится успешно.

event

Событие восстановления означает текущий статус восстановления.

  • OCI_FO_BEGIN означает, что произошла потеря соединения и процесс восстановления начат.

  • OCI_FO_END означает удачное восстановление соединения.

  • OCI_FO_ABORT означает, что восстановление завершилось неудачно и попыток восстановления больше не будет.

  • OCI_FO_ERROR также означает, что восстановление завершилось с ошибкой, но приложению даётся возможность обработать ошибку и вернуть OCI_FO_RETRY для ещё одной попытки восстановления.

  • OCI_FO_REAUTH означает, что пользователь Oracle был повторно аутентифицирован.

type

Тип восстановления после отказа. Это позволяет функции понять, какой тип восстановления запрошен приложением. Допустимы такие значения:

  • OCI_FO_SESSION означает, что пользователь запросил только восстановление сессии. К примеру, если соединение пропало, то будет создана новая сессия на резервном сервере. Этот тип восстановления не будет пытаться восстановить запросы типа SELECT.

  • OCI_FO_SELECT означает, что запрошено восстановление запросов SELECT. Это позволит использовать открытый курсор для извлечения значений после восстановления.

return value

  • 0 означает, что шаги восстановления после отказа должны продолжаться нормально.

  • OCI_FO_RETRY означает, что необходимо попробовать восстановиться ещё раз. В случае возникновения ошибки при переходе на новое соединение TAF может повторить переход на другой ресурс. Обычно перед возвращением кода OCI_FO_RETRY рекомендуется некоторое время подождать.

Пример #1 Регистрация callback-функции TAF

<?php

// Определяем callback-функцию в пространстве пользователя
class MyClass
{
public static
$retry_count;

public static function
TAFCallback($conn, $event, $type)
{
switch (
$event) {
case
OCI_FO_BEGIN:
printf(" Failing Over ... Please stand by\n");
printf(" Failover type was found to be %s \n",
((
$type==OCI_FO_SESSION) ? "SESSION"
:(($type==OCI_FO_SELECT) ? "SELECT" : "UNKNOWN!")));
self::$retry_count = 0;
break;
case
OCI_FO_ABORT:
// Приложение больше не может использовать базу данных
printf(" Восстановление невозможно.\n");
break;
case
OCI_FO_END:
// Восстановление завершилось успешно. Оповестим пользователей, что была проблема.
printf(" Восстановление завершено ... восстанавливаю работу\n");
break;
case
OCI_FO_REAUTH:
printf(" Пользователь переавторизован ... восстанавливаю работу\n");
// Заново выполняем все необходимые ALTER SESSION
// т.е. oci_parse($conn, ‘ALTER SESSION …’) ;
break;
case
OCI_FO_ERROR:
// Прекращаем попытки соединения, если их было более 20.
if (self::$retry_count >= 20)
return
0;
printf(" Ошибка восстановления. Повторная попытка через 10 секунд...\n");
sleep(10);
self::$retry_count++;
return
OCI_FO_RETRY; // retry failover
break;
default:
printf("Неизвестное событие восстановления: %d.\n", $event);
break;
}
return
0;
}
}

$fn_name = 'MyClass::TAFCallback';

$conn = oci_connect('hr', 'welcome', 'orcl');
$sysconn = oci_connect('system', 'oracle', 'orcl');

// Используйте привилегированное соединение для создания SQL-запроса, который инициирует отработку отказа
$sql = <<< 'END'
select unique 'alter system disconnect session '''||sid||','||serial#||''''
from v$session_connect_info
where sid = sys_context('USERENV', 'SID')
END;

$s = oci_parse($conn, $sql);
oci_execute($s);
$r = oci_fetch_array($s);
$disconnectssql = $r[0];

oci_register_taf_callback($conn, $fn_name); // Зарегистрируйте TAFCallback для Oracle TAF

print "Разбор пользовательского запроса\n";
$sql = "select systimestamp from dual";
$stmt = oci_parse($conn, $sql);

// Например, если соединение было потеряно на этом шаге, функция oci_execute()
// определит это и запустит процедуру восстановления. В процессе восстановления
// функция oci_execute() будет вызывать зарегистрированную callback-функцию
// несколько раз. Если восстановление пройдёт успешно, callback-функция создаст новое соединение
// и выполнение функции oci_execute() продолжится в нормальном режиме.
// Настройки сессии могут быть сброшены в callback-функции.
// Если восстановление завершится неудачно, функция oci_execute() вернёт ошибку,
// поскольку будет отсутствовать соединение.

// Отключите пользователя, который инициирует аварийное переключение
print "Отключение пользователя\n";
$discsql = oci_parse($sysconn, $disconnectssql);
oci_execute($discsql);

print
"Выполнение пользовательского запроса\n";
$e = oci_execute($stmt);
if (!
$e) {
$m = oci_error($stmt);
trigger_error('Не удалось выполнить условие:'. $m['message'], E_USER_ERROR);
}
$row = oci_fetch_array($stmt);
print
$row[0] . "\n";

// Выполняем другие SQL-запросы на новом подключении
// $stmt = oci_parse($conn, . . .);

?>
add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top