TAF 是一項 Oracle 資料庫功能,可提供高可用性。它讓 PHP OCI8 應用程式在資料庫連線因執行個體或網路故障而失敗時,自動重新連線到預先設定的資料庫。
在已設定的 Oracle 資料庫系統中,當 PHP 應用程式偵測到資料庫執行個體已關閉或無法連線時,就會發生 TAF。它會建立與 Oracle » RAC 設定中的另一個節點、熱備援資料庫或相同資料庫執行個體本身的連線。詳情請參閱 » Oracle 呼叫介面程式設計師指南 以取得關於 OCI TAF 的更多資訊。
應用程式回呼函式可以使用 oci_register_taf_callback() 註冊。在故障轉移期間,正常的應用程式處理會停止,並呼叫已註冊的回呼函式。該回呼函式會將故障轉移事件通知應用程式。如果故障轉移成功,則會繼續正常處理。如果故障轉移中止,則應用程式中後續的任何資料庫操作都將失敗,因為沒有可用的連線。
當連線故障轉移到另一個資料庫時,回呼函式可以重設任何必要的連線狀態,例如,如果資料庫服務未啟用 -failover_restore,則重新執行任何必要的 ALTER SESSION 命令。
可以透過呼叫 oci_unregister_taf_callback() 來移除應用程式回呼函式。
TAF 可以在 PHP OCI8 端或資料庫設定中設定。如果兩者都已設定,則以資料庫端設定優先。
在 PHP OCI8(用戶端)中設定 TAF,方法是在連線描述元的 CONNECT_DATA 部分中加入 FAILOVER_MODE 參數。有關 TAF 用戶端設定的更多資訊,請參閱《Oracle Database Net Services 管理員指南》中的設定透明應用程式故障轉移 ( » Oracle Database Net Services 管理員指南 )。
tnsnames.ora 設定 TAF 重新連線到同一個資料庫實例的範例
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 封裝程序(適用於單一實例資料庫)修改目標服務。
TAF 回呼函式是一個應用程式函式,可以註冊在故障轉移期間被呼叫。在重新建立應用程式連線時,它會被呼叫多次。
當偵測到連線中斷時,會先發生回呼。這允許應用程式針對即將發生的故障轉移延遲採取相應的行動。如果故障轉移成功,則在連線重新建立且可用後會呼叫回呼函式。此時,應用程式可以重新同步會話設定,並採取一些動作,例如通知使用者已發生故障轉移。如果故障轉移失敗,則會發生回呼,通知應用程式故障轉移未發生且連線無法使用。
TAF 使用者定義回呼函式的介面如下:
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 使用者已重新驗證。
類型
故障轉移類型。這讓回呼函式知道應用程式請求的故障轉移類型。通常的值如下:
OCI_FO_SESSION
表示使用者僅請求工作階段故障轉移。例如,如果使用者的連線斷開,則會在備份伺服器上自動為使用者建立新的工作階段。這種故障轉移類型不會嘗試恢復 SELECT 陳述式。
OCI_FO_SELECT
表示使用者也請求了 SELECT 故障轉移。它允許具有開啟游標的使用者在故障後繼續從中擷取資料。
傳回值
0
表示故障轉移步驟應正常繼續。
OCI_FO_RETRY
表示 Oracle 應再次嘗試故障轉移。如果在故障轉移到新連線時發生錯誤,TAF 可以重試故障轉移。通常,應用程式程式碼應在返回 OCI_FO_RETRY 之前休眠一段時間。
範例 #1 註冊 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, . . .);
?>