Ajuste de los parámetros de enrutamiento IP de Linux: secret_interval y tcp_mem

30

Hoy tuvimos un pequeño problema de conmutación por error con una de nuestras máquinas virtuales HAProxy. Cuando lo investigamos, encontramos esto:

26 de enero 07:41:45 kernel haproxy2: [226818.070059] __ratelimit: 10 devoluciones de llamada suprimidas
26 de enero 07:41:45 kernel haproxy2: [226818.070064] Memoria fuera de socket
26 de enero 07:41:47 kernel haproxy2: [226819.560048] Memoria fuera de socket
26 de enero 07:41:49 kernel haproxy2: [226822.030044] Memoria fuera de socket

Lo cual, según este enlace , aparentemente tiene que ver con una configuración predeterminada baja para net.ipv4.tcp_mem. Así que los aumentamos 4 veces de sus valores predeterminados (este es Ubuntu Server, no estoy seguro de si el sabor de Linux importa):

los valores actuales son: 45984 61312 91968
los nuevos valores son: 183936 245248 367872

Después de eso, comenzamos a ver un extraño mensaje de error:

26 de enero 08:18:49 kernel haproxy1: [2291.579726] ¡Ruta de hash chain demasiado larga!
26 de enero 08:18:49 kernel haproxy1: [2291.579732] ¡Ajuste su secret_interval!

Shh .. es un secreto!

Aparentemente, esto tiene que ver con /proc/sys/net/ipv4/route/secret_intervalel valor predeterminado de 600 y controla el vaciado periódico de la caché de ruta

Le secret_intervalindica al kernel con qué frecuencia debe eliminar TODAS las entradas de hash de ruta, independientemente de cuán nuevas / antiguas sean. En nuestro entorno, esto es generalmente malo. La CPU estará ocupada reconstruyendo miles de entradas por segundo cada vez que se borre el caché. Sin embargo, configuramos esto para que se ejecute una vez al día para mantener a raya las pérdidas de memoria (aunque nunca hemos tenido una).

Si bien nos complace reducir esto, parece extraño recomendar que se elimine toda la caché de la ruta a intervalos regulares , en lugar de simplemente eliminar los valores antiguos de la caché de la ruta más rápido.

Después de investigar un poco, encontramos /proc/sys/net/ipv4/route/gc_elasticitycuál parece ser una mejor opción para mantener el tamaño de la tabla de ruta bajo control:

gc_elasticityse puede describir mejor como la profundidad promedio del depósito que el núcleo aceptará antes de que comience a expirar las entradas de hash de ruta. Esto ayudará a mantener el límite superior de las rutas activas.

Ajustamos la elasticidad de 8 a 4, con la esperanza de que la caché de ruta se podara más agresivamente. El secret_intervalno se siente correcto para nosotros. Pero hay un montón de configuraciones y no está claro cuáles son realmente la forma correcta de llegar aquí.

  • / proc / sys / net / ipv4 / route / gc_elasticity (8)
  • / proc / sys / net / ipv4 / route / gc_interval (60)
  • / proc / sys / net / ipv4 / route / gc_min_interval (0)
  • / proc / sys / net / ipv4 / route / gc_timeout (300)
  • / proc / sys / net / ipv4 / route / secret_interval (600)
  • / proc / sys / net / ipv4 / route / gc_thresh (?)
  • rhash_entries (parámetro del kernel, ¿valor predeterminado desconocido?)

No queremos hacer el enrutamiento de Linux peor , así que estamos un poco de miedo a meterse con algunos de estos ajustes.

¿Alguien puede aconsejar qué parámetros de enrutamiento son mejores para ajustar, para una instancia de HAProxy de alto tráfico?

Jeff Atwood
fuente

Respuestas:

28

Nunca me encontré con este problema. Sin embargo, probablemente debería aumentar el ancho de la tabla hash para reducir su profundidad. Usando "dmesg", verá cuántas entradas tiene actualmente:

$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)

Puede cambiar este valor con el parámetro de línea de comando de arranque del kernel rhash_entries. Primero pruébelo a mano y luego agréguelo a su lilo.confo grub.conf.

Por ejemplo: kernel vmlinux rhash_entries=131072

Es posible que tenga una tabla hash muy limitada porque ha asignado poca memoria a su VM HAProxy (el tamaño hash de la ruta se ajusta según la RAM total).

En cuanto a tcp_mem, ten cuidado. Su configuración inicial me hace pensar que estaba ejecutando con 1 GB de RAM, 1/3 de los cuales podrían asignarse a sockets TCP. Ahora ha asignado 367872 * 4096 bytes = 1.5 GB de RAM a sockets TCP. Debe tener mucho cuidado de no quedarse sin memoria. Una regla general es asignar 1/3 de la memoria a HAProxy y otro 1/3 a la pila TCP y los últimos 1/3 al resto del sistema.

Sospecho que su mensaje de "memoria fuera de socket" proviene de la configuración predeterminada en tcp_rmemy tcp_wmem. Por defecto, tiene 64 kB asignados en la salida para cada socket y 87 kB en la entrada. Esto significa un total de 300 kB para una conexión proxy, solo para buffers de socket. Agregue a eso 16 o 32 kB para HAProxy, y verá que con 1 GB de RAM solo admitirá 3000 conexiones.

Al cambiar la configuración predeterminada de tcp_rmemy tcp_wmem( parámetro medio), puede obtener mucha menos memoria. Obtengo buenos resultados con valores tan bajos como 4096 para el búfer de escritura y 7300 o 16060 en tcp_rmem(5 u 11 segmentos TCP). Puede cambiar esas configuraciones sin reiniciar, sin embargo, solo se aplicarán a las nuevas conexiones.

Si prefiere no tocar demasiado sus sysctls , el último HAProxy, 1.4-dev8, le permite ajustar esos parámetros desde la configuración global y por lado (cliente o servidor).

¡Espero que esto ayude!

Willy Tarreau
fuente
8

El Out of socket memory errores a menudo engañoso. La mayoría de las veces, en servidores con conexión a Internet, no indica ningún problema relacionado con la falta de memoria. Como expliqué en detalles mucho mayores en una publicación de blog , la razón más común es la cantidad de enchufes huérfanos. Un socket huérfano es un socket que no está asociado a un descriptor de archivo. En ciertas circunstancias, el núcleo emitirá Out of socket memory erroraunque esté 2x o 4x lejos del límite ( /proc/sys/net/ipv4/tcp_max_orphans). Esto sucede con frecuencia en los servicios de Internet y es perfectamente normal. El curso de acción correcto en este caso es sintonizar tcp_max_orphanspara tener al menos 4 veces el número de huérfanos que normalmente ve con su tráfico máximo.

No hagas caso a los consejos que recomienda la sintonización tcp_memo tcp_rmemo tcp_wmemmenos que realmente sepa lo que está haciendo. Quienes dan estos consejos generalmente no lo hacen. Su vudú a menudo es incorrecto o inapropiado para su entorno y no resolverá su problema. Incluso podría empeorarlo.

tsuna
fuente
1
Cuando esto sucede, el mensaje es diferente en dmesg, verá "demasiados sockets huérfanos". Sin embargo, estoy de acuerdo con usted en que los huérfanos pueden consumir una gran cantidad de memoria.
Willy Tarreau
Cuando exceda el número de /proc/sys/net/ipv4/tcp_max_orphansusted experimentará un error diferente. La pila completa de Stack Exchange, por ejemplo, tiene /proc/sys/net/ipv4/tcp_max_orphans65536 y /proc/net/sockstatda como resultado TCP: inuse 2996 huérfano 171 tw 15972 alloc 2998 mem 1621, una diferencia que no se puede ignorar.
Geoff Dalgas
-4

Ajustamos algunos de estos parámetros regularmente. Nuestro estándar para plataformas comerciales de alto rendimiento y baja latencia es:

net.ipv4.tcp_rmem = 4096 16777216 33554432
net.ipv4.tcp_wmem = 4096 16777216 33554432
net.ipv4.tcp_mem = 4096 16777216 33554432
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 30000
net.core.netdev_max_backlog = 30000
Scott Alan Miller
fuente
1
Según las matemáticas de Willy, eso significa que su presión de memoria estándar # (número medio) es 68 GB ¿Tres veces (rmem, wmem, mem) ??
Jeff Atwood
10
Estos sintonizables son incorrectos y se encuentran con mucha frecuencia en entornos de banco y luego se copian a ciegas No tendrán ningún problema con solo unas pocas sesiones simultáneas, pero incluso con 100 sockets TCP, asignará 3.2 GB de RAM. Mientras la latencia sea baja, no notarás nada sospechoso. Solo tiene que desconectar una máquina remota durante una transferencia para ver cómo se llenan los búferes de salida, o congelar una tarea local y ver el llenado del búfer de entrada. Esto es una locura ...
Willy Tarreau
66
Jeff, esto no es tres veces. tcp_mem está en páginas y define el tamaño global. tcp_rmem y tcp_wmem están en bytes y definen el tamaño por socket.
Willy Tarreau
Esos tuneables parecen incorrectos, para servidores concurrentes con datos pequeños no desea reservar tantos buffers de socket y tcp_mem es totalmente diferente de r / wmem, usar los mismos números realmente no tiene sentido, (uno es bytes por Conexiones, el otro páginas por sistema)
eckes