OCI8 투명 애플리케이션 장애 조치(TAF) 지원

TAF는 고가용성을 제공하는 Oracle 데이터베이스 기능입니다. 이를 통해 PHP OCI8 애플리케이션은 인스턴스 또는 네트워크 장애로 인해 데이터베이스 연결이 실패할 때 사전 구성된 데이터베이스에 자동으로 다시 연결할 수 있습니다.

구성된 Oracle Database 시스템에서 TAF는 PHP 애플리케이션이 데이터베이스 인스턴스가 다운되었거나 연결할 수 없음을 감지할 때 발생합니다. Oracle » RAC 구성, 상시 대기 데이터베이스 또는 동일한 데이터베이스 인스턴스 자체의 다른 노드에 대한 연결을 설정합니다. OCI TAF에 대한 자세한 내용은 » Oracle Call Interface Programmer's Guide를 참조하세요.

애플리케이션 콜백은 oci_register_taf_callback()으로 등록할 수 있습니다. 장애 조치 중에 정상적인 응용 프로그램 처리가 중지되고 등록된 콜백이 호출됩니다. 콜백은 장애 조치 이벤트를 애플리케이션에 알립니다. 장애 조치가 성공하면 정상 처리가 재개됩니다. 장애 조치가 중단되면 사용 가능한 연결이 없기 때문에 애플리케이션에서 다음 데이터베이스 작업이 실패합니다.

연결이 다른 데이터베이스로 장애 조치되면 콜백은 필요한 연결 상태를 재설정할 수 있습니다. 예를 들어 데이터베이스 서비스에 -failover_restore가 활성화되어 있지 않은 경우 필요한 ALTER SESSION 명령을 재생합니다.

oci_unregister_taf_callback()을 호출하여 애플리케이션 콜백을 제거할 수 있습니다.


투명한 애플리케이션 장애 조치 구성

TAF는 PHP OCI8 측 또는 데이터베이스 구성에서 구성할 수 있습니다. 둘 다 구성된 경우 데이터베이스 측 설정이 우선합니다.

연결 설명자의 CONNECT_DATA 부분에 FAILOVER_MODE 매개변수를 포함하여 PHP OCI8(클라이언트 측)에서 TAF를 구성합니다. TAF의 클라이언트 측 구성에 대한 자세한 내용은 » 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))))
                

또는 » srvctl(RAC용) 또는 » DBMS_SERVICE.MODIFY_SERVICE 패키지 프로시저(단일 인스턴스 데이터베이스용)를 사용하여 대상 서비스를 수정하여 데이터베이스 측에서 TAF를 구성합니다.


OCI8에서 TAF 콜백 사용

TAF 콜백은 장애 조치 중에 호출되도록 등록할 수 있는 응용 프로그램 함수입니다. 응용 프로그램의 연결을 다시 설정하는 동안 여러 번 호출됩니다.

연결 끊김이 감지되면 콜백이 먼저 발생합니다. 이를 통해 애플리케이션은 다가오는 장애 조치 지연에 따라 적절하게 작동할 수 있습니다. 장애 조치가 성공하면 연결이 다시 설정되고 사용 가능한 후에 콜백이 호출됩니다. 이때 애플리케이션은 세션 설정을 재동기화하고 사용자에게 장애 조치(failover)가 발생했음을 알리는 등의 조치를 취할 수 있습니다. 장애 조치가 실패하면 장애 조치가 발생하지 않았으며 연결을 사용할 수 없음을 애플리케이션에 알리는 콜백이 발생합니다.

TAF 사용자 정의 콜백 함수의 인터페이스는 다음과 같습니다.

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

connection
oci_register_taf_callback()을 통해 TAF 콜백이 등록된 Oracle 연결입니다. 장애 조치가 성공적으로 완료될 때까지 연결이 유효하지 않습니다.
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는 Oracle에서 페일오버를 다시 시도해야 함을 나타냅니다. 새 연결로 장애 조치하는 동안 오류가 발생하는 경우 TAF는 장애 조치를 재시도할 수 있습니다. 일반적으로 애플리케이션 코드는 OCI_FO_RETRY를 반환하기 전에 잠시 동안 휴면해야 합니다.

다음 예에서는 TAF 콜백을 등록합니다.

                  
<?php

// Define userspace 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:
                // The application cannot continue using the database
                printf(" Failover aborted. Failover will not take place.\n");
                break;
            case OCI_FO_END:
                // Failover completes successfully. Inform users a failover occurs.
                printf(" Failover ended ... resuming services\n");
                break;
            case OCI_FO_REAUTH:
                printf(" Failed over user ... resuming services\n");
                // Replay any ALTER SESSION commands associated with this connection
                // eg. oci_parse($conn, ‘ALTER SESSION …’) ;
                break;
            case OCI_FO_ERROR:
                // Stop retrying if we have already attempted for 20 times.
                if (self::$retry_count >= 20)
                    return 0;
                printf(" Failover error received. Sleeping...\n");
                sleep(10);
                self::$retry_count++;
                return OCI_FO_RETRY; // retry failover
                break;
            default:
                printf("Bad Failover Event: %d.\n", $event);
                break;
        }
        return 0;
    }
}

$fn_name = 'MyClass::TAFCallback';

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

// Use a privileged connection to construct a SQL statement that will initiate failover
$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); // Register TAFCallback to Oracle TAF

print("Parsing user query\n");
$sql = "select systimestamp from dual";
$stmt = oci_parse($conn, $sql);

// For example, if a connection loss occurs at this point, oci_execute() will
// detect the loss and failover begins. During failover, oci_execute() will
// invoke the TAF callback function several times. If the failover is successful,
// a new connection is transparently created and oci_execute() will continue as
// usual. The connection session settings can be reset in the TAF callback
// function. If the failover is aborted, oci_execute() will return an error
// because a valid connection is not available.

// Disconnect the user, which initiates failover
print("Disconnecting the user\n");
$discsql = oci_parse($sysconn, $disconnectssql);
oci_execute($discsql);

print("Executing user query\n");
$e = oci_execute($stmt);
if (!$e) {
    $m = oci_error($stmt);
    trigger_error("Could not execute statement: ". $m['message'], E_USER_ERROR);
}
$row = oci_fetch_array($stmt);
print($row[0] . "\n");

// do other SQL statements with the new connection, if it is valid
// $stmt = oci_parse($conn,  . . .);

?>
                  
                

기타