firstworks SQL Relay - Load Balancing and Failover

Load Balancing and Failover

- Distributing Load Over a Pool of Database Servers
- Database Server Failover
- Distributing Load Over a Pool of SQL Relay Servers
- SQL Relay Server Failover

Distributing Load Over a Pool of Database Servers

There are probably a dozen commercial and Open Source Load Balancers available today. They are often implemented differently, and some have unique features, but they all provide a single IP address for a pool of servers and distribute incoming connections over the pool.

It's possible to set up a pool of database servers behind a Load Balancer. Database clusters such as Oracle RAC come with their own built-in load-balancer. SQL Relay should work just fine with these systems. Just configure the instance of SQL Relay to connect to the IP address of the pool or cluster and the Load Balancer will distribute the connections over the pool of servers.

If you don't have a Load Balancer or would rather not use one, SQL Relay can still distribute load over a pool of database servers. In effect, SQL Relay is a very specialized Load Balancer. An instance of SQL Relay can be configured to maintain connections to more than one database server and distribute client sessions over the pool of servers it's connected to.

Note that SQL Relay distributes client sessions, not individual queries. When a client connects to the SQL Relay listener daemon, it will be assigned to one of the database servers in the pool, and as long as it remains connected, all of its queries will be run against the same database server. If the client disconnects and reconnects, it may be assigned to a different database server the next time around.

To configure an instance of SQL Relay to connect to a set of database servers, you have to define multiple connection tags, as follows:

>     <?xml version="1.0"?>
>     <!DOCTYPE instances SYSTEM "sqlrelay.dtd">

>     <instances>

>             <instance id="example" dbase="oracle8" connections="15">
>                     <users>
>                             <user user="user1" password="password1"/>
>                     </users>
>                     <connections>
>                             <connection connectionid="DB1" string="user=exampleuser1;password=examplepassword1;oracle_sid=EXAMPLE1;" metric="1"/>
>                             <connection connectionid="DB2" string="user=exampleuser2;password=examplepassword2;oracle_sid=EXAMPLE2;" metric="1"/>
>                             <connection connectionid="DB3" string="user=exampleuser3;password=examplepassword3;oracle_sid=EXAMPLE3;" metric="1"/>
>                     </connections>
>             </instance>

>     </instances>

In this example, SQL Relay will maintain 15 persistent database connections. Since this instance is configured to connect to 3 different database servers, SQL Relay will maintain 5 persistent connections to each server.

The metric attribute may be used to alter the distribution of connections over the databases in the pool. Lets say that the server running DB1 and DB2 are old machines, but the server running DB3 is brand new and can handle twice as many connections as DB1 or DB2. Assigning a metric of 1 to DB1 and DB2 and 2 to DB3 will cause twice as many connections to be started to DB3 than either DB1 or DB2, making it twice as likely that a client will use DB3 than either DB1 or DB2. In this example, only 15 connections will be started, but 7 or 8 will be started against DB3 and 3 or 4 will be started against each of DB1 and DB2.

For instance:

>     <?xml version="1.0"?>
>     <!DOCTYPE instances SYSTEM "sqlrelay.dtd">

>     <instances>

>             <instance id="example" dbase="oracle8" connections="15">
>                     <users>
>                             <user user="user1" password="password1"/>
>                     </users>
>                     <connections>
>                             <connection connectionid="DB1" string="user=exampleuser1;password=examplepassword1;oracle_sid=EXAMPLE1;" metric="1"/>
>                             <connection connectionid="DB2" string="user=exampleuser2;password=examplepassword2;oracle_sid=EXAMPLE2;" metric="1"/>
>                             <connection connectionid="DB3" string="user=exampleuser3;password=examplepassword3;oracle_sid=EXAMPLE3;" metric="2"/>
>                     </connections>
>             </instance>

>     </instances>

Database Server Failover

If an SQL Relay notices that the database server has gone down then it will log out all connections to that server and loop, attempting to reestablish them. While the database server is down, client sessions will be distributed over the servers that are still up. When the database server comes back up, it will be available again.

If the database servers are load balanced (eg. Oracle RAC) then behindloadbalancer="yes" should be set in the connection tag to enable some behaviors that greatly improve performance in this environment.

Distributing Load Over a Pool of SQL Relay Servers

If your pool of application or web servers is sufficiently large, you might want to set up a pool of SQL Relay servers between them and the database.

You can use a load balancer to make a pool of SQL Relay servers appear to be a single server or just set up a pool of SQL Relay servers and distribute client connections over them using Round Robin DNS.

SQL Relay Server Failover

Failover between SQL Relay servers can be implemented using Round Robin DNS or a load balancer.

With Round Robin DNS, when the SQL Relay client looks up the IP address of the host, it actually gets back a list of all of the IP addresses in the pool. It tries to connect to the first address in the list. If that fails, it tries the next address, then the next, etc. Eventually, it will either succeed in connecting to one of the servers or run out of addresses and fail.

For example, this client is configured to connect to "sqlrserver". If "sqlrserver" resolves to a pool of addresses, then the client will attempt to connect to each address that "sqlrserver" resolves to before giving up.

>     sqlrconnection  sqlrcon("sqlrserver",9000,NULL,"sqlruser","sqlrpass",0,1);

The client can also be configured to try to connect to the same host multiple times. If the host name resolves to the IP address of a load balanced pool of SQL Relay servers, then the client will attempt to log into the pool over and over.

For example, this client is configured to log into the pool that the hostname "sqlrserver" resolves to 10 times with a 1 second pause between each try.

>     sqlrconnection  sqlrcon("sqlrserver",9000,NULL,"sqlruser","sqlrpass",1,10);

The number of seconds between tries can be set to any number, including 0. The total number of tries can be set to any number as well. Setting it to 0 will cause the client to retry forever.