【UCP】理解TAF和FCF(重點是UCP)

xysoul_雲龍發表於2021-01-21

In this Document


Purpose

Scope

Details

Transparent Application Failover (TAF)

Fast Connection Failover (FCF)

References

APPLIES TO:

JDBC - Version 10.1.0.2 to 11.2.0.4.0 [Release 10.1 to 11.2]
Oracle Database - Enterprise Edition - Version 11.2.0.4 to 11.2.0.4 [Release 11.2]
Information in this document applies to any platform.

PURPOSE

This note is intended to give explanation on two RAC concepts, Transparent Application Failover (TAF) and Fast Connection Failover (FCF).

 

SCOPE

Need to have an understanding of JDBC.

DETAILS

Transparent Application Failover (TAF)

  • What does TAF mean?
    Transparent Application Failover (TAF) or simply Application Failover is a feature of the OCI driver. It enables you to automatically reconnect to a database if the database instance to which the connection is made goes down. In this case, the active transactions roll back. A transaction rollback restores the last committed transaction. The new database connection, though created by a different node, is identical to the original. This is true regardless of how the connection was lost.
    TAF is always active and does not have to be set. 
    TAF cannot be used with thin driver. 


  • What exactly is the use of TAF?
    TAF provides automatic transfer to the other instance when the first one fails. 
    For additional details regarding OCI and TAF, see the  Oracle® Call Interface Programmer's Guide


  • How do we use TAF with JDBC driver?
    You need to set up the following service in your  tnsnames.ora
    <PRIMARY TNS ENTRY> =(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(Host=<HOSTNAME1>)(Port=<PORT>)) (ADDRESS = (PROTOCOL = TCP)(HOST=<HOSTNAME2>)(PORT=<PORT>))
    (CONNECT_DATA=(SERVICE_NAME=<SERVICE NAME>)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC))))
    Please see  Oracle® Database Net Services Administrator's Guide section:   for more detail about failover_mode. 

    Failover Type Events 

    The following are possible failover types in the OracleOCI Failover interface: 
    • FO_SESSION
      Is equivalent to FAILOVER_MODE=SESSION in the tnsnames.ora file CONNECT_DATA flags. This means that only the user session is re-authenticated on the server-side while open cursors in the OCI application need to be re-executed.

    • FO_SELECT
      Is equivalent to FAILOVER_MODE=SELECT in tnsnames.ora file CONNECT_DATA flags. This means that not only the user session is re-authenticated on the server-side, but open cursors in the OCI can continue fetching. This implies that the client-side logic maintains fetch-state of each open cursor.

    • FO_NONE
      Is equivalent to FAILOVER_MODE=NONE in the tnsnames.ora file CONNECT_DATA flags. This is the default, in which no failover functionality is used. This can also be explicitly specified to prevent failover from happening. Additionally, FO_TYPE_UNKNOWN implies that a bad failover type was returned from the OCI driver.


    The following are possible failover events in the OracleOCI Failover interface: 
    • FO_BEGIN
      Indicates that failover has detected a lost connection and failover is starting.

    • FO_END
      Indicates successful completion of failover.

    • FO_ABORT
      Indicates that failover was unsuccessful and there is no option of retrying.

    • FO_REAUTH
      Indicates that a user handle has been re-authenticated.

    • FO_ERROR
      Indicates that failover was temporarily un-successful, but it gives the application the opportunity to handle the error and retry failover. The usual method of error handling is to issue the sleep() method and retry by returning the value FO_RETRY.

    • FO_RETRY
      Indicates that the application should retry failover.

    • FO_EVENT_UNKNOWN
      A bad failover event.

    TAF Callbacks 
    TAF callbacks are used in the event of the failure of one database connection, and failover to another database connection. TAF callbacks are callbacks that are registered in case of failover. The callback is called during the failover to notify the JDBC application of events generated. The application also has some control of failover.
  • TAF callbacks are documented in the  Oracle® Database JDBC Developer's Guide in the section:   
    Note:  The callback setting is optional.

    Java TAF Callback Interface 
    The OracleOCI Failover interface includes the callbackFn() method supporting the following types and events: 
    public interface OracleOCIFailover{

    // Possible Failover Types
    public static final int FO_SESSION = 1;
    public static final int FO_SELECT  = 2;
    public static final int FO_NONE  = 3;
    public static final int;

    // Possible Failover events registered with callback
    public static final int FO_BEGIN   = 1;
    public static final int FO_END     = 2;
    public static final int FO_ABORT   = 3;
    public static final int FO_REAUTH  = 4;
    public static final int FO_ERROR  = 5;
    public static final int FO_RETRY  = 6;
    public static final int FO_EVENT_UNKNOWN = 7;

    public int callbackFn (Connection conn,
                           Object ctxt, // ANy thing the user wants to save
                           int type, // One of the possible Failover Types
                           int event ); // One of the possible Failover Events

  • Sample code to test TAF
    Please see the sample for TAF below, it has been picked from the JDBC Standard sample that is available on OTN. 
    /* 
     * This sample demonstrates the registration and operation of
     * JDBC OCI application failover callbacks
     * 
     * Note: Before you run this sample, set up the following
     *       service in tnsnames.ora: 
     *       <PRIMARY TNS ENTRY>=(DESCRIPTION=
     *             (ADDRESS=(PROTOCOL=tcp)(Host=<HOSTNAME>)(Port=<PORT>))
     *             (CONNECT_DATA=(SERVICE_NAME=<SERVICE NAME>)
     *                           (FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC))
     *             )
     *           )
     *       Please see Net8 Administrator's Guide for more detail about 
     *       failover_mode
     *
     * To demonstrate the the functionality, first compile and start up the sample,
     *    then log into sqlplus and connect /as sysdba. While the sample is still 
     *    running, shutdown the database with "shutdown abort;". At this moment, 
     *    the failover callback functions should be invoked. Now, the database can
     *    be restarted, and the interrupted query will be continued.
     *
     */

    // You need to import java.sql and oracle.jdbc packages to use
    // JDBC OCI failover callback 

    import java.sql.*;
    import java.net.*;
    import java.io.*;
    import java.util.*;
    import oracle.jdbc.OracleConnection;
    import oracle.jdbc.OracleOCIFailover;
    import oracle.jdbc.pool.OracleDataSource;

    public class OCIFailOver {

      static final String user = "<USER>";
      static final String password = "<PASSWORD>";

      static final String URL = "jdbc:oracle:oci8:@<PRIMARY TNS ENTRY>"; 


      public static void main (String[] args) throws Exception {

        Connection conn = null;
        CallBack   fcbk= new CallBack();
        String     msg = null;
        Statement  stmt = null;
        ResultSet rset = null; 
     
        // Create a OracleDataSource instance and set properties
        OracleDataSource ods = new OracleDataSource();
        ods.setUser(user);
        ods.setPassword(password);
        ods.setURL(URL);

        // Connect to the database
        conn = ods.getConnection();

        // register TAF callback function
        ((OracleConnection) conn).registerTAFCallback(fcbk, msg);

        // Create a Statement
        stmt = conn.createStatement ();

        for (int i=0; i<30; i++) {
          // Select the columns from the table
          rset = stmt.executeQuery ("select <COLUMN NAME1>, <COLUMN NAME2> from <TABLE>");

          // Iterate through the result and print the columns
          while (rset.next ()) 
            System.out.println (rset.getString (1) + " " +
                                rset.getString (2));

          // Sleep one second to make it possible to shutdown the DB.
          Thread.sleep(1000);
        } // End for
     
        // Close the RseultSet
        rset.close();

        // Close the Statement
        stmt.close();

        // Close the connection
        conn.close();


      } // End Main()

    } // End class jdemofo 


    /*
     * Define class CallBack
     */
    class CallBack implements OracleOCIFailover {
       
       // TAF callback function 
       public int callbackFn (Connection conn, Object ctxt, int type, int event) {

         /*********************************************************************
          * There are 7 possible failover event
          *   FO_BEGIN = 1   indicates that failover has detected a 
          *                  lost connection and faiover is starting.
          *   FO_END = 2     indicates successful completion of failover.
          *   FO_ABORt = 3   indicates that failover was unsuccessful, 
          *                  and there is no option of retrying.
          *   FO_REAUTH = 4  indicates that a user handle has been re-
          *                  authenticated. 
          *   FO_ERROR = 5   indicates that failover was temporarily un-
          *                  successful, but it gives the apps the opportunity
          *                  to handle the error and retry failover.
          *                  The usual method of error handling is to issue 
          *                  sleep() and retry by returning the value FO_RETRY
          *   FO_RETRY = 6
          *   FO_EVENT_UNKNOWN = 7  It is a bad failover event
          *********************************************************************/
         String failover_type = null;

         switch (type) {
           case FO_SESSION: 
             failover_type = "SESSION";
             break;
           case FO_SELECT:
             failover_type = "SELECT";
             break;
           default:
             failover_type = "NONE";
         }

         switch (event) {
           case FO_BEGIN:
             System.out.println(ctxt + ": "+ failover_type + " failing over...");
             break;
           case FO_END:
             System.out.println(ctxt + ": failover ended");
             break;
           case FO_ABORT:
             System.out.println(ctxt + ": failover aborted.");
             break;
           case FO_REAUTH:
             System.out.println(ctxt + ": failover.");
             break;
           case FO_ERROR:
             System.out.println(ctxt + ": failover error gotten. Sleeping...");
             // Sleep for a while 
             try {
               Thread.sleep(100);
             }
             catch (InterruptedException e) {
               System.out.println("Thread.sleep has problem: " + e.toString());
             }
             return FO_RETRY;
           default:
             System.out.println(ctxt + ": bad failover event.");
             break;
           
         }  

         return 0;

       }
    }

Fast Connection Failover (FCF)

  • W hat does FCF mean?
    Fast Connection Failover offers a driver-independent way for your JDBC application to take advantage of the connection failover facilities introduced in 10g Release 1 (10.1).
    When a RAC service failure is propagated to the JDBC application, the database has already rolled back the local transaction. The cache manager then cleans up all invalid connections. When an application holding an invalid connection tries to do work through that connection, it receives a SQLException ORA-17008, Closed Connection. The application has to handle the exception and reconnect.


  • What exactly is the use of FCF?
    FCF provides is very fast notification of the failure and the ability to reconnect immediately using the same URL. When a RAC node fails the application will receive an exception. The application has to handle the exception and reconnect.
    The JDBC driver does not re-target existing connections. If a node fails the application must close the existing connection and get a new one. The way the application knows that the node failed is by getting an exception. There is more than one ORA error that can be thrown when a node fails,the application must be able to deal with them all.
    An application may call isFatalConnectionError() API on the OracleConnectionCacheManager to determine if the SQLException caught is fatal. 

    If the return value of this API is true, we need to retry the getConnection on the DataSource.xxxxxx


  • How do we use FCF with JDBC driver?
    In order to use FCF with JDBC, the following things must be done:
    1. Configure and start ONS. If ONS is not correctly set up,implicit connection cache creation fails and an ONSException is thrown at the first getConnection() request.
      See   in the section  Configuring ONS located in   
    2. FCF is now configured through a pool-enabled data source and is tightly integrated with UCP.  The FCF enabled through the Implicit Connection Cache as was used in 10g and 11g R1 is now deprecated.
    3. Set the FastConnectionFailoverEnabled property before making the first getConnection() request to an OracleDataSource. When FastConnection Failover is enabled, the failover applies to all connections in the pool.
    4. Use a service name rather than a SID when setting the OracleDataSource url property.


  • Sample code to test FCF
    The code sample below shows the way how FCF works, it may not necessarily be the best way to do, but it should give you a general idea of what is needed.
    Make sure to change the following strings in the program, <hostname1>, <hostname2> and <service_name>.
    PoolDataSource  pds = PoolDataSourceFactory.getPoolDataSource();

    pds.setConnectionPoolName("FCFSamplePool");
    pds.setFastConnectionFailoverEnabled(true);
    pds.setONSConfiguration("nodes=<RAC NODE 1>:<PORT>,<RAC NODE 2>:<PORT>\nwalletfile= /<PATH>/<onswalletfile>");
    pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");pds.setURL("jdbc:oracle:thin@(DESCRIPTION= "+
       "(LOAD_BALANCE=on)"+
       "(ADDRESS=(PROTOCOL=TCP)(HOST=<RAC NODE 1>) (PORT=<PORT>))"+
       "(ADDRESS=(PROTOCOL=TCP)(HOST=<RAC NODE 2>) (PORT=<PORT>))"+
       "(CONNECT_DATA=(SERVICE_NAME=<SERVICE NAME)))");
    ...
    try {  conn = pds.getConnection;  ...}catch (SQLException sqlexc)
    {
       if (conn == null || !((ValidConnection) conn).isValid())
            
       // take the appropriate action
       
    ...
    conn.close();
    }


 

The example above is taken from the FCF documentation located the  Oracle® Universal Connection Pool for JDBC Developer's Guide 11 g Release 2 (11.2) section  .  
The ICC-based FCF is still documented in the  Oracle® Database JDBC Developer's Guide 11 g Release 2 (11.2) however this chapter is now flagged as deprecated.
It is recommended to use the UCP based FCF implementation.
See example in  Note 566573.1 Fast Connection Failover (FCF) Test Client Using 11g JDBC Driver and 11g RAC Cluster


REFERENCES

NOTE:1064652.1  - How to Verify Universal Connection Pool (UCP) / Fast Connection Failover (FCF) Setup
NOTE:566573.1  - Fast Connection Failover (FCF) Test Client Using the JDBC Driver version 11.1 and a RAC Cluster version 11.1
NOTE:433827.1  - How to Verify and Test Fast Connection Failover (FCF) Setup from a JDBC Thin 10g Client Against a 10.2.x RAC Cluster
NOTE:1080674.1  - FAQ: JDBC Drivers and Failover Mechanisms (FCF, TAF, SCAN)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29487349/viewspace-2751618/,如需轉載,請註明出處,否則將追究法律責任。

相關文章