Views

Sunday, July 31, 2011

Load Balancing Without a Load Balancer

Application delivery controllers perform a great service to direct traffic to servers which should handle client requests. Decisions on where to send information can be based on a variety of factors. Like their kid brother, the server load balancer, they present a virtual service address, linked to more than one backend system. By monitoring services on individual servers, the ADC or SLB drops unreliable services from pools to ensure high availability. Further, they divvy requests between servers which can answer them, balancing a load which might be higher than one system could accept.

There are times when you don't need the delivery options an ADC can provide, and even an SLB solution might not make sense. A tandem set of appliances for each local area network where servers reside is expensive to purchase and maintain vendor support. They also require power and use precious rack space. If a server load balancer is all you need to ensure service availability while dividing load, perhaps a different solution could do the job.



One Address To Rule Them All

Let's pick a service or two: named and httpd. Now, we'll assign an address to each service: 172.16.254.53 for DNS and 172.16.254.80 for web services. No matter what network the servers for these services lives on, the servicing address will be the same. With anycast, multiple servers can advertise their availability, inserting into the infrastructure's routing table a single address across multiple machines. Note, that this article will only deal with the httpd example.

More Than One Way To Get There

The OSPF protocol populates network destinations in a table based on the cost of the link. If there are multiple paths packets could take to reach a destination, the one with the lowest cost, or metric, gets its gateway updated in the routing table. If more than one of these share the lowest metric value, multiple gateways are placed in the routing table. For anycast, the destination is simply a host route and the multiple gateways are the addresses of the Ethernet interfaces of servers. Clients are directed to the system with the lowest metric, ensuring requests go to the closest systems, ones without WAN costs.

Home Lab

I assembled a small lab to test out this system.

Host: geary.streetsof.sf
System: Juniper SRX
Interfaces:
lo.0 172.16.0.1/32 ospf area 0.0.0.0
vlan.10 172.16.1.1/30 ospf area 0.0.0.0
vlan.100 172.16.100.1/24 ospf area 172.16.100.0

Host: kearny.streetsof.sf
System: Juniper SRX
Interfaces:
lo.0 172.16.0.2/32 ospf area 0.0.0.0
vlan.10 172.16.1.2/30 ospf area 0.0.0.0
vlan.200 172.16.200.1/24 ospf area 172.16.200.0

Host: polk.streetsof.sf
System: CentOS Linux 6.0
Interfaces: ospf area 172.16.100.0
lo:0 172.16.0.3/32
lo:1 172.16.254.80/32
eth0 172.16.100.128/24

Host: union.streetsof.sf
System: CentOS Linux 6.0
Interfaces: ospf area 172.16.100.0
lo:0 172.16.0.4/32
lo:1 172.16.254.80/32
eth0 172.16.100.129/24

Host: mission.streetsof.sf
System: CentOS Linux 6.0
Interfaces: ospf area 172.16.200.0
lo:0 172.16.0.5/32
lo:1 172.16.254.80/32
eth0 172.16.200.128/24

The routing table on GEARY looks like:

Prefix             Path  Route      NH       Metric NextHop       Nexthop      
                   Type  Type       Type            Interface     Address/LSP
172.16.0.2         Intra Router     IP            1 vlan.10       172.16.1.2
172.16.0.3         Intra Router     IP            1 vlan.100      172.16.100.128
172.16.0.4         Intra Router     IP            1 vlan.100      172.16.100.129
172.16.0.5         Intra Router     IP            1 vlan.10       172.16.1.2
172.16.0.1/32      Intra Network    IP            0 lo0.0
172.16.0.3/32      Intra Network    IP           11 vlan.100      172.16.100.128
172.16.0.4/32      Intra Network    IP           11 vlan.100      172.16.100.129
172.16.254.80/32   Intra Network    IP           11 vlan.100      172.16.100.128
                                                    vlan.100      172.16.100.129
172.16.100.0/24    Intra Network    IP            1 vlan.100
172.16.200.0/24    Intra Network    IP           19 vlan.10       172.16.1.2

When POLK and UNION become unavailable, the routing table on GEARY updates.

Prefix             Path  Route      NH       Metric NextHop       Nexthop      
                   Type  Type       Type            Interface     Address/LSP
172.16.0.2         Intra Router     IP            1 vlan.10       172.16.1.2
172.16.0.3         Intra Router     IP            1 vlan.100      172.16.100.128
172.16.0.4         Intra Router     IP            1 vlan.100      172.16.100.129
172.16.0.5         Intra Router     IP            1 vlan.10       172.16.1.2
172.16.0.1/32      Intra Network    IP            0 lo0.0
172.16.0.3/32      Intra Network    IP           11 vlan.100      172.16.100.128
172.16.0.4/32      Intra Network    IP           11 vlan.100      172.16.100.129
172.16.254.80/32   Intra Network    IP           19 vlan.10       172.16.1.2
172.16.100.0/24    Intra Network    IP            1 vlan.100
172.16.200.0/24    Intra Network    IP           19 vlan.10       172.16.1.2

172.16.0.80 lives on as a valid destination, but since MISSION is now serving it, the route to a farther point (higher cost) is visible in the routing table.

Change Noted

On each web server was a file, host.txt, which simply contained the name of the server. Requests were made from FILLMORE, address 172.16.100.151.

[fillmore]$ curl -x "" http://172.16.254.80/host.txt
POLK
[fillmore]$

After the web server on POLK went offline...

[fillmore]$ curl -x "" http://172.16.254.80/host.txt
UNION
[fillmore]$

And, after the web server on UNION went offline...

[fillmore]$ curl -x "" http://172.16.254.80/host.txt
MISSION
[fillmore]$

So, it works as expected.

The Linux Configuration

For the OSPF networking, you might want to install Quagga routing software. On CentOS, this was simple.

[polk]# yum -y install quagga
...
[polk]# chkconfig zebra on

You need to set up the loopback interfaces.

# /etc/sysconfig/network-scripts/ifcfg-lo:1
# Used as router-id, always available
#
DEVICE=lo:0
BOOTPROTO=none
NM_CONTROLLED="no"
IPADDR=172.16.0.3
NETMASK=255.255.255.255
ONBOOT=yes

# /etc/sysconfig/network-scripts/ifcfg-lo:2
# To be brought up if Apache is working as expected
#
DEVICE=lo:1
BOOTPROTO=none
NM_CONTROLLED="no"
IPADDR=172.16.254.80
NETMASK=255.255.255.255
ONBOOT=no

A simple check would insert or remove the host's service loopback into the routing tables.

state="up"
ifup lo:1
while : ; do
  /bin/sleep 10
  # be sure to check an interface other than the anycast address
  # is Apache listening?
  /usr/bin/nc -z 172.16.0.3 80
  if [ $? -eq 0 ]; then
  # if Apache is listening
  # Fire up ospfd and set state variable
    if [ "$state" != "up" ]; then
      /sbin/service zebra restart
      /sbin/service ospfd restart
      state="up"
    fi
  else
  # if Apache is not listening
  # Remove routing
  # Fire up Apache and give it a bit of time to load
  # Fire up routing
    /sbin/service ospfd stop
    /sbin/service zebra stop
    /sbin/service httpd restart
    /bin/sleep 10
  fi
done

! /etc/quagga/zebra.conf
!
hostname polk
password sfquagga
enable password sfquagga
!
interface lo:0
 ip address 172.16.0.3/32
interface eth0
 ip address 172.16.100.128/24
interface lo:1
 ip address 172.16.0.80/32
!
line vty
!
! /etc/quagga/ospfd.conf
!
hostname polk
password sfquagga
enable password sfquagga
!
interface eth0
 ip ospf priority 0
 ip ospf cost 32768
!
router ospf
 log-adjacency-changes
 ospf router-id 172.16.0.3
 network 172.16.100.0/24 area 172.16.100.0
 network 172.16.0.3/32 area 172.16.100.0
 network 172.16.0.80/32 area 172.16.100.0
!
line vty
!

I would be interested in hearing how this works for you.

No comments:

Post a Comment