mirror of
https://github.com/php/doc-ru.git
synced 2025-07-22 18:26:31 +00:00
352 lines
17 KiB
XML
352 lines
17 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: 28529d3539b850e870e3aa97570f4db0e53daa03 Maintainer: rjhdby Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<chapter xml:id="oci8.taf" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>Поддержка прозрачного для приложений восстановления после отказа (Transparent Application Failover или TAF) для OCI8</title>
|
||
<section>
|
||
<para>
|
||
TAF — это механизм базы данных Oracle обеспечивающий высокую доступность.
|
||
Он позволяет приложениям PHP использующим OCI8 автоматически переподключаться
|
||
к резервной базе данных в случае сбоя на основной или при сетевых проблемах..
|
||
</para>
|
||
<para>
|
||
В сконфигурированной системе базы данных Oracle, TAF происходит когда
|
||
приложение PHP определяет, что экземпляр базы данных недоступен.
|
||
В этом случае происходит соединение с другим узлом в
|
||
Oracle <link xlink:href="&url.oracle.taf.rac;">RAC</link>. Это может быть горячий
|
||
резерв или тот же самый экземпляр базы данных. Более подробно о OCI TAF
|
||
читайте в <link xlink:href="&url.oracle.taf.ociguide;">Oracle
|
||
Call Interface Programmer's Guide</link>.
|
||
</para>
|
||
<para>
|
||
Функцию обратного вызова для приложения можно зарегистрировать с помощью
|
||
<function>oci_register_taf_callback</function>. В процессе восстановления после
|
||
отказа исполнение приложения будет приостановлено и будет вызвана зарегистрированная
|
||
функция обратного вызова. Эта функция будет оповещать приложение о событиях
|
||
процесса восстановления. Если восстановление завершилось успешно, управление будет
|
||
возвращено приложению. Если восстановление завершилось неудачно, то все последующие
|
||
обращения к базе данных будут завершаться с ошибкой, так как отсутствует подключение.
|
||
</para>
|
||
<para>
|
||
Когда соединение переходит к другой базе данных, обратный вызов может сбросить
|
||
любое необходимое состояние соединения, к примеру перевыполнить любую
|
||
необходимую команду ALTER SESSION если для сервиса базы данных не включён
|
||
-failover_restore.
|
||
</para>
|
||
<para>
|
||
Регистрацию функции обратного вызова можно удалить с помощью <function>oci_unregister_taf_callback</function>.
|
||
</para>
|
||
</section>
|
||
<section>
|
||
<title>настройка TAF</title>
|
||
<para>
|
||
TAF можно настроить на стороне PHP OCI8 или в конфигурации базы данных.
|
||
Если настроено и там и там, то предпочтение отдаётся настройкам на стороне базы данных.
|
||
</para>
|
||
<para>
|
||
Настроить TAF в PHP OCI8 (на стороне клиента) можно добавив параметр
|
||
FAILOVER_MODE в часть CONNECT_DATA дескриптора соединения.
|
||
Более подробно о настройке TAF на стороне клиента читайте в
|
||
<link xlink:href="&url.oracle.taf.clientconfig;">
|
||
Oracle Database Net Services Administrator's Guide</link>.
|
||
</para>
|
||
<para>
|
||
Пример настройки TAF в tnsnames.ora для переподключения к той же самой БД:
|
||
</para>
|
||
<para>
|
||
<informalexample>
|
||
<screen>
|
||
<![CDATA[
|
||
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))))
|
||
]]>
|
||
</screen>
|
||
</informalexample>
|
||
</para>
|
||
<para>
|
||
Также можно настроить TAF на стороне базы данных путём модификации сервиса
|
||
с помощью <link xlink:href="&url.oracle.taf.srvctl;">srvctl</link>
|
||
(для RAC) или с помощью пакетной процедуры
|
||
<link xlink:href="&url.oracle.taf.dbmsservice;">
|
||
DBMS_SERVICE.MODIFY_SERVICE</link>
|
||
(для одиночных экземпляров баз данных).
|
||
</para>
|
||
</section>
|
||
<section>
|
||
<title>Использование функций обратного вызова TAF в OCI8</title>
|
||
<para>
|
||
Функция обратного вызова TAF являются функцией зарегистрированной из приложения
|
||
для запуска в процессе восстановления после сбоя. При восстановлении соединения она
|
||
вызывается несколько раз.
|
||
</para>
|
||
<para>
|
||
Первый раз она запускается в момент обнаружения проблем с соединением.
|
||
Это позволяет приложению корректно подготовиться к задержке выполнения
|
||
на время восстановления после сбоя. Если восстановление завершилось удачно,
|
||
функция будет вызвана сразу после восстановления подключения. Этот запуск
|
||
приложение может использовать для пересинхронизации настроек сессии и оповещения
|
||
пользователя о том, что произошло восстановление после сбоя. Если восстановление
|
||
завершилось неудачно, функция запускается ещё раз для оповещения приложения о
|
||
том, что восстановление завершилось с ошибкой и соединение с БД недоступно.
|
||
</para>
|
||
<para>
|
||
Интерфейс функции обратного вызова TAF:
|
||
</para>
|
||
<methodsynopsis>
|
||
<type>int</type><methodname>userCallbackFn</methodname>
|
||
<methodparam><type>resource</type><parameter>connection</parameter></methodparam>
|
||
<methodparam><type>int</type><parameter>event</parameter></methodparam>
|
||
<methodparam><type>int</type><parameter>type</parameter></methodparam>
|
||
</methodsynopsis>
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term><parameter>connection</parameter></term>
|
||
<listitem>
|
||
<para>
|
||
Идентификатор соединения Oracle для которого эта функция
|
||
была зарегистрирована с помощью <function>oci_register_taf_callback</function>.
|
||
Соединение недоступно во время аварийного восстановления.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term><parameter>event</parameter></term>
|
||
<listitem>
|
||
<para>
|
||
Событие восстановления означает текущий статус восстановления.
|
||
</para>
|
||
<para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_BEGIN</constant> означает, что произошла потеря
|
||
соединения и процесс восстановления начат.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_END</constant> означает удачное восстановление соединения.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_ABORT</constant> означает, что восстановление завершилось
|
||
неудачно и попыток восстановления больше не будет.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_ERROR</constant> также означает, что восстановление
|
||
завершилось с ошибкой, но приложению даётся возможность обработать
|
||
ошибку и вернуть OCI_FO_RETRY для ещё одной попытки восстановления.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_REAUTH</constant> означает, что пользователь
|
||
Oracle был повторно аутентифицирован..
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term><parameter>type</parameter></term>
|
||
<listitem>
|
||
<para>
|
||
Тип восстановления после отказа. Это позволяет функции понять,
|
||
какой тип восстановления запрошен приложением. Допустимы такие значения:
|
||
</para>
|
||
<para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_SESSION</constant> означает, что пользователь
|
||
запросил только восстановление сессии. К примеру, если соединение пропало,
|
||
то будет создана новая сессия на резервном сервере. Этот тип восстановления
|
||
не будет пытаться восстановить запросы типа SELECT.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_SELECT</constant> означает, что запрошено восстановление
|
||
запросов SELECT. Это позволит использовать открытый курсор для
|
||
извлечения значений после восстановления.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term><parameter>return value</parameter></term>
|
||
<listitem>
|
||
<para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
<constant>0</constant> означает, что шаги восстановления после отказа должны
|
||
продолжаться нормально.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<constant>OCI_FO_RETRY</constant> означает, что необходимо попробовать
|
||
восстановиться ещё раз. В случае возникновения ошибки при переходе на новое соединение TAF
|
||
может повторить переход на другой ресурс. Обычно перед возвращением кода
|
||
OCI_FO_RETRY рекомендуется некоторое время подождать.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</para>
|
||
<example>
|
||
<para>
|
||
Пример регистрации функции обратного вызова TAF
|
||
</para>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Определяем функцию обратного вызова в пространстве пользователя
|
||
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() будет вызовать зарегистрированную функцию обратного вызова
|
||
// несколько раз. Если восстановление пройдёт успешно, то будет создано новое соединение
|
||
// и выполнение oci_execute() будет продолжено в нормальном режиме.
|
||
// Настройки сессии могут быть сброшены в функции обратного вызова.
|
||
// Если восстановление завершится неудачно, 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, . . .);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</section>
|
||
|
||
<section>
|
||
&reftitle.seealso;
|
||
<simplelist>
|
||
<member><function>oci_register_taf_callback</function></member>
|
||
<member><function>oci_unregister_taf_callback</function></member>
|
||
</simplelist>
|
||
</section>
|
||
|
||
|
||
</chapter>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|