Cloud Agnostic Load Balancing and High Availability of Microservices

“Developing an architecture that is highly available and load balanced using Consul and Fabio or HAProxy”

Microservices architecture is geared towards horizontal scalability, where new instances are spawned/removed to dynamically respond to changes in demand and/or failures to ensure High Availabilty of the system as a whole.

In this constantly changing environment we need some fault tolerant mechanism to ensure a client is aware of the network location viz., IP address and port number of these instances.

Service Registry

A service registry plays a key role, as it continuosly keeps track of the available services.The network location of a service instance is registered with the service registry when it starts up. It is removed from the service registry when the instance terminates. The service instance’s registration is typically refreshed periodically using a heartbeat mechanism.

Consul as Service Registry

The popular service registries are Consul, Zookeeper, andETCD. We choose Consul for two primary reasons, multi-datacenter support and inbuilt servive discovery.

Multi-Datacenter support allows us to spread service instances across multiple cloud providers and availabilty zones. Inbuilt Service Discovery allows clients to directly discover services directly using a DNS or HTTP interface.

More details on Consul’s multi-datacenter architecture can be accessed here.

Instance

Consul Setup :

Setup instructions for dockerized Consul v0.7.5

  # Allow alias to be used in non-interactive shell
  shopt -s expand_aliases

  # Creating alias for determining the wan ip address and lan ip address of the instance
  alias wanip="dig +short myip.opendns.com @resolver1.opendns.com"
  alias lanip="ifconfig eth0 | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'"

  # adding the aliases to .bashrc to make them persistant
  echo "alias wanip=\"dig +short myip.opendns.com @resolver1.opendns.com\"" >> .bashrc
  echo "alias lanip=\"ifconfig eth0 | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'\"" >> .bashrc

  # run consul in server mode on instance
  sudo docker run --restart unless-stopped --net=host  -d  -e 'CONSUL_LOCAL_CONFIG={"translate_wan_addrs": true}' consul \
          agent -server -bootstrap-expect=1  -advertise $(lanip) -ui -advertise-wan $(wanip) -client=0.0.0.0

  • --restart unless-stopped allows docker to autorestart Consul in the event of crash
  • CONSUL_LOCAL_CONFIG={"translate_wan_addrs": true} enables consul’s auto translation i.e if the an application being queried is in the same DataCenter, the LAN IP address is retrieved, and if its from a different datacenter the WAN IP address is retrieved.
  • agent Consul agent is run
  • -server The agent is run in server mode
  • -bootstrap-expect The number of consul servers that will be present in the cluster, this is needed for maintaining the quorum.
  • -advertise the IP address that will be broadcasted to the Consul cluster. (A single IP address can also be broadcasted either WAN or LAN)
  • -advertise-wan the WAN IP address that will be broadcasted to the Consul cluster.
  • -ui enables web UI

Fabio

Fabio is a fast, modern, zero-conf load balancing HTTP(S) router written in Go for deploying applications managed by Consul. Fabio watches services in consul and reloads its configuration on every change without interrupting existing connections. So in that sense it provides true zero-downtime compared to HAProxy+Consul-Template.

To enable load balancing with Fabio we have to add a tag beginning with urlprefix- and enable healthcheck while registering the microservices with Consul. Fabio only adds services with a passing healthcheck and a valid tag.

Register one urlprefix- tag per host/path prefix it serves, e.g.:

  urlprefix-/microserviceA  --> localhost:9999/microserviceA

  urlprefix-microserviceB/data --> localhost:9999/microserviceB/data

  urlprefix-mysite.com/  --> --> localhost:9999/mysite.com/

By default Fabio listens on port 9999, so any traffic received at that port with their path beginning with a valid path will be loadbalanced among the matching services.

Fabio web user interface can be accessed at port 9998.