Cómo cerrar o eliminar instancias de AWS de un grupo ELB de forma elegante


Tengo una nube de instancias de servidor que se ejecutan en Amazon utilizando su equilibrador de carga para distribuir el tráfico. Ahora estoy buscando una buena manera de escalar con gracia la red hacia abajo, sin causar errores de conexión en el lado del navegador.

Por lo que sé, cualquier conexión de una instancia se terminará groseramente cuando se elimine del balanceador de carga.

Me gustaría tener una manera de informar a mi instancia como un minuto antes de que se apague o tener el balanceador de carga deje de enviar tráfico a la instancia que muere, pero sin terminar las conexiones existentes a ella.

Mi aplicación es node.js basado en Ubuntu. También tengo un software especial que se ejecuta en él, así que prefiero no usar los muchos nodos que ofrecen PAAS.js hosting.

Gracias por cualquier sugerencia.

Author: Johann Philipp Strathausen, 2011-10-05

6 answers

Esta idea utiliza la capacidad del ELB para detectar un nodo no saludable y eliminarlo del pool, PERO se basa en que el ELB se comporta como se espera en las suposiciones a continuación. Esto es algo que he querido probar por mí mismo, pero aún no he tenido tiempo. Actualizaré la respuesta cuando lo haga.

Descripción general del proceso

La siguiente lógica podría ser empaquetada y ejecutada en el momento en que el nodo necesita ser cerrado.

  1. Bloquear nuevas conexiones HTTP a nodeX pero continuar para permitir conexiones existentes
  2. Espere a que las conexiones existentes se agoten, ya sea supervisando las conexiones existentes a su aplicación o permitiendo una cantidad de tiempo "segura".
  3. Inicie un apagado en la instancia de Nodex EC2 usando la API de EC2 directamente o scripts abstractos.

"seguro" de acuerdo con su aplicación, que puede no ser posible determinar para algunas aplicaciones.

Supuestos que deben probarse

Sabemos que ELB elimina instancias no saludables de su piscina Esperaría que esto sea elegante, de modo que:

  1. Una nueva conexión a un puerto cerrado recientemente se redirigirá al siguiente nodo del grupo
  2. Cuando un nodo está marcado como Malo, las conexiones ya establecidas a ese nodo no se ven afectadas.

Posibles casos de prueba:

  • Disparar conexiones HTTP en ELB (por ejemplo, desde un script curl) resultados durante la apertura de un guión cierre de uno de los nodos Puertos HTTP. Usted tendría que experimentar para encontrar un cantidad de tiempo aceptable que permite al ELB determinar siempre un estado cambio.
  • Mantenga una sesión HTTP larga, (por ejemplo, descarga de archivos) mientras bloquea nueva Conexiones HTTP, la larga sesión debería continuar.

1. Cómo bloquear conexiones HTTP

Use un firewall local en nodeX para bloquear sesiones nuevas pero continúe permitiendo sesiones establecidas.

Por ejemplo IP cuadros:

iptables -A INPUT -j DROP -p tcp --syn --destination-port <web service port>
 16
Author: Ray Vahey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-11 10:37:33

Sé que esta es una pregunta antigua, pero debe tenerse en cuenta que Amazon ha agregado recientemente soporte para connection draining, lo que significa que cuando una instancia se elimina del loadbalancer, la instancia completará las solicitudes que estaban en curso antes de que la instancia se eliminara del loadbalancer. No se enrutarán nuevas solicitudes a la instancia que se eliminó. También puede proporcionar un tiempo de espera para estas solicitudes, lo que significa que cualquier solicitud que se ejecute más tiempo que la ventana de tiempo de espera se terminará después todo.

Para habilitar este comportamiento, vaya a la pestaña Instances de su equilibrador de carga y cambie el comportamiento Connection Draining.

 15
Author: Jaap Haagmans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-08 09:26:32

La forma recomendada de distribuir el tráfico desde su ELB es tener un número igual de instancias en varias zonas de disponibilidad. Por ejemplo:

ELB

  • Instancia 1 (us-east-a)
  • Instancia 2 (us-east-a)
  • Instancia 3 (us-east-b)
  • Instancia 4 (us-east-b)

Ahora hay dos API de ELB de interés siempre que le permitan separar instancias mediante programación (o a través del panel de control):

  1. Cancelar el registro instancia
  2. Deshabilitar una zona de disponibilidad (que posteriormente deshabilita las instancias dentro de esa zona)

La Guía para desarrolladores de ELB tiene una sección que describe los efectos de deshabilitar una zona de disponibilidad. Una nota en esa sección es de particular interés:

El equilibrador de carga siempre distribuye el tráfico a todos los Zonas de Disponibilidad. Si todas las instancias de una zona de disponibilidad son desregistrado o insalubre antes de esa Disponibilidad La zona está desactivada para el balanceador de carga, todas las solicitudes enviadas a esa zona de disponibilidad fallará hasta que DisableAvailabilityZonesForLoadBalancer lo solicite Zona de Disponibilidad.

Lo interesante de la nota anterior es que podría implicar que si llama DisableAvailabilityZonesForLoadBalancer, el ELB podría comenzar a enviar solicitudes instantáneamente solo a las zonas disponibles, lo que posiblemente resulte en una experiencia de tiempo de inactividad 0 mientras realiza el mantenimiento en los servidores zona de disponibilidad.

La 'teoría' anterior necesita pruebas detalladas o el reconocimiento de un ingeniero en la nube de Amazon.

 7
Author: Faraz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-03 07:54:07

Parece que ya ha habido una serie de respuestas aquí y algunas de ellas tienen buenos consejos. Pero creo que en general su diseño es defectuoso. No importa lo perfecto que diseñe su procedimiento de apagado para asegurarse de que la conexión de los clientes se cierre antes de apagar un servidor, todavía es vulnerable.

  1. El servidor podría perder energía.
  2. Un error de hardware hace que el servidor falle.
  3. La conexión podría cerrarse por un problema de red.
  4. El cliente pierde internet o wifi.

Podría seguir con la lista, pero mi punto es que en lugar de diseñar para que el sistema funcione siempre correctamente. Diseñarlo para manejar fallas. Si diseña un sistema que puede manejar un servidor que pierde energía en cualquier momento, entonces ha creado un sistema muy robusto. Esto no es un problema con el ELB esto es un problema con la arquitectura de sistema actual que tiene.

 4
Author: bwight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-04 16:03:43

No puedo comentar la causa de mi baja reputación. Aquí hay algunos fragmentos que elaboré que podrían ser muy útiles para alguien por ahí. Utiliza la herramienta aws cli para comprobar si una instancia se ha vaciado de conexiones.

Necesita una instancia ec2 con un servidor python proporcionado detrás de un ELB.

from flask import Flask
import time

app = Flask(__name__)

@app.route("/")
def index():
    return "ok\n"

@app.route("/wait/<int:secs>")
def wait(secs):
    time.sleep(secs)
    return str(secs) + "\n"

if __name__ == "__main__":
    app.run(
        host='0.0.0.0',
        debug=True)

Luego ejecute el siguiente script desde la estación de trabajo local hacia el ELB.

#!/bin/bash

which jq >> /dev/null || {
   echo "Get jq from http://stedolan.github.com/jq"
}

# Fill in following vars
lbname="ELBNAME"
lburl="http://ELBURL.REGION.elb.amazonaws.com/wait/30"
instanceid="i-XXXXXXX"

getState () {
    aws elb describe-instance-health \
        --load-balancer-name $lbname \
        --instance $instanceid | jq '.InstanceStates[0].State' -r
}

register () {
    aws elb register-instances-with-load-balancer \
        --load-balancer-name $lbname \
        --instance $instanceid | jq .
}

deregister () {
    aws elb deregister-instances-from-load-balancer \
        --load-balancer-name $lbname \
        --instance $instanceid | jq .
}

waitUntil () {
    echo -n "Wait until state is $1"
    while [ "$(getState)" != "$1" ]; do
        echo -n "."
        sleep 1
    done
    echo
}

# Actual Dance
# Make sure instance is registered. Check latency until node is deregistered

if [ "$(getState)" == "OutOfService" ]; then
    register >> /dev/null
fi

waitUntil "InService"

curl $lburl &
sleep 1

deregister >> /dev/null

waitUntil "OutOfService"
 2
Author: Loa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-23 10:46:50

Una advertencia que no se discutió en las respuestas existentes es que los ELB también usan registros DNS con TTLs de 60 segundos para equilibrar la carga entre múltiples nodos ELB (cada uno con una o más de sus instancias asociadas).

Esto significa que si tiene instancias en dos zonas de disponibilidad diferentes, probablemente tenga dos direcciones IP para su ELB con un TTL de 60s en sus registros A. Cuando elimina las instancias finales de dicha zona de disponibilidad, sus clientes "podrían" seguir utilizando la IP antigua dirección durante al menos un minuto: los resolutores DNS defectuosos podrían comportarse mucho peor.

Otra vez los ELBs usan múltiples IPs y tienen el mismo problema, es cuando en una sola zona de disponibilidad tiene un gran número de instancias que es demasiado para un servidor ELB para manejar. ELB en ese caso también creará otro servidor y agregará su IP a la lista de registros A con un TTL de 60 segundos.

 1
Author: Evgeny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-04 14:15:27