Using failover in high availability systems

A high availability cluster includes two or more machines that are configured so that if one machine (or application) is interrupted, the second machine assumes the workload of both machines. Each of these machines is called one node of the high availability cluster. A high availability cluster is used in an environment that must always be available, such as, a banking system to which clients must connect continuously, 365 days a year.

The machines in Figure 3-1 are configured so that each machine can read the other machine's disks, although not at the same time. (All of the disks that are failed-over should be shared disks).

Figure 3-1: High availability cluster using failover

*

For example, if Adaptive Server 1 is the primary companion server, and it crashes, Adaptive Server 2, as the secondary companion server, reads its disks (disks 1 - 4) and manages any databases on them until Adaptive Server 1 can be rebooted. Any clients connected to Adaptive Server 1 are automatically connected to Adaptive Server 2.

Failover allows Adaptive Server to work in a high availability cluster in active-active or active-passive configuration.

During failover, clients connected to the primary companion using the failover property automatically reestablish their network connections to the secondary companion. Failover can be enabled by setting the connection property HASession to “1” (default value is “0”). If this property is not set, the session failover does not occur, even if the server is configured for failover. You also must set SecondaryServer (the IP address or the machine name of the secondary ASE server) and SecondaryPort (the port number of the secondary ASE server) properties. See the ASE book, Using Sybase Failover in a High Availability System, for information, about configuring your system for high availability.

When the ASE ODBC driver detects a connection failure with the primary ASE server, it first tries to reconnect to the primary. If it cannot reconnect, it assumes that a failover has occurred. Then, it automatically tries to connect to the secondary ASE server using the connection properties set in SecondaryServer, and SecondaryPort.

Confirming a successful failover

If a connection to the secondary server is established, the ASE ODBC Driver returns SQL_ERROR for the function return code. To confirm a successful failover, you should further examine the SQLState and NativeError for values of “08S01” and “30130” respectively. The error message returned on such failover is:

“Connection to Sybase server has been lost
, you have been successfully connected
to the next available HA server.
All active transactions have been rolled
back.”

You can access these values by calling SQLGetDiagRec on the StatementHandle. Then, the client must reapply the failed transaction with the new connection. If failover happens while a transaction is open, only changes that were committed to the database before failover are retained.

Verifying an unsuccessful failover

If the connection to the secondary server is not established, the ASE ODBC Driver returns SQL_ERROR for the function return code. To confirm that failover did not occur, you should further examine the SQLState and NativeError for values of “08S01” and “30131.” The error message returned on an unsuccessful failover is:

“Connection to Sybase server has been lost,
connection to the next available HA server
also failed. All active transactions 
have been rolled back”.

You can access these values by calling SQLGetDiagRec on the StatementHandle.

The following shows how to code for a failover:

/* Declare required variables */
....
/* Open Database connection */
....
/* Perform a transaction */
...
/* Check return code and handle failover */
if( retcode == SQL_ERROR )
{
   retcode = SQLGetDiagRec(stmt, 1,       sqlstate,&NativeError, errmsg,100, NULL );
   if(retcode == SQL_SUCCESS || 
      retcode == SQL_SUCCESS_WITH_INFO)
   {
        if(NativeError == 30130 )
        {
        /* Successful failover retry transaction*/
        ...
     }
     else if (NativeError == 30131)
     {
        /* Failover failed. Return error */
        ...
     }
   }	
}