BLOG | NGINX

Cómo superar el agotamiento de puertos efímeros en NGINX y NGINX Plus

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Kevin Jones
Kevin Jones
Publicado el 19 de abril de 2016

NGINX y NGINX Plus son balanceadores de carga HTTP , TCP y UDP extremadamente potentes. Son muy eficientes a la hora de procesar grandes ráfagas de solicitudes y mantener una gran cantidad de conexiones simultáneas. Pero estas características hacen que NGINX y NGINX Plus estén particularmente sujetos al agotamiento efímero de puertos , una condición en la que no se pueden crear nuevas conexiones porque el sistema operativo se ha quedado sin los números de puerto asignados para establecer nuevos sockets locales. (El agotamiento del puerto efímero se aplica a ambos productos, pero por el bien de la brevedad nos referiremos solo a NGINX Plus en el resto de este blog).

En este blog, repasamos los componentes de una conexión TCP y cómo se decide su contenido antes de que se establezca una conexión. A continuación mostramos cómo determinar cuándo NGINX Plus se ve afectado por el agotamiento del puerto efímero. Por último, analizamos estrategias para combatir esas limitaciones utilizando ajustes del kernel de Linux y directivas NGINX Plus.

Una breve descripción general de los sockets de red

Cuando se establece una conexión a través de TCP, se crea un socket tanto en el host local como en el remoto. Estos sockets se conectan luego para crear un par de sockets, que se describe mediante una tupla única de 4 que consta de la dirección IP local y el puerto junto con la dirección IP remota y el puerto.

La dirección IP y el puerto remotos pertenecen al lado del servidor de la conexión y deben ser determinados por el cliente antes de poder iniciar la conexión. En la mayoría de los casos, el cliente elige automáticamente qué dirección IP local utilizar para la conexión, pero a veces la elige el software que establece la conexión. Finalmente, el puerto local se selecciona aleatoriamente de un rango definido que el sistema operativo pone a disposición. El puerto está asociado con el cliente sólo mientras dura la conexión, por eso se denomina efímero . Cuando se finaliza la conexión, el puerto efímero queda disponible para ser reutilizado.

Reconociendo el agotamiento efímero del puerto

Como se mencionó en la introducción, NGINX Plus por naturaleza está sujeto al agotamiento efímero del puerto y los problemas que esto causa. Cuando NGINX Plus envía una solicitud a un servidor ascendente, es el cliente en el proceso de creación de socket descrito anteriormente, y su comportamiento predeterminado es vincular el socket para la solicitud enviada automáticamente a una dirección IP local y un puerto efímero disponible en el host donde se está ejecutando. Si la tasa de conexión es alta, de modo que los sockets que se están estableciendo pasan a un estado de espera más rápido que el tiempo en que se cierran los sockets abiertos existentes, eventualmente los puertos disponibles se agotan y no se pueden crear nuevos sockets. Esto genera errores tanto en el sistema operativo como en NGINX Plus. A continuación se muestra un ejemplo del error resultante en el registro de errores de NGINX Plus.

18/03/2016 09:08:37 [crit] 1888#1888: *13 la conexión() a 10.2.2.77:8081 falló (99: No se puede asignar la dirección solicitada ) mientras se conecta al upstream, cliente: 10.2.2.42, servidor: , solicitud: "GET / HTTP/1.1", origen: "http://10.2.2.77:8081/", host: "10.2.2.77"

El agotamiento del puerto también provoca un aumento en500 errores originados por NGINX Plus en lugar del servidor ascendente. A continuación se muestra una entrada de muestra en el registro de acceso de NGINX Plus.

10.2.2.42 - - [18/Mar/2016:09:14:20 -0700] "GET / HTTP/1.1"500 192 "-" "rizo/7.35.0"

Para verificar la cantidad de sockets en el estado TIME-WAIT en su servidor NGINX Plus, ejecute el siguiente comando ss en el shell de Linux. El ejemplo muestra que hay 143 sockets abiertos con el estado TIME-WAIT . En el ejemplo, obtenemos el recuento utilizando el comando wc para enumerar la cantidad de líneas en la salida del comando.

# ss -a | grep TIEMPO-ESPERA | wc -l143

Ajuste del kernel para aumentar la cantidad de puertos efímeros disponibles

Una forma de reducir el agotamiento del puerto efímero es con la configuración net.ipv4.ip_local_port_range del kernel de Linux. El rango predeterminado más comúnmente es 32768 a 61000.

Si nota que se está quedando sin puertos efímeros, cambiar el rango predeterminado de 1024 a 65000 es una forma práctica de duplicar la cantidad de puertos efímeros disponibles para usar. Para obtener más información sobre cómo cambiar la configuración del kernel, consulte nuestra publicación de blog Cómo optimizar NGINX para mejorar el rendimiento .

Habilitación de conexiones Keepalive en NGINX Plus

Otra forma de reducir el agotamiento del puerto efímero es habilitar conexiones keepalive entre NGINX Plus y los servidores ascendentes. En la implementación más simple de HTTP, un cliente abre una nueva conexión, escribe la solicitud, lee la respuesta y luego cierra la conexión para liberar los recursos asociados.

Una conexión keepalive se mantiene abierta después de que el cliente lee la respuesta, de modo que puede reutilizarse para solicitudes posteriores.

Utilice la directiva keepalive para habilitar conexiones keepalive desde NGINX Plus a servidores ascendentes, definiendo la cantidad máxima de conexiones keepalive inactivas a servidores ascendentes que se conservan en la memoria caché de cada proceso de trabajo. Cuando se supera este número, se cierran las conexiones utilizadas menos recientemente. Sin keepalives, agrega más sobrecarga y resulta ineficiente tanto con las conexiones como con los puertos efímeros.

La siguiente configuración de ejemplo le indica a NGINX Plus que mantenga al menos 128 conexiones keepalive a los servidores definidos en el bloque ascendente llamado backend .

backend ascendente { servidor 10.0.0.100:1234;
servidor 10.0.0.101:1234;
keepalive 128;
}

Al habilitar conexiones keepalive a sus servidores ascendentes, también debe usar la directiva proxy_http_version para indicarle a NGINX Plus que use la versión HTTP 1.1, y la directiva proxy_set_header para eliminar cualquier encabezado llamado Connection . Ambas directivas se pueden colocar en los bloques de configuración http , servidor o ubicación .

proxy_http_version 1.1; proxy_set_header Conexión "";

Vinculación dinámica de conexiones a una lista definida de direcciones IP locales

Optimizar el kernel y habilitar conexiones keepalive proporciona mucho más control sobre la disponibilidad y el uso de puertos efímeros, pero hay ciertas situaciones en las que esos cambios no son suficientes para combatir el uso excesivo de puertos efímeros. En este caso podemos emplear algunas directivas y parámetros de NGINX Plus que nos permitan vincular un porcentaje de nuestras conexiones a direcciones IP locales estáticas. Esto multiplica efectivamente la cantidad de puertos efímeros disponibles por la cantidad de direcciones IP definidas en la configuración. Para lograr esto utilizamos las directivas proxy_bind y split_clients .

En la siguiente configuración de ejemplo, la directiva proxy_bind en el bloque de ubicación establece la dirección IP local durante cada solicitud de acuerdo con el valor de la variable $split_ip . Establecemos esta variable dinámicamente en el valor generado por el bloque split_clients , que utiliza una función hash para determinar ese valor.

El primer parámetro de la directiva split_clients es una cadena ( "$remote_addr$remote_port" ) que se codifica mediante una función MurmurHash2 durante cada solicitud. El segundo parámetro ( $split_ip ) es la variable que establecemos dinámicamente en función del hash del primer parámetro.

Las declaraciones dentro de las llaves dividen la tabla hash en “grupos”, cada uno de los cuales contiene un porcentaje de los hashes. Aquí dividimos la tabla en 10 cubos del mismo tamaño, pero podemos crear cualquier cantidad de cubos y no es necesario que todos sean del mismo tamaño. (El porcentaje del último segmento siempre se representa con un asterisco [ * ] en lugar de un número específico, porque la cantidad de hashes podría no ser divisible de manera uniforme en los porcentajes especificados).

El rango de valores hash posibles es de 0 a 4294967295, por lo que en nuestro caso cada depósito contiene aproximadamente 429496700 valores (10% del total): el primer depósito los valores de 0 a 429496700, el segundo depósito de 429496701 a 858993400, y así sucesivamente. La variable $split_ip se establece en la dirección IP asociada con el depósito que contiene el hash de la cadena $remote_addr$remote_port . Como ejemplo específico, el valor hash 150000000 cae en el cuarto grupo, por lo que la variable $split_ip se establece dinámicamente en 10.0.0.213 en ese caso.

http { servidor backend ascendente { servidor 10.0.0.100:1234; servidor 10.0.0.101:1234; } servidor { # ... ubicación / { # ... contraseña_de_proxy http://backend; enlace_de_proxy $ip_dividida; encabezado_de_conjunto_de_proxy X-Reenviado-Para $dirección_remota; } } clientes_divididos "$dirección_remota$puerto_remoto" $ip_dividida { 10% 10.0.0.210; 10% 10.0.0.211; 10% 10.0.0.212; 10% 10.0.0.213; 10% 10.0.0.214; 10% 10.0.0.215; 10% 10.0.0.216; 10% 10.0.0.217; 10% 10.0.0.218; * 10.0.0.219; } }

CONCLUSIÓN

Ajustar la configuración del kernel de Linux para la cantidad de puertos efímeros proporciona una disponibilidad y un uso más eficientes. Habilitar conexiones keepalive desde NGINX Plus a sus servidores ascendentes hace que su consumo de puertos efímeros sea más eficiente. Por último, el uso de las directivas split_clients y proxy_bind en su configuración de NGINX Plus le permite vincular dinámicamente conexiones salientes a una lista definida de direcciones IP locales, lo que aumenta en gran medida la cantidad de puertos efímeros disponibles para NGINX Plus.

Para probar NGINX Plus, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.