Modificar el balanceador de carga de Azure Cloud Services

Estos días he estado jugando con el balanceador de carga que tiene como cometido añadir y quitar instancias en Azure Cloud Services. Por defecto, cuando trabajas con este servicio, él se encarga de enrutar el tráfico a las instancias de un rol, apoyándose en un agente que se instala en las mismas y que mediante un sondeo periódico, el agente responde con un HTTP 200 si todo funciona correctamente.

En ocasiones es necesario cambiar este comportamiento y tener en cuenta otros factores para que una instancia esté lista para añadirse al balanceador, y es por ello que hoy te quiero contar cómo es posible que tú determines cuándo una instancia está disponible para recibir peticiones y cuándo no. He creado un ejemplo muy sencillo para que entiendas cómo funciona.

Load Balancer Probe - Demo
Load Balancer Probe – Demo

Lo que he hecho ha sido utilizar una aplicación ASP.NET MVC que muestra el nombre de la instancia que ha atendido la petición, qué valor tiene la variable que se va a encargar de hacer que la máquina falle y un enlace que te ayude a marcarla como no disponible. El código es bastante sencillo:

<div class="jumbotron">
    <h1>@Server.MachineName</h1>
    <p class="lead">Fail? @ViewBag.Fail</p>
    <p><a href="/Home/MakeItUnavailable" class="btn btn-danger btn-lg">make this unavailable</a></p>
</div>

Por el lado del servidor solo necesito una variable estática que almacene si la instancia está fallando, una acción que modifique su valor y otra más que el balanceador pueda utilizar para comprobar que la máquina está fallando o no, con el fin de determinar que pueda recibir tráfico. Para que el balanceador tome una instancia como inválida debe devolver cualquier otro valor que no sea un HTTP 200. En mi ejemplo estoy lanzando una excepción en el código, es decir un HTTP 500.

using System;
using System.Web.Mvc;

namespace WebRole.Controllers
{
    public class HomeController : Controller
    {
        static bool fail = false;

        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }

        public void MakeItUnavailable()
        {
            fail = true;
        }

        public bool isFailing()
        {
            if (fail)
                throw new Exception();
            else
                return fail;
        }
    }
}

Por último falta modificar el archivo Service Definition para añadir un LoadBalancerProbe, que es lo que te ayudará a definir la ruta de la prueba que vas a lanzar para comprobar si una instancia está lista para recibir peticiones. Asimismo debes enlazar este elemento al InputEndpoint correspondiente. LoadBalancerProbe sólo acepta http y tcp.

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="CSLoadBalancerProbe" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
  <LoadBalancerProbes>
    <LoadBalancerProbe name="isFailing" path="/Home/isFailing" protocol="http" port="80" intervalInSeconds="5" />
  </LoadBalancerProbes>
  <WebRole name="WebRole" vmsize="Small">
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
      <Setting name="APPINSIGHTS_INSTRUMENTATIONKEY" />
    </ConfigurationSettings>
    <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" loadBalancerProbe="isFailing" />
    </Endpoints>
  </WebRole>
</ServiceDefinition>

Una vez que hagas clic sobre el botón rojo del ejemplo, podrás comprobar que la instancia que tiene a true el valor de la variable fail dejará de estar disponible (en teoría hasta que se solucione).

¡Saludos!