Aumentar el número máximo de conexiones TCP / IP en Linux

214

Estoy programando un servidor y parece que mi número de conexiones está limitado ya que mi ancho de banda no está saturado, incluso cuando he establecido el número de conexiones en "ilimitado".

¿Cómo puedo aumentar o eliminar un número máximo de conexiones que mi caja de Ubuntu Linux puede abrir a la vez? ¿El sistema operativo limita esto, o es el enrutador o el ISP? ¿O es otra cosa?

red0ct
fuente
2
@Software Monkey: respondí esto de todos modos porque espero que esto pueda ser útil para alguien que realmente esté escribiendo un servidor en el futuro.
derobert
1
@derobert: vi que +1. En realidad, tuve el mismo pensamiento después de mi comentario anterior, pero pensé que dejaría el comentario en pie.
Lawrence Dol el

Respuestas:

395

El número máximo de conexiones se ve afectado por ciertos límites tanto en el lado del cliente como del servidor, aunque de manera un poco diferente.

En el lado del cliente: aumente el rango de puertos ephermal y disminuya eltcp_fin_timeout

Para conocer los valores predeterminados:

sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.tcp_fin_timeout

El rango de puertos ephermal define el número máximo de sockets salientes que un host puede crear desde una dirección IP particular. El fin_timeoutdefine el tiempo mínimo de estas tomas permanecerán en TIME_WAITestado (inutilizable después de ser utilizado una vez). Los valores predeterminados habituales del sistema son:

  • net.ipv4.ip_local_port_range = 32768 61000
  • net.ipv4.tcp_fin_timeout = 60

Esto básicamente significa que su sistema no puede garantizar consistentemente más de (61000 - 32768) / 60 = 470sockets por segundo. Si no está satisfecho con eso, podría comenzar aumentando el port_range. Establecer el rango en 15000 61000es bastante común en estos días. Podría aumentar aún más la disponibilidad disminuyendo el fin_timeout. Suponga que hace ambas cosas, debería ver más de 1500 conexiones salientes por segundo, más fácilmente.

Para cambiar los valores :

sysctl net.ipv4.ip_local_port_range="15000 61000"
sysctl net.ipv4.tcp_fin_timeout=30

Lo anterior no debe interpretarse como los factores que afectan la capacidad del sistema para realizar conexiones salientes por segundo. Pero más bien, estos factores afectan la capacidad del sistema para manejar conexiones concurrentes de manera sostenible durante grandes períodos de "actividad".

Los valores predeterminados de Sysctl en un cuadro típico de Linux para tcp_tw_recycley tcp_tw_reuseserían

net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=0

Estos no permiten una conexión desde un zócalo "usado" (en estado de espera) y obligan a los zócalos a durar el time_waitciclo completo . Recomiendo configurar:

sysctl net.ipv4.tcp_tw_recycle=1
sysctl net.ipv4.tcp_tw_reuse=1 

Esto permite un ciclo rápido de los enchufes en time_waitestado y su reutilización. Pero antes de hacer este cambio, asegúrese de que no entre en conflicto con los protocolos que usaría para la aplicación que necesita estos sockets. Asegúrese de leer la publicación "Enfrentando el TCP TIME-WAIT" de Vincent Bernat para comprender las implicaciones. La net.ipv4.tcp_tw_recycle opción es bastante problemática para los servidores públicos, ya que no manejará las conexiones de dos computadoras diferentes detrás del mismo dispositivo NAT , lo cual es un problema difícil de detectar y espera para morderte. Tenga en cuenta que net.ipv4.tcp_tw_recyclese ha eliminado de Linux 4.12.

En el lado del servidor: el net.core.somaxconnvalor tiene un papel importante. Limita el número máximo de solicitudes en cola a un socket de escucha. Si está seguro de la capacidad de su aplicación de servidor, aumente el valor predeterminado de 128 a algo así como 128 a 1024. Ahora puede aprovechar este aumento modificando la variable de backlog de escucha en la llamada de escucha de su aplicación, a un número entero igual o superior.

sysctl net.core.somaxconn=1024

txqueuelenEl parámetro de sus tarjetas Ethernet también tiene un papel que desempeñar. Los valores predeterminados son 1000, por lo tanto, amplíelos hasta 5000 o incluso más si su sistema puede manejarlo.

ifconfig eth0 txqueuelen 5000
echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local

Del mismo modo aumentar los valores de net.core.netdev_max_backlogy net.ipv4.tcp_max_syn_backlog. Sus valores predeterminados son 1000 y 1024 respectivamente.

sysctl net.core.netdev_max_backlog=2000
sysctl net.ipv4.tcp_max_syn_backlog=2048

Ahora recuerde iniciar las aplicaciones del lado del cliente y del servidor aumentando los límites de FD en el shell.

Además de la técnica anterior más utilizada por los programadores, es reducir la cantidad de llamadas de escritura tcp . Mi preferencia es usar un búfer en el que inserto los datos que deseo enviar al cliente y luego, en los puntos apropiados, escribo los datos almacenados en el zócalo real. Esta técnica me permite usar grandes paquetes de datos, reducir la fragmentación, reduce la utilización de mi CPU tanto en el terreno del usuario como a nivel del núcleo.

mdk
fuente
44
Respuesta brillante! Mi problema era un poco diferente, es decir, estaba tratando de mover la información de sesión de un almacenamiento de sesión de nivel de aplicación a redis vía PHP. Por alguna razón, no pude agregar más de 28230 sesiones sin agregar mucho sueño de una sola vez, sin errores vistos ni en php ni en los registros de redis. Rompimos nuestras cabezas sobre esto durante todo un día hasta que pensé que tal vez el problema no es con php / redis sino en la capa tcp / ip que conecta los dos y llegué a esta respuesta. Logramos solucionar el problema en poco tiempo :) ¡Muchas gracias!
s1d
27
No olvide que siempre estamos hablando del puerto IP +. Puede tener sockets "ilimitados" abiertos al puerto XY desde muchas IP diferentes. El límite de 470 se aplica a los sockets abiertos concurrentes a la misma IP solamente. Otra IP puede tener sus propias conexiones 470 a los mismos puertos.
Marki555
66
@ Marki555: Tu comentario es MUY CORRECTO. Las aplicaciones desarrolladas para generar y mantener una gran cantidad de conexiones salientes, deben tener un "conocimiento" de las direcciones IP disponibles para crear conexiones salientes, y luego deben unirse adecuadamente a estas direcciones IP utilizando algún tipo de "algoritmo round-robin" y mantener un "marcador".
mdk
8
Esta respuesta tiene errores. Primero, net.ipv4.tcp_fin_timeout es solo para el estado FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). En segundo lugar, como dijo @Eric, "470 tomas en un momento dado" no es correcto.
Sharvanath
3
@mdk: no estoy claro con esta parte de cálculo (61000 - 32768) / 60 = 470 sockets per second. ¿Puedes por favor elaborar esto?
Tom Taylor
64

Hay un par de variables para establecer el número máximo de conexiones. Lo más probable es que primero te estés quedando sin números de archivo. Verifique ulimit -n. Después de eso, hay configuraciones en / proc, pero las predeterminadas son decenas de miles.

Más importante aún, parece que estás haciendo algo mal. Una sola conexión TCP debería ser capaz de usar todo el ancho de banda entre dos partes; si no lo es:

  • Compruebe si la configuración de su ventana TCP es lo suficientemente grande. Los valores predeterminados de Linux son buenos para todo, excepto para enlaces inet realmente rápidos (cientos de mbps) o enlaces satelitales rápidos. ¿Cuál es su producto de retraso de ancho de banda *?
  • Verifique la pérdida de paquetes usando ping con paquetes grandes ( ping -s 1472...)
  • Verifique la limitación de velocidad. En Linux, esto se configura contc
  • Confirme que el ancho de banda que cree que existe realmente existe, por ejemplo, iperf
  • Confirme que su protocolo es cuerdo. Recuerda la latencia.
  • Si se trata de una LAN gigabit +, ¿puede usar paquetes jumbo? ¿Es usted?

Posiblemente he entendido mal. Tal vez estás haciendo algo como Bittorrent, donde necesitas muchas conexiones. Si es así, debe averiguar cuántas conexiones está utilizando realmente (intente netstato lsof). Si ese número es sustancial, podría:

  • Tiene mucho ancho de banda, por ejemplo, 100mbps +. En este caso, es posible que necesite subir el ulimit -n. Aún así, ~ 1000 conexiones (por defecto en mi sistema) son bastantes.
  • Tiene problemas de red que ralentizan sus conexiones (por ejemplo, pérdida de paquetes)
  • Haga que algo más lo desacelere, por ejemplo, el ancho de banda de E / S, especialmente si lo está buscando. ¿Lo has comprobado iostat -x?

Además, si está utilizando un enrutador NAT de nivel de consumidor (Linksys, Netgear, DLink, etc.), tenga en cuenta que puede exceder sus capacidades con miles de conexiones.

Espero que esto ayude un poco. Realmente estás haciendo una pregunta sobre redes.

derobert
fuente
16

Para mejorar la respuesta dada por derobert,

Puede determinar cuál es el límite de conexión de su sistema operativo capturando nf_conntrack_max.

Por ejemplo: cat / proc / sys / net / netfilter / nf_conntrack_max

Puede usar el siguiente script para contar el número de conexiones tcp a un rango determinado de puertos tcp. Por defecto 1-65535.

Esto confirmará si está maximizando o no el límite de conexión de su sistema operativo.

Aquí está el guión.

#!/bin/bash
OS=$(uname)

case "$OS" in
    'SunOS')
            AWK=/usr/bin/nawk
            ;;
    'Linux')
            AWK=/bin/awk
            ;;
    'AIX')
            AWK=/usr/bin/awk
            ;;
esac

netstat -an | $AWK -v start=1 -v end=65535 ' $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ {
    if ($1 ~ /\./)
            {sip=$1}
    else {sip=$4}

    if ( sip ~ /:/ )
            {d=2}
    else {d=5}

    split( sip, a, /:|\./ )

    if ( a[d] >= start && a[d] <= end ) {
            ++connections;
            }
    }
    END {print connections}'
whitehat237
fuente
3
which awkes tu amigo para determinar el camino hacia awk, SunOS también tiene un enlace :)
Panagiotis Moustafellos
2
@PanagiotisM. whichse basa en el programa, PATHen cuyo caso puede usarlo en awklugar de proporcionar la ruta completa. (Dicho esto, no estoy seguro de si la solución en el script está más cerca de la perfección, pero de esto no se trata el script).
Michael Krelin - pirata informático
55
Me encanta cómo este script se vuelve balístico para determinar la awkubicación, pero asume que Shell siempre es /bin/bash (consejo profesional: AIX5 / 6 ni siquiera tiene bash por defecto).
kubanczyk
¿Es awkútil la detección? Personalmente me gustaría asumir simplemente para tener una correcta PATHsino una alternativa razonable podría ser /usr/bin/env awky /usr/bin/env bash, respectivamente. Por lo que vale, se equivocó de ubicación en mi sistema Linux. Está en /usr/bin/awkno/bin/awk
Wolph
1
cuando ejecuto este script obtengo 798, entonces, ¿qué significa?
10

En un nivel de aplicación, aquí hay algo que un desarrollador puede hacer:

Del lado del servidor:

  1. Compruebe si el equilibrador de carga (si lo tiene) funciona correctamente.

  2. Convierta los tiempos de espera TCP lentos en 503 Respuesta inmediata rápida, si el equilibrador de carga funciona correctamente, debería elegir el recurso de trabajo para servir, y es mejor que quedarse allí con masajes de error inesperados.

Por ejemplo: si está usando un servidor de nodo, puede usar demasiado ocupado desde npm. Implementación algo como:

var toobusy = require('toobusy');
app.use(function(req, res, next) {
  if (toobusy()) res.send(503, "I'm busy right now, sorry.");
  else next();
});

¿Por qué 503? Aquí hay algunas buenas ideas para la sobrecarga: http://ferd.ca/queues-don-t-fix-overload.html

También podemos hacer algo de trabajo en el lado del cliente:

  1. Intente agrupar las llamadas por lotes, reduzca el tráfico y el número total de solicitudes en blanco y negro cliente y servidor.

  2. Intente construir una capa intermedia de caché para manejar solicitudes duplicadas innecesarias.

Kev
fuente