콘텐츠로 이동

JDBC와 Failover

JDBC와 Failover#

이 절은 Altibase JDBC 애플리케이션에서 Failover 기능을 사용하는 방법을 설명한다.

Failover란#

Failover란 데이터베이스 서버에 장애가 발생하여 연결이 끊어졌을 때, 애플리케이션이 즉시 다른 서버로 연결을 생성하여 기존에 수행하던 작업을 계속하는 기능을 말한다.

Failover는 아래 두 가지 방식으로 동작할 수 있다.

CTF(Connection Time Failover)#

데이터베이스로의 접속 시도를 실패한 경우, 다른 서버로 접속을 재시도하는 동작 방식이다. CTF는 Connection 객체의 connect 메소드를 호출할 때 발생할 수 있다.

STF(Session Time Failover)#

SQL문을 수행하여 서버로부터 결과를 받기 전에 연결 오류가 발생한 경우, 다른 서버로 접속하여 사용자가 지정한 작업을 계속하는 동작 방식이다. STF는 connect를 제외한 서버와 통신을 하는 모든 메소드 수행 시에 발생할 수 있다.

Failover에 대한 자세한 내용은 Replication Manual의 "Failover"장을 참고하도록 한다.

사용 방법#

여기에서는 JDBC 애플리케이션에서 CTF 및 STF 기능을 사용하는 방법을 설명한다.

CTF#

Properties 객체에 아래의 속성을 추가해서 CTF 기능을 사용할 수 있다.

Properties sProps = new Properties();
sProps.put("alternateservers", "database1:20300, database2:20300");
sProps.put("connectionretrycount", "5");
sProps.put("connectionretrydelay", "2");
sProps.put("sessionfailover", "off");

각각의 속성에 대한 자세한 설명은 1장의 "연결 속성" 절을 참고하라.

STF#

CTF 기능을 설정하는 속성에 추가로 "SessionFailover=on"을 설정해서 STF 기능을 사용할 수 있다.

데이터베이스 서버로 접속을 시도하는 것을 제외한 통신 상황에서, 클라이언트가 서버의 장애를 감지하면 먼저 CTF 과정을 수행하여 접속을 복원한다. 그 다음, 클라이언트는 사용자가 등록한 콜백 함수를 수행한 후에, 사용자가 Failover 발생을 인지할 수 있도록 Failover Success Exception을 발생시킨다. 이 때 모든 서버로 Failover가 실패하면 드라이버는 원래 발생했던 Exception을 던진다.

아래는 사용자가 작성해야 할 Failover 콜백 함수를 위한 인터페이스이다.

public interface AltibaseFailoverCallback
{
    public final static class Event
    {
        public static final int BEGIN     = 0;
        public static final int COMPLETED = 1;
        public static final int ABORT     = 2;
    }
    public final static class Result
    {
        public static final int GO   = 3;
        public static final int QUIT = 4;
    }
    int failoverCallback(Connection aConnection,
                         Object     aAppContext,
                         int        aFailoverEvent);
};

다음은 사용자가 Failover 콜백 함수를 등록하고 해제하는 과정을 보여주는 코드 예제이다.

public class  UserDefinedFailoverCallback implements AltibaseFailoverCallback
{
    ...

    public int failoverCallback(Connection aConnection,
                                Object     aAppContext,
                                int        aFailoverEvent)
    {
        // User Defined Code
        // Result.GO나 Result.QUIT 중 한 가지 값을 반환해야 함.
    }

    ...
}

위의 AltibaseFailoverCallback 인터페이스에 포함된 Event 상수는 사용자가 작성한 Failover 콜백 함수가 JDBC 드라이버에 의해 호출될 때, 콜백 함수의 세 번째 인자인 aFailoverEvent로 전달된다. 각 Event 상수의 의미는 다음과 같다.

  • Event.BEGIN: Session Failover가 시작됨

  • Event.COMPLETED: Session Failover가 성공하였음

  • Event.ABORT: Session Failover가 실패하였음

AltibaseFailoverCallback 인터페이스에 포함된 Result 상수는 사용자가 작성하는 콜백 함수에서 반환할 수 있는 값들이다. 콜백 함수에서 Result 상수 이외의 값을 반환하면 Failover가 정상적으로 동작하지 않는다.

  • Result.GO 콜백 함수에서 이 상수값이 반환되면, JDBC 드라이버는 STF의 다음 과정을 계속해서 진행한다.

  • Result.QUIT 콜백 함수에서 이 상수값이 반환되면, JDBC 드라이버는 STF 과정을 종료한다.

다음은 사용자가 작성하는 Failover 콜백 함수의 두 번째 인자로 사용할 수 있는 객체의 코드 예제이다.

public class UserDefinedAppContext
{
    // User Defined Code
}

사용자가 구현한 애플리케이션의 정보를 STF 과정에서 사용할 필요가 있는 경우, Failover 콜백 함수를 등록하면서 콜백 함수에 전달될 객체를 지정할 수 있다. 콜백 함수를 등록하는 registerFailoverCallback 메소드의 두 번째 인자로 이 객체를 지정하면, 실제로 콜백 함수가 호출될 때 이 객체가 전달된다. 다음은 이런 과정을 코드로 나타낸 예제이다.

// 사용자 정의 콜백 함수 객체 생성
UserDefinedFailoverCallback sCallback = new UserDefinedFailoverCallback();
// 사용자 정의 애플리케이션 정보 객체 생성
UserDefinedAppContext sAppContext = new UserDefinedAppContext();

...

Connection sCon = DriverManager.getConnection(sURL, sProp);

// 사용자 정의 애플리케이션 객체와 함께 콜백 함수 등록
((AltibaseConnection)sCon).registerFailoverCallback(sCallback, sAppContext);

...

// 콜백 함수 해제
((AltibaseConnection)sCon).deregisterFailoverCallback();

코드 예제#

STF를 위한 콜백 함수를 구현하는 코드 예제이다.

아래의 예제는 여러 가지 경우를 무시한 단순 코드이므로, 사용자 애플리케이션에서 그대로 사용할 수 없음을 주의해야 한다.

public class MyFailoverCallback implements AltibaseFailoverCallback
{
    public int failoverCallback(Connection aConnection, Object aAppContext,int aFailoverEvent)
    {
        Statement sStmt = null;
        ResultSet sRes = null;

        switch (aFailoverEvent)
        {
            // 사용자 어플리케이션의 로직상 Failover 시작 전에 필요한 작업을 진행할 수 있다.
            case Event.BEGIN:
                System.out.println("Failover Started .... ");
                break;
            // 사용자 어플리케이션의 로직상 Failover 완료 후에 필요한 작업을 진행할 수 있다.
            case Event.COMPLETED:
                try
                {
                    sStmt = aConnection.createStatement();
                }
                catch( SQLException ex1 )
                {
                    try
                    {
                        sStmt.close();
                    }
                    catch( SQLException ex3 )
                    {
                    }
                    return Result.QUIT;
                }

                try
                {
                    sRes = sStmt.executeQuery("select 1 from dual");
                    while(sRes.next())
                    {
                        if(sRes.getInt(1) == 1 )
                        {
                            break;
                        }
                    }
                }
                catch ( SQLException ex2 )
                {
                    try
                    {
                        sStmt.close();
                    }
                    catch( SQLException ex3 )
                    {
                    }
                    // Failover 과정을 종료한다.
                    return Result.QUIT;
                }
                break;
        }
        // Failover 과정을 계속한다.
        return Result.GO;
    }
}

다음은 STF 성공 여부를 확인하는 코드 예제이다. STF가 성공했는지 실패했는지를 판단하는 방법은 SQLException의 ErrorCode가 Validation.FAILOVER_SUCCESS와 일치하는지 확인하는 것이다. while loop 내에 Failover 검증 코드를 삽입한 이유는 Failover가 성공하더라도 이전에 수행중이던 작업은 다시 수행해야 하기 때문이다.

// 반드시 수행하려던 작업을 재수행할 수 있도록 구현해야 한다.
// 이 경우에는 while loop를 사용하였다.
while (true)
{
    try
    {
        sStmt = sConn.createStatement();
        sRes = sStmt.executeQuery("SELECT C1 FROM T1");
        while (sRes.next())
        {
            System.out.println("VALUE : " + sRes.getString(1));
        }
    }
    catch (SQLException e)
    {
        // Failover 성공 여부 확인
        if (e.getErrorCode() == AltibaseFailoverCallback.FailoverValidation.FAILOVER_SUCCESS)
        {
            // Failover가 성공했으므로 Exception을 무시하고 계속 진행한다.
            continue;
        }
        System.out.println("EXCEPTION : " + e.getMessage());
    }
    break;
}