oracle_rac_application_continuity

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:

Service Creation

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 \
-notification TRUE

We can check the configuration of the service as follows. Remember to put the database name.

Status and Start the service

[oracle@enode01 labs]$ srvctl config service -db eastdb -service actest
Service name: actest
Server pool:
Cardinality: 1
Disconnect: false
Service role: PRIMARY
Management policy: AUTOMATIC
DTP transaction: false
AQ HA notifications: true
Global: false
Commit Outcome: true
Failover type: TRANSACTION
Failover method:
TAF failover retries: 30
TAF failover delay: 5
Connection Load Balancing Goal: SHORT
Runtime Load Balancing Goal: SERVICE_TIME
TAF policy specification: NONE
Edition:
Pluggable database name:
Maximum lag time: ANY
SQL Translation Profile:
Retention: 86400 seconds
Replay Initiation Time: 1800 seconds
Session State Consistency: DYNAMIC
GSM Flags: 0
Service is enabled
Preferred instances: eastdb1
Available instances: eastdb2
[oracle@enode01 labs]$
[oracle@enode01 labs]$ srvctl start service -db eastdb -service actest
[oracle@enode01 labs]$
[oracle@enode01 labs]$ srvctl status service -db eastdb
Service actest is running on instance(s) eastdb1
[oracle@enode01 labs]$

Now that we have the service, let's run the simple application. The application itself is one, but we will run it with different connection settings:

Below you can see the source which I have used:

Application Source

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;
  }

}

Now that we have the code, we can run it one in a two ways:

We can run that application standard without any application continuity as follows:

No Repluay Mode

[oracle@enode01 labs]$ cat runnoreplay.sh
java -classpath
./actest.jar:$ORACLE_HOME/ucp/lib/ucp.jar:$ORACLE_HOME/jdbc/lib/
ojdbc6.jar actest.ACTest actest_noreplay.properties

Where the connection properties are as follows:

Connection properties

[oracle@enode01 labs]$ cat actest_noreplay.properties
username=scott
password=tiger
autoCommit=false
# Use standard 12.1 datasource no replay
datasource=oracle.jdbc.pool.OracleDataSource
url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=
cluster01-
scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=actest.
example.com)))
# UCP setting:
ucp_pool_size=2
ucp_validate_connection_on_borrow=true
ucp_connection_wait_timeout=60
# Think Time taken to process the results from the database.
Time in milliseconds.
# -1 means no sleep.
thread_think_time=20
# Number of concurrent threads running in the application
# UCP is tuned to have MAX and MIN limit set to this
number_of_threads=6
verbose=true

That way, the application WILL NOT take advantage of the Application Continuity and it will fail if the connection gets interrupted:

Interrupted Connection

[oracle@enode01 labs]$ ./runnoreplay.sh
######################################################
Connecting to
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=clus
ter01-
scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=actest.
example.com)))
# of Threads : 6
UCP pool size : 2
Thread think time : 20 ms
######################################################
2 active connections, avg response time from db 21 ms
2 active connections, avg response time from db 11 ms
... (killed process from 2nd session)
.Exception occurred while getting connection:
oracle.ucp.UniversalConnectionPoolException: Cannot get
Connection from Datasource: java.sql.SQLRecoverableException:
Listener refused the connection with the following error:
ORA-12514, TNS:listener does not currently know of service
requested in connect descriptor
...
[oracle@enode01 labs]$

In order to make the application aware of the feature, we have to start it with the Universal Connection pooling using the replay option. To do that, we can use THE SAME application but with different connection properties:

Connection Properties

[oracle@enode01 labs]$ cat actest_replay.properties
username=scott
password=tiger
autoCommit=false
# Use new 12.1 replay datasource
datasource=oracle.jdbc.replay.OracleDataSourceImpl
url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=
cluster01-
scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=actest.
example.com)))
# UCP setting:
ucp_pool_size=2
ucp_validate_connection_on_borrow=true
ucp_connection_wait_timeout=60
# Think Time taken to process the results from the database.
Time in milliseconds.
# -1 means no sleep.
thread_think_time=20
# Number of concurrent threads running in the application
# UCP is tuned to have MAX and MIN limit set to this
number_of_threads=6
verbose=true

The properties are 99.9% the same, with the only difference of the: “datasource=oracle.jdbc.replay.OracleDataSourceImpl” property in the replay one:

Difference between Replay and No replay

[oracle@enode01 labs]$ diff actest_noreplay.properties
actest_replay.properties
5,6c5,6
< # Use standard 12.1 datasource no replay
< datasource=oracle.jdbc.pool.OracleDataSource
---
> # Use new 12.1 replay datasource
> datasource=oracle.jdbc.replay.OracleDataSourceImpl

That way, the application will be able to reconnect after interrupted connection:

Interrupted Connection

[oracle@enode01 labs]$ ./runreplay.sh
######################################################
Connecting to
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=clus
ter01-
scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=actest.
example.com)))
# of Threads : 6
UCP pool size : 2
Thread think time : 20 ms
######################################################
2 active connections, avg response time from db 304 ms
2 active connections, avg response time from db 45 ms
2 active connections, avg response time from db 304 ms
2 active connections, avg response time from db 45 ms
2 active connections, avg response time from db 29 ms
2 active connections, avg response time from db 32 ms
2 active connections, avg response time from db 29 ms
2 active connections, avg response time from db 18 ms
2 active connections, avg response time from db 36 ms
... (Interupted connection)
2 active connections, avg response time from db 5962 ms
2 active connections, avg response time from db 98 ms
2 active connections, avg response time from db 61 ms
2 active connections, avg response time from db 72 ms
[oracle@enode01 labs]$

  • oracle_rac_application_continuity.txt
  • Last modified: 2020/10/22 12:13
  • by andonovj