Analyze Connection Failover options 1
TAF 를구현하기위한 Application 고려사항 1. Application FailOver 방법결정 2. Application의사용형태, 종류, 중요도에따라 TAF적용여부결정 3. Language별, 사용형태별 TAF사용여부및방법결정 4. Transaction에따른장애시점별 TAF 사용여부및방법결정 5. 장애유형별 TAF 사용여부 6. FailOver후의 Session 상태변경 2 전제사항 : Oracle Server 는 9i RAC 로구성되어야한다. OCI 를이용하지않은 Application 은 TAF 를위한특별한기능을제공하지않으며, 개발자가 Logic 을구현해야한다. TAF 를위한 Server Configuration 은이문서에서고려하지않는다. CONNECTION TIME FAIL OVER 는이문서에서고려하지않는다. 위의사항들을시간의여유가있을경우에는작성한다.
TAF 시고려사항들 (Summary) q TAF 는 RAC 를사용하는환경에서가용성을극대화하기위해제공되는기능이며, 모든 Application 을적용하기보다는중요한 Application 에대해서만적용토록한다. q TAF 적용시고려사항들 구분 CTF(Connection Time FailOver) 내 데이터베이스로접속하는순간에 Server, DB, Listener 등이가용하지않을경우에다른쪽 Server 로접속하는것을말함. 용 고려사항 OCI 를사용하지않는프로그램은매뉴얼하게 Logic 를구사해야한다. TAF(Run Time FailOver) FailOver 방법 Language별장애유형별사용여부 접속후데이터베이스사용중에 DB 나 Session 이장애가발생했을경우에다른 node 로접속하여진행하던작업을계속할수있도록하는것을말함. TAF 에서제공하는 Failover 방법들을말함. Mode : session, select Method : Basic, Preconnect 모든 programming language 를 TAF 가지원하지는않고 OCI 를사용하는 language 만을지원한다. 장애유형별 TAF 를사용해야할지결정한다. OCI 를사용할경우에는오라클에서 CallBack method 를지원하나 OCI 를사용하지않을경우에는 Logic 으로구사해야함 Long select 수행중장애발생시수행하던작업을넘기기위해서는 select 로해야하며 session 으로하면 session 만넘어가고 SQL 은다시수행해야함. Basic 은장애발생시다시접속하는방법이고, preconnect 는최초접속시다른 node 에미리 OCI 를사용하지않는 Language 의경우에는자체적으로 Logic 으로처리해한다. Ex) java thin driver 사용시 여러가지장애에따라, TAF 를사용할 Error 와사용하지않을 Error 를구분하여적용해야함. 적용할 Application 선정 위의내역들을모두고려하여 CTF,TAF 를적용한 Application 을선정한다. 이때너무많은 Application 을고려할경우에는상황의복잡함에시스템의안정화에나쁜영향을줄수있다. 프로그램의중요도에따라 CTF, TAF 를적용할 Application 을선정하며, 다양한 Error 에대한조치사항을적절하게적용해야한다. 3
1. Application FailOver 방법결정 TAF 에는여러가지 mode 및 method 가있는데, 각 Application 에적합한 TAF 방법을결정한다. Method/Mod BASIC PRECONNECT SESSION 장애발생시 client 는자동적으로다른 node 로 Login 이된다. 만약수행하던 Select 문이있을경우에는다시수행해야한다. Client 는접속시 2 개의 node 에모두접속한다. 이러한방식은장애발생시접속의부하를줄일수있다. 물로양쪽 node 에접속하고있으므로접속에대한부담이존재한다. SELECT Query 를수행하는동안장애가발생하면자동으로다른 node 로 Login 이되며, 수행하던 Query 를자동으로다시수행하게된다. Client 는접속시 2 개의 node 에모두접속한다. 제약사항 :OCI(NET8) 을사용하는 Application 에한해서적용가능하다. 만약 OCI 를사용하지않는 Application 은 Manual 하게조치해야함. 성능측면에서 Application Partitioning 후에 TAF 로 Failover 는 RAC 의 부담을줄수있으므로이에대한고려도필요함 (ping 의부하 ) 4
2. TAF 를적용할 Application 결정 q TAF Application 선택기준 적용여부 TAF 적용 TAF 미적용 24X365 로수행되는 Application(daemon 형태의프로그램으로자체적으로재기동할수없는 Application) 중요 Transaction 을포함하는 Application 단순조회 Web Application C/S 환경의조회 Application Application 의성격 다시시작해도되는 Transaction 을가진 Application q Application TAF 적용단계 Flow DB 관리자 개발자 TAF 개념전달 Application 유형분석 Application 대상선정 TAF Application 작성 Guide 대상 Application TAF 작성 TAF Test 5
3. Language 별 TAF 사용여부결정 q 개발언어에따른 TAF 사용여부 Java, C++, etc q TAF 를사용가능한 Client Application Product Product Oracle Call Interface ODBC driver JDBC driver Pro*C SQL*Plus Oracle Object for OLE 구분 Release 8 Release 8.0.5 Release 8 (thick driver only) Release 8i Release 8.0.4 Release 8i(Planned) q 특수한사용형태에따른고려사항. Java 의 Connection Pool 형태의 Connection 에대한 TAF 구현방법모색. OCI 를사용하지않는 Application 은자체적으로 Error 를탐지하여프로그램내에서 Logic 으로처리하여야한다. 6
4. 장애시점별 TAF 사용여부및방법결정 장애발생시점시나리오 장애구분 장애 Map 비고 (TAF 일경우 ) 트랜잭션없는작업 1 S1 장애 Session: SQL 수행은실패하고 Connection 만다른노드로전이 Select : Connection 은다른노드로전이되고 SQL 은계속수행됨 트랜잭션없는작업 2 Connection 전이됨. 특별한조치없이계속적인작업가능 S1 장애 S2 트랜잭션있는작업 작업중에있는 Transaction 은반드시 Rollback 을해야한다. TX1 장애 S1 접속한상태대기 S1 이수행되는시점에알수있으며, Session 은전이된다. 장애 S1 : Select : Tx(insert, update, delete) 7
5. 장애유형별 TAF 사용여부 장애의유형에따라 TAF 를사용하는경우와사용하지않는경우를구분하여나누어고려한다. 사용중장애 (TAF 함 ) 접속시장애 (CTF 함 ) 일반 Error(TAF 하지않음 ) Others Error 번호 ORA-01034 ORA-3113,ORA-3114 ORA-1033 ORA-25401 ORA-00020 ORA-12541 ORA-01034 Oracle Not Available Instance Down Shutdown progress Cannot Continue Fetch(Fetch 중 Error) Maximum number of processes xx exceeded TNS:no listener Oracle Not Available Error 내용 일반 SQL 수행시발생하는 Error 는 TAF 에적용하지않는다. Ex) extent error 나 unique violation error 등. 장애의복구를위한시도에대한제한 ( 예, 10 회 ) 을두어장기적인장애시불필요한자원낭비를예방한다. 8
6. FailOver 후의 Session 상태변경내역 q FailOver(TAF) 의경우에아래의몇가지정보들을잃어버리게되므로, TAF 를적용하기로선정된 Application 내에서잃어버린정보에대한처리 Logic 을넣어야한다. q FailOver 될때, RAC 환경의 Global Lock 에대한 remastering 작업으로약간의지체현상이나타날수있다. 종류 PL/SQL Package status Alter Session Statement 진행중인 Transaction Cursor Temporary table data Lob locator reads 내용 Package 의 global 변수같은정보는손실됨 Alter session 을이용한작업은손실되며, 이는 TAF 후에다시적용하여수행해야한다. Transaction 은반드시 rollback 한후작업을진행할수있다. Cursor 를열고연속적인작업을하는것은 error 를발생할수있다. (ora- 25401) Temporary table 을사용하는정보는잃어버린다. 9
7. Connection Time Failover Pseudo Code q OCI 를사용하는경우의 CTF q OCI 없이 CTF 구현 Program Start Program Start DB Connection Primary node Primary node 가 down 이면 NET8 에서자동으로 Backup node 로접속을시도한다. DB Connection Primary node 개발자로직으로구현 Connection OK? Connection OK? No DB Connection Second node Yes 업무로직처리 업무로직처리 Program End Program End 10
8. Transparent Application Failover Pseudo Code q OCI 를사용하는경우의 TAF q OCI 없이 TAF 구현 Program Start Program Start CallBack Register Error 발생시자동처리 업무로직처리 개발자로직으로구현 업무로직처리 CallBack Logic 정의 재처리 Program End Error 처리후자동복귀혹은, 프로그램종료 정상처리? Yes No Error 에따른 Logic 처리 OCI 제공 TAF 구조 종료 Program End 11
TAF Sample 프로그램 Test환경 Server : THVSD01, THVSD02 Java : Thick(OCI에서제공되는 callback이용 ), Thin(Logic으로처리 ) User : oraerp01 Listener.ora 내역 listener.ora(node 1) ERP01 = (ADDRESS_LIST = (ADDRESS= (PROTOCOL= IPC)(KEY= EXTPROCERP01)) (ADDRESS= (PROTOCOL= TCP)(Host= thvsd01_net)(port= 1812)) ) listener.ora(node 2) ERP02 = (ADDRESS_LIST = (ADDRESS= (PROTOCOL= IPC)(KEY= EXTPROCERP01)) (ADDRESS= (PROTOCOL= TCP)(Host= thvsd02_net)(port= 1812)) ) Tnsnames.ora TAF_ERP01= (DESCRIPTION_LIST= (DESCRIPTION= (FAILOVER=on) (ADDRESS_LIST = (ADDRESS=(PROTOCOL=tcp)(HOST=THVSD01_net) (PORT=1812)) (ADDRESS=(PROTOCOL=tcp)(HOST=THVSD02_net) (PORT=1812)) ) (CONNECT_DATA= (SERVICE_NAME=ERP) (FAILOVER_MODE= (BACKUP=TAF_ERP01) (TYPE=SELECT) (METHOD=BASIC) ) ) ) ) 12
TAFwithOCI.java Sampe //OCI 를이용한 Sample 로써 CallBack Class 를이용하여처리한다. // 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; public class TAFwithOCI { static final String user = "scott"; static final String password = "tiger"; static final String driver_class = "oracle.jdbc.driver.oracledriver"; static final String URL = "jdbc:oracle:oci8:@taf_erp01"; public static void main (String[] args) throws Exception { Connection conn = null; CallBack fcbk= new CallBack(); String msg = null; Statement stmt = null; ResultSet rset = null; // Load JDBC driver try { Class.forName(driver_class); catch(exception e) { System.out.println(e); // Connect to the database conn = DriverManager.getConnection(URL, user, password); // register TAF callback function ((OracleConnection) conn).registertafcallback(fcbk, msg); // Create a Statement stmt = conn.createstatement (); for (int i=0; i<30; i++) { // Select the ENAME column from the EMP table rset = stmt.executequery (" select to_char(sysdate,'yyyy MM DD HH24:MI:SS') " + " '[' instance_name '][' host_name ']' from v$instance "); 13
TAFwithOCI.java Sampe // Iterate through the result and print the employee names while (rset.next ()) System.out.println (rset.getstring (1)); // Sleep one second to make it possible to shutdown the DB. Thread.sleep(1000); // End for rset.close(); stmt.close(); 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 conenction 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 opp- * ortunity 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"; 14
TAFwithOCI.java Sampe 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; 15
TAFwithLogic.java Sampe // 장애에대한처리를 Application 에서 Logic 으로처리한다 import java.io.*; import java.util.*; import java.sql.*; import java.text.*; public class TAFwithLogic { public static void main( String[] args ) throws Exception { DriverManager.registerDriver( new oracle.jdbc.driver.oracledriver() ); Connection conn = null; Statement stmt = null; //while ( true ) for(int i = 1; i < 100; i++) { if ( conn == null ) try { conn = DriverManager.getConnection( "jdbc:oracle:oci8:@taf_erp01", "apps", "apps" ); System.out.println( "[" + DateFormat.getDateTimeInstance().format( new java.util.date() ) + "] Connection Success" ); catch ( SQLException e ) { System.out.println( "[" + DateFormat.getDateTimeInstance().format( new java.util.date() ) + "] Connect FAIL!!" ); System.out.println( e ); Thread.sleep( 1000 ); continue; try { stmt = conn.createstatement(); //ResultSet rs = stmt.executequery( "select sid from v$session" ); ResultSet rs = stmt.executequery( " select to_char(sysdate,'yyyy MM DD HH24:MI:SS') " + " '[' instance_name '][' host_name ']' from v$instance " ); rs.next(); System.out.println(rs.getString(1)); stmt.close(); Thread.sleep( 1000 ); // wait 1 second catch ( SQLException e ) // SQL 수행중에 Error 가발생하면다시접속한다. { System.out.println( "[" + DateFormat.getDateTimeInstance().format( new java.util.date() ) + "] Select FAIL!!" ); System.out.println( e ); conn = null; 16