Application Continuity is a new feature and enhancement of the TAF and FCF. Application continuity is composed by two components:
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 \ -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]$