Clúster web de applicaciones ASP.NET con Linux Virtual Server e IIS 6.0

En este post os describo como montar un cluster o web farming de IIS con aplicaciones ASP.NET utilizando como balanceador de carga entre nodos del clúster un Linux Virtual Server (LVS).

Como sabeis, cuando crece el número de usuarios web el escalado interno de vuestro servidor suele resolver a corto plazo el problema de atender gran numero de peticiones. Pero si teneis éxito en vuestra web 😉 y empieza a subir exponencialmente el número de peticiones, vais a tener que buscar otra solución: el escalado externo.

Las técnicas de Clustering o Webfarming permiten añadir servidores web o nodos formando un conjunto de máquinas que se reparten las peticiones http/https y si una está muy cargada o no disponible, otro nodo operativo resuelve la petición. Al final se logran entornos con alta disponibilidad y tolerante a fallos. Para realizar el balanceo de carga puede optarse por soluciones software como LVS o NLBs o por soluciones hardware como conmutadores de capa 7, también llamados conmutadores de capa de aplicación.

La solución más óptima es la última pero es muchísimo más cara (entre $30.000 y $60.000). Mediante software se puede montar un balanceo muy económico (tanto por hardware requerido como por licencias software) utilizando LVS.

Ya puestos en materia los aspectos a considerar son:

1.         La instalación de un Linux con LVS.

2.         La configuración de red y LVS del clúster.

3.         La persistencia de la sesión de las aplicaciones web.

Como la mayoría de nosotros estamos un poco más acostumbrados a los servidores Windows, seré algo más extenso en la configuración de LINUX y LVS.

Para simular el entorno utilicé vmware sobre un Debian ya que solo disponía un equipo con 1GB de RAM y necesitaba ejecutar 3 Windows 2003 Server y un LVS.

Instalación de LVS

Existen bastantes recursos en línea de cómo instalar LVS, concretamente yo lo instalé sobre un Debian con kernel 2.4.7 y la distribución UltraMonkey de LVS. También hay productos comerciales como Piranha de RedHat. En el sitio web de UltraMonkey está bastante detallado el proceso de instalación en debian para diversos escenarios.

En esencia, no es muy complicada, pero en mi kernel tuve que compilar e instalar los módulos de IPVS (el core del LVS) manualmente con insmod y activar el reenvío de paquetes ip (packet forwarding). Por cierto, tiene tres mecanismos para hacerlo y dependen un poco de la infraestructura de red que tengamos: Rutado directo, encapsulación IP a IP y NAT. Por comodidad yo elegí NAT en mi entorno de vmware.

IPVS no es simplemente un IP forwarding con un algoritmo de balanceo de carga. IPVS reconstruye los datagramas IP (layer 3) en el mensaje de capa de aplicación (Layer 4), como por ejemplo mensajes HTTP, y se lo manda completo (en uno o más paquetes IP) al nodo que lo va a resolver. Esto, que parece una tontería, es muy importante porque si no podrían llegar peticiones HTTP incompletas y el clúster funcionaría intermitentemente.

Aquí podéis ver el esquema de la red del clúster que monté.

El servidor con LVS se suele llamar Linux Director (LD). El esquema presentado está pensado para balanceo de carga con alta disponibilidad. En el caso de precisar tolerancia a fallos en el Linux Director se podría montar un nuevo servidor gemelo y configurarlo según la documentación  para que actúe como respaldo del Linux Director principal.

Fijaos que el LD tiene dos interfaces de red, uno público de cara al exterior (10.200.11.128) y uno interno para los servidores del cluster (10.200.10.128). Los nodos del cluster (wincluster01 y wincluster02) tienen como puerta de enlace principal la 10.200.10.128, de esta forma las respuestas de los wincluster llegan al cliente remoto enmascaradas con la ip 10.200.11.128 y no con la IP del nodo del clúster que ha respondido. Esto es imprescindible si estamos manteniendo el seguimiento de la sesión con cookies (así lo hace por defecto ASP.NET) y no queremos que se cree una nueva sesión cuando cambia el nodo que responde.

El fichero de configuración del ldirectord es ldirector.cf, ahí es dónde reflejaremos la estructura de nuestro clúster.

# Global Directives

checktimeout=10

checkinterval=2

autoreload=no

quiescent=yes

# A sample virtual with a fallback that will override the gobal setting

virtual=10.200.11.128:80

            real=10.200.10.129:80 masq

            real=10.200.10.130:80 masq

            #fallback=127.0.0.1:80 gate

            service=http

            request="/TestCluster"

            receive=".NET"

            scheduler=rr

            #persistent=600

            protocol=tcp

            checktype=negotiate

 

En ese fichero definimos el servidor virtual, 10.200.11.128:80 y los nodos reales (en este caso 2).  Con fallback podemos definir un servidor de respuesta en caso de que todos los nodos estén caídos.

Lo que me resultó curioso fue la forma de comprobar cada dos segundos (CheckInterval=2) qué nodos del cluster están activos. No envía un simple ping, en el caso de un servicio http o https hace una petición a una página de pruebas (request="/TestCluster") y busca una expresión regular en ella (receive=".NET"). En caso de no obtener respuesta (checktimeout=10) o no sea la esperada marca el servidor como caído y manda la petición HTTP a otro lado del cluster. El algoritmo de balanceo para este clúster es RoundRobin (rr), pero hay muchos más. Por ejemplo, si tenemos servidores con distinta capacidad podemos usar Weighted Round Robin (wrr) y darle pesos adecuados (entre 0 y 1) a los nodos. A menor peso, menos peticiones a resolver.

¿Y cómo sabemos que todo marcha?, fácil, tenemos unas cuantas herramientas para ello. La primera es mirar el syslog y ver que el deamon ldirectord ha arrancado perfectamente. Luego podemos utilizar ipvsadm, nos informará de los nodos definidos, su peso actual (0 – inactivo, 1- activo) y el número de conexiones activas.

Además pueden consultarse estadísticas que serían representables con software de monitorización.

#ipvsadm

IP Virtual Server version 1.0.11 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  10.200.11.128:www rr

  -> 10.200.10.129:www            Masq    1      1          0        

  -> 10.200.10.130:www            Masq    1      0          1         

#ipvsadm -Ln –stats

IP Virtual Server version 1.0.11 (size=4096)

Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes

  -> RemoteAddress:Port

TCP  10.200.11.128:80                   16     1105      536   316196   732713

  -> 10.200.10.129:80                    8      690      337   194315   468421

  -> 10.200.10.130:80                    8      415      199   121881   264292

 

En caso de problemas os recomiendo que utilicéis tcpdump, aunque no os conozcáis el protocolo IP al detalle os puede ayudar a resolver problemas en la configuración de red o de ldirectord.

Una vez que el LD está funcionando vamos a configurar los nodos para que puedan ejecutar aplicaciones ASP.NET en el clúster.

Una vez que el LD está funcionando vamos a configurar los nodos para que puedan ejecutar aplicaciones ASP.NET en el clúster.

 

Persistencia de sesión

La sesión de las aplicaciones web contienen el contexto de ejecución del cliente remoto. Supongo que es un concepto que conocereis todos ;-). La sesión se almacena en la memoria del servidor, el cliente remoto utiliza cookies o parámetros en el POST para identificarse en el servidor en cada petición y que éste sepa asociar los contenidos de una sesión determinada con el cliente correcto.

Lo interesante es que en un clúster hay varios nodos y una petición http puede ser resuelta por cualquier nodo activo del clúster. Si el nodo del clúster no tiene en memoria los datos de la sesión del cliente, porque fue creada en otro nodo, tenemos un problema realmente grave ya que no se puede recuperar el contexto de la aplicación.

Existen dos enfoques para resolver peticiones http a una aplicación web dentro de un clúster y no tener el problema mencionado:

El primer enfoque utiliza afinidad de nodo (sticky sessions, persistent connections…) en esencia: si un nodo crea una sesión para un cliente, ese nodo resuelve todas las peticiones del cliente remoto para esa sesión.

Es una aproximación sencilla pero no hay tolerancia a fallos real. Si un nodo se cae, lo hace con las sesiones de sus clientes. Además si un nodo esta cargado los que hayan iniciado sesión allí no pueden moverse a otro nodo menos saturado.

En el segundo enfoque cualquier nodo del clúster puede responder la petición. Para eso es necesario que todos los nodos tengan acceso a los datos de las sesiones de los clientes.

Con ASP.NET es posible compartir la sesión de dos formas: en la memoria o en un SqlServer de un servidor al que preguntan los nodos para recuperar una sesión activa.

Esta aproximación sí es tolerante a fallos (respecto a los nodos del clúster) y mejora el rendimiento. Aunque hay un punto único de fallo. Para evitarlo sería necesario montar dos SqlServers para mantener la sesión con replicación.

En mi caso monté el gestor de sesiones en memoria dentro de un Server 2003. Basta con iniciar el servicio "Servicio de estado de ASP.NET". Si bien hay que tocar el registro de windows para indicarle que acepte conexiones remotas y reiniciar el servicio.

Concretamente hay que darle un valor positivo a la clave:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesaspnet_stateParametersAllowRemoteConnection

Ahí también podéis cambiarle el puerto por defecto, que es el 42424.

Ahora hay que decirle a las aplicaciones ASP.NET dónde deben gestionar la sesión.

Para .Net 1.1 hay que tocar el web.config de la aplicación y modificar la forma de mantener la sesión:

    <sessionState

            mode="StateServer"

            stateConnectionString="tcpip=10.200.10.131:42424"

            cookieless="false"

            timeout="20"

    />

Para probarlo cree una pequeña página .aspx que incrementa una variable de sesión en cada invocación e informa del nombre de la máquina que resuelve la petición junto con el código de sesión.

Esta aplicación debe montarse en el mismo directorio virtual de IIS en todos los nodos. En una ejecución típica y para el entorno descrito podemos obtener resultados como los que siguen.

Petición a http://10.200.11.128/TestCluster

Postback 1:

Fecha:  13/09/2006 10:19:06

Servidor: WINCLUSTER01 (10.200.10.129)

Sesión: epeh12552w2blr45u2nhur2e (nueva)

Timeout: 20 min.

Counter (sesión): 1

Postback 2:

Fecha: 13/09/2006 10:19:07

Servidor: WINCLUSTER02 (10.200.10.130)

Sesión: epeh12552w2blr45u2nhur2e (vieja)

Timeout: 20 min.

Counter (sesión): 2

En el primer post se crea una nueva sesión y la crea el nodo WINCLUSTER01. El contador, que se almacena en la sesión, comienza en 1. Se hace una recarga de la página y el segundo post es contestado por el nodo WINCLUSTER02. Se observa que la sesión es la misma y se ha incrementado el counter almacenado en la sesión.

Hice varias pruebas tumbando algún nodo del clúster y no hubo ningún problema. En cuanto el servidor Linux Director detecta que un nodo no le devuelve la página de pruebas le asigna un peso 0, lo descarta y busca otro nodo según el algoritmo de balanceo. El cliente sufre un retraso de 1 segundo pero recupera el flujo normal de la aplicación.

Conclusiones

El aumento de tráfico de un sitio web solo puede ser atendido con una solución basada en clústers. Lo ideal es garantizar alta disponibilidad y tolerancia a fallos. En este artículo se describe una solución de clustering para ASP.NET basada en tecnología heterogénea (Linux/OpenSource, Windows/Microsoft). Utilizando Linux/LVS puedes dedicar hardware relativamente antiguo como equipo LinuxDirector y evitarte alguna licencia de 2003 para hacer NLB.

Las ventajas de clustering son la alta disponibilidad y una tolerancia a fallos total o parcial (dependiendo del esquema elegido y los puntos de fallo únicos). Incluso con un número pequeño de usuarios, si la aplicación es crítica, merece la pena optar por un esquema como el presentado.

Queda para un futuro una prueba de rendimiento de NLB y LVS

Espero que os haya gustado! y si alguna parte os queda poco clara u oscura comentádmelo y amplío el post.

5 comentarios en “Clúster web de applicaciones ASP.NET con Linux Virtual Server e IIS 6.0”

  1. Hola le escribo desde cuba ..me interesa mucho el tema de linux virtual server y veo que esta muy buena la opcion de como manejan esta herramienta …yo estoy haciendo un trabajo de tesis para graduarme este año en cuba y debo montar un servidor virtual de linux es decir un LVS en los para servidores proxy aplicaciones web y bases de datos en los servidores de mi universidad (UCI). y necesito si es posible informacion con respecto a esto para hacer una buena invstigacion y que mi propuesta sea utilizada. mi email es agarciab@estudiantes.uci.cu seria de una magnifica ayuda si me guiaran sobre esto
    gracias

  2. Este artículo apesta. Solo siembra mas dudas y frustraciones de los no expertos en Linux. No solo se trata de generalizar se necesitan muchos detalles para realizar este tipo de trabajos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *