0

Balanceo de carga con el plug-in en un entorno clusterizado

balancingLos servidores IHS distribuyen las peticiones en entornos clusterizados siguiendo el algoritmo Round Robin. Para ello, a cada servidor de aplicaciones miembro de un cluster se le asigna un “peso” en dicho algoritmo en el fichero plugin-config.xml.

En muchas aplicaciones se utilizan las sesiones HTTP para manejar información sobre el estado de dicha petición. Los IHS tratan que todas las peticiones HTTP asociadas a una sesión sean atendidas por el servidor “dueño” de esa sesión (el que atendió la primera petición).

El funcionamiento del plugin en los IHS V5.0, V5.1 y V6.0 es así:

1.- El plugin HTTP crea una tabla interna de ruteo, asignando los pesos a los distintos miembros del cluter. Los pesos de esta tabla de ruteo se calculan partiendo de los pesos declarados en el fichero plugin-cfg.xml y dividiéndolos por su divisor común. Por ejemplo: si los pesos del plugin-cfg.xml para tres miembros de un cluster son 8,6 y 18, la tabla de ruteo asignará 4, 3 y 9 (divide los pesos entre 2, que es el divisor común).

<ServerCluster CloneSeparatorChange=”false” LoadBalance=”Round Robin”
Name=”Server_WebSphere_Cluster” PostSizeLimit=”10000000″ RemoveSpecialHeaders=”true” RetryInterval=”60″>

<Server CloneID=”10k66djk2″ ConnectTimeout=”0″ ExtendedHandshake=”false” LoadBalanceWeight=”8″ MaxConnections=”0″ Name=”Server1_WebSphere_Appserver” WaitForContinue=”false”>
<Transport Hostname=”server1.domain.com” Port=”9091″ Protocol=”http”/>
</Server>

<Server CloneID=”10k67eta9″ ConnectTimeout=”0″ ExtendedHandshake=”false”
LoadBalanceWeight=”6″ MaxConnections=”0″ Name=”Server2_WebSphere_Appserver” WaitForContinue=”false”>
<Transport Hostname=”server2.domain.com” Port=”9091″ Protocol=”http”/>
</Server>

<Server CloneID=”10k68xtw10″ ConnectTimeout=”0″ ExtendedHandshake=”false” LoadBalanceWeight=”18″ MaxConnections=”0″ Name=”Server3_WebSphere_Appserver” WaitForContinue=”false”>
<Transport Hostname=”server3.domain.com” Port=”9091″ Protocol=”http”/>
</Server>

<PrimaryServers>
<Server Name=”Server1_WebSphere_Appserver”/>
<Server Name=”Server2_WebSphere_Appserver”/>
<Server Name=”Server3_WebSphere_Appserver”/>
</PrimaryServers>
</ServerCluster>

2.- La primera petición se asignará de manera aleatoria a alguno de los miembros del cluster. Para las peticiones que no tengan permanencia de sesión, el algoritmo Round Robin las irá distribuyendo entre los miembros del cluster que tengan un peso mayor a cero.

3.- Cada petición atendida por un miembro del cluster (tenga permanencia de sesión o no) bajará un punto el peso actual de ese miembro.

4.- Las peticiones sin permanencia de sesión nunca serán enviadas por el plugin a miembros del cluster cuyo peso actual en ese momento sea menor o igual a cero. Sin embargo, aquellas que tienen configurada permanencia de sesión sí que pueden ser atendidas por servidores con peso menor o igual a cero, llegando incluso a dejar el valor del peso en números negativos.

5.- Cuando el valor del peso de todos los miembros del cluster llega a ser menor o igual a cero, el plugin resetea los valores de los pesos en su tabla interna de ruteo. Esto no significa que los pesos vuelvan a sus valores iniciales, sino que lo hará calculando un valor (M) mediante la siguiente fórmula:

W + M * S

Siendo W el valor actual del peso (antes de reseteralo) y S el peso incial de ese miembro en la tabla interna de ruteo. M será el el número más bajo (mayor que cero, claro) que hará que se cumpla (W + M * s) > 0 en todos y cada uno de los miembros del cluster.

En nuestro ejemplo anterior, con los pesos de la tabla interna de ruteo configurados a 4, 3 y 9 y asumiendo que los pesos actuales antes del reseteo es de -20, -40 y 0 el valor M sería 14 y los pesos quedarían configurados tras el reseteo 36, 2 y 126.

(-20 + 14 * 4), (-40 + 14 * 3), (0 + 14 * 9) = 36, 2, 126

Ejemplo

1.- Tenemos un cluster formado por Server1 y Server2 con un peso de 1 cada uno, usando el balanceo Round Robin.

2.- Si la primera petición se manda al Server1, este pasa a tener un peso de 0.

3.- Si las próximas 10 peticiones tienen permanencia de sesión con el Server1 serán atendidas por el mismo servidor, pasando ahora a tener un peso de -10. En este momento el Server1 ha atendido 11 peticiones y el Server2 ninguna.

4.- La siguiente petición sin permanencia de sesión será atendida por el Server2, que pasa a tener un peso de 0.

5.- En el momento que llega la tercera petición sin permanencia de sesión, ni el Server1 ni el Server2 tienen un valos positivo en su peso actual (-10, 0). El plugin reseteará los valores en ese momento, pasando a ser 1 y 11 para cada servidor respectivamente (el valor M citado en la fórmula anterior).

6.- La tercera petición sin permanencia de sesión pasará entonces a ser atendida por el Server1, pasando su peso a 0.

7.- Las siguientes 11 peticiones sin permanencia de sesión van a ser atendidas por el Server2, hasta dejar su peso a 0.

8.- De esta manera la distribución de estas 24 peticiones (siendo nuevas 14 de ellas) habría quedado de la siguiente manera:

  • Server1: 12 peticiones, 10 con permanencia de sesión y 2 sin ella
  • Server2: 12 peticiones, todas ellas sin permanencia de sesión.

9.- Ahora, en el supuesto de que cada sesión generase 10 peticiones con permanencia, la distribución de la carga pasaría a estar mal balanceada:

  • Server1: 22 peticiones, 20 con permanencia de sesión
  • Server2: 132 peticiones, 120 con permanencia de sesión.

Esto nos descubre un riesgo conocido del plugin: la permanencia de sesión puede afectar a la distribución de la carga. La desviación depende, básicamente, de dos factores:

  • El número de peticiones con permanencia de sesión recibidas por un miembro del cluster, haciendo que su peso sea un alto número negativo.
  • El uso concurrente de múltiples sesiones HTTP y sus correspondientes permanencias de sesión en un miembro del cluster, haciendo también que su peso baje a elevados valores negativos.

Lógicamente, un mayor número de usuarios incrmenta la presencia de estos patrones de tráfico. Lo peor de todo es que no existe una forma de solucionar ésto, aunque sí que podemos minimizar los riesgos con un par de configuraciones:

  • Configurar un peso inicial elevado en el plugin-cfg.xml. Con esto evitamos los reseteos frecuentes, que los valores del peso en cada miembro del cluster alcancen valores negativos muy altos y que el valor del peso tras un reseteo siga siendo alto.
  • Usar una versión de IHS que soporte multithreading (por ejemplo la V6.0 de UNIX). Mantener un número de procesos IHS bajo y elevar el número de hilos por proceso (esto se modifica en el httpd.conf).

Sugerencias de configuración

Configurar el algoritmo de balanceo como “Random” en el plugin-cfg.xml. De esta forma no se incluye el número de sesiones con permanencia al elegir un servidor para atender la petición.

<ServerCluster CloneSeparatorChange=”false” LoadBalance=”Random”
Name=”Server_WebSphere_Cluster” PostSizeLimit=”10000000″ RemoveSpecialHeaders=”true” RetryInterval=”60″>

<Server CloneID=”10k66djk2″ ConnectTimeout=”0″ ExtendedHandshake=”false” LoadBalanceWeight=”2″ MaxConnections=”0″ Name=”Server1_WebSphere_Appserver” WaitForContinue=”false”>
<Transport Hostname=”server1.domain.com” Port=”9091″ Protocol=”http”/>
</Server>

<Server CloneID=”10k67eta9″ ConnectTimeout=”0″ ExtendedHandshake=”false”
LoadBalanceWeight=”2″ MaxConnections=”0″ Name=”Server2_WebSphere_Appserver” WaitForContinue=”false”>
<Transport Hostname=”server2.domain.com” Port=”9091″ Protocol=”http”/>
</Server>

<PrimaryServers>
<Server Name=”Server1_WebSphere_Appserver”/>
<Server Name=”Server2_WebSphere_Appserver”/>
</PrimaryServers>
</ServerCluster>

En las versiones 2.0 y 6.0 de IHS para UNIX se puede modificar a mano el módulo <IfModule worker.c> para que el número de procesos sea igual a 2 (lo que asegura un balanceo homogéneo entre los miembros del cluster) y el número de hilos igual a 250 (adecuado para atender los picos de carga en entornos clusterizados).

<IfModule worker.c>
ThreadLimit 250
ServerLimit 2
StartServers 2
MaxClients 500
MinSpareThreads 2
MaxSpareThreads 325
ThreadsPerChild 250
MaxRequestsPerChild 10000
</IfModule>

Deja un comentario

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