This is an old revision of the document!


Overview

Application Continuity is a new feature and enhancement of the TAF and FCF. Application continuity is composed by two components:

  • Transactional Guard
  • Transactional Replay

In a nutshell, you will no more wonder if you have to redo your changes if a session is killed or the instance is terminated. Up to now, all your session data (including your transactional data) was wiped, once the instance is destroyed. However from Oracle Database 12c, you can configure a service to record your changes and replay them next time you connect as follows:

Create service actest

[oracle@enode01 labs]$ srvctl add service -db eastdb \
-service actest \
-preferred eastdb1 \
-available eastdb2 \
-clbgoal SHORT \
-rlbgoal SERVICE_TIME \
-failovertype TRANSACTION \
-commit_outcome TRUE \
-failoverretry 30 \
-failoverdelay 5 \
-retention 86400 \
-replay_init_time 1800 \

[oracle@lparaca ~]$ srvctl status service -serverpool orclsp
Service actest of database orcl is not running.
[oracle@lparaca ~]$ srvctl start service -db orcl -service actest

[oracle@lparaca ~]$ srvctl status service -serverpool orclsp
Service actest of database orcl is running on nodes: lparaca.
[oracle@lparaca ~]$ lsnrctl status

LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 19-JAN-2018 05:16:01

Copyright (c) 1991, 2014, Oracle.  All rights reserved.

Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 12.1.0.2.0 - Production
Start Date                19-JAN-2018 04:02:17
Uptime                    0 days 1 hr. 13 min. 44 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /u01/app/oracle/grid/network/admin/listener.ora
Listener Log File         /u01/app/oracle/product/diag/tnslsnr/lparaca/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=LISTENER)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.100.50)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.100.51)(PORT=1521)))
Services Summary...
Service "+ASM" has 1 instance(s).
  Instance "+ASM1", status READY, has 1 handler(s) for this service...
Service "actest" has 1 instance(s).     <--- **Our new SERVICE**
  Instance "orcl_1", status READY, has 1 handler(s) for this service...
Service "orcl" has 1 instance(s).
  Instance "orcl_1", status READY, has 1 handler(s) for this service...
Service "orclXDB" has 1 instance(s).
  Instance "orcl_1", status READY, has 1 handler(s) for this service...
The command completed successfully

Now your service will failover to the other instance and the uncommited changes will be replayed. Therefore, any node failure will be transparent to the end user.

The application should be changed also be using the UPC = Universal Connection Pooling

Below you can see the source which I have used:


package act;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.ValidConnection;
import java.sql.ResultSet;

/**
 *
 * @author Julien
 */
public class Actest {

  /**
  * @param args the command line arguments
  */
  public static void main(String[] args) throws SQLException, Exception {
  String message;

  if (args.length == 0) {
  message = "default";
  } else {
  message = args[0];
  }

  PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
  pds.setConnectionFactoryClassName("oracle.jdbc.replay.OracleDataSourceImpl");

  System.out.println("connection factory set");

  String URL = "jdbc:oracle:thin:@(DESCRIPTION = (TRANSPORT_CONNECT_TIMEOUT=3) (RETRY_COUNT=20)(FAILOVER=ON) " +
  "(ADDRESS = (PROTOCOL = TCP)(HOST = lparac-scan.myrac.com)(PORT = 1521)) (CONNECT_DATA = " +
  "(SERVER = DEDICATED) (SERVICE_NAME = ACTEST)))";
  System.out.println("Using URL\n" + URL);
  pds.setURL(URL);
  pds.setUser("acuser");
  pds.setPassword("acpassword");

  pds.setInitialPoolSize(10);
  pds.setMinPoolSize(10);
  pds.setMaxPoolSize(20);

  // RAC Features
  pds.setConnectionPoolName("Application Continuity Pool");
  pds.setFastConnectionFailoverEnabled(true);
  // use srvctl config nodeapps to get the ONS ports on the cluster
  pds.setONSConfiguration("nodes=192.168.100.50:6200,192.168.100.60:6200");

  System.out.println("pool configured, trying to get a connection");

  Connection conn = pds.getConnection();
  if (conn == null || !((ValidConnection) conn).isValid()) {

  System.out.println("connection is not valid");
  throw new Exception ("invalid connection obtained from the pool");
  }

  if ( conn instanceof oracle.jdbc.replay.ReplayableConnection ) {
  System.out.println("got a replay data source");
  } else {
  System.out.println("this is not a replay data source. Why not?");
  }

  System.out.println("got a connection! Getting some stats if possible");
  oracle.ucp.jdbc.JDBCConnectionPoolStatistics stats = pds.getStatistics();
  System.out.println("\tgetAvailableConnectionsCount() " + stats.getAvailableConnectionsCount());
  System.out.println("\tgetBorrowedConnectionsCount() " + stats.getBorrowedConnectionsCount() );
  System.out.println("\tgetRemainingPoolCapacityCount() " + stats.getRemainingPoolCapacityCount());
  System.out.println("\tgetTotalConnectionsCount() " + stats.getTotalConnectionsCount());

  System.out.println(((oracle.ucp.jdbc.oracle.OracleJDBCConnectionPoolStatistics)pds.getStatistics()).getFCFProcessingInfo());

  System.out.println("Now working");

  java.sql.CallableStatement cstmt = conn.prepareCall("{call callProc(?)}");
  cstmt.setString(1, message);
  cstmt.execute();

  System.out.println("Statement executed. Now closing down");
  System.out.println("Almost done! Getting some more stats if possible");

  stats = pds.getStatistics();
  System.out.println("\tgetAvailableConnectionsCount() " + stats.getAvailableConnectionsCount());
  System.out.println("\tgetBorrowedConnectionsCount() " + stats.getBorrowedConnectionsCount() );
  System.out.println("\tgetRemainingPoolCapacityCount() " + stats.getRemainingPoolCapacityCount());
  System.out.println("\tgetTotalConnectionsCount() " + stats.getTotalConnectionsCount());
System.out.println(((oracle.ucp.jdbc.oracle.OracleJDBCConnectionPoolStatistics)pds.getStatistics()).getFCFProcessingInfo());

  cstmt.close();
  conn.close();
  conn = null;
  }

}


Once the code is compiled can be run via:

C:\Users\Julien>java -jar -Djava.util.logging.config.file=logging.properties.txt
 C:\Users\Julien\Documents\NetBeansProjects\actest\dist\actest.jar all_out_loggi
ng2
connection factory set
Using URL
jdbc:oracle:thin:@(DESCRIPTION = (TRANSPORT_CONNECT_TIMEOUT=3) (RETRY_COUNT=20)(
FAILOVER=ON) (ADDRESS = (PROTOCOL = TCP)(HOST = lparac-scan.myrac.com)(PORT = 15
21)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ACTEST)))
pool configured, trying to get a connection

C:\Users\Julien>

  • oracle_rac_application_continuity.1603367750.txt.gz
  • Last modified: 2020/10/22 11:55
  • by andonovj