
Estoy ejecutando una serie de pruebas de carga para determinar el rendimiento de la siguiente configuración:
Node.js test suite (client) --> StatsD (server) --> Graphite (server)
En resumen, el conjunto de pruebas de node.js envía una cantidad determinada de métricas cada x segundos a una instancia de StatsD que se encuentra en otro servidor. Luego, StatsD, a su vez, envía las métricas cada segundo a una instancia de Graphite ubicada en el mismo servidor. Luego miro cuántas métricas envió realmente el conjunto de pruebas y cuántas recibió Graphite para determinar la pérdida de paquetes entre el conjunto de pruebas y Graphite.
Sin embargo, noté que a veces obtenía tasas de caída de paquetes muy altas (tenga en cuenta que se envían con el protocolo UDP), que oscilan entre el 20 y el 50%. Fue entonces cuando comencé a investigar dónde se descartaban estos paquetes, ya que podría haber algún problema de rendimiento con StatsD. Entonces comencé a registrar las métricas en cada parte del sistema para rastrear dónde ocurrió esta caída. Y aquí es donde las cosas se ponen raras.
Estoy usandotcpdumppara crear un archivo de captura que inspecciono una vez finalizada la ejecución de la prueba. Pero cada vez que ejecuto las pruebas con tcpdump en ejecución, ¡la pérdida de paquetes es casi inexistente! Parece que tcpdump está aumentando de alguna manera el rendimiento de mis pruebas y no puedo entender por qué ni cómo lo hace. Estoy ejecutando el siguiente comando para registrar los mensajes tcpdump tanto en el servidor como en el cliente:
tcpdump -i any -n port 8125 -w test.cap
En un caso de prueba particular, estoy enviando 40000 métricas/s. La prueba mientras se ejecuta tcpdump tiene una pérdida de paquetes de aproximadamente el 4%, mientras que la que no la realiza tiene una pérdida de paquetes de aproximadamente el 20%.
Ambos sistemas se ejecutan como máquinas virtuales Xen con la siguiente configuración:
- Intel Xeon E5-2630 v2 a 2,60 GHz
- 2 GB de RAM
- Ubuntu 14.04 x86_64
Cosas que ya verifiqué para detectar posibles causas:
- Aumento del tamaño de recepción/envío del búfer UDP.
- Carga de CPU que afecta la prueba. (carga máxima del 40-50%, tanto del lado del cliente como del servidor)
- Ejecutando tcpdump en interfaces específicas en lugar de "cualquiera".
- Ejecutando tcpdump con '-p' para desactivar el modo promiscuo.
- Ejecutando tcpdump solo en el servidor. Esto resultó en una pérdida de paquetes del 20% y parece no afectar las pruebas.
- Ejecutando tcpdump solo en el cliente. Esto resultó en un mayor rendimiento.
- Incrementando netdev_max_backlog y netdev_budget a 2^32-1. Esto no hizo ninguna diferencia.
- Probé todas las configuraciones posibles del modo promiscuo en cada NIC (servidor encendido y cliente apagado, servidor apagado y cliente encendido, ambos encendidos, ambos apagados). Esto no hizo ninguna diferencia.
Respuesta1
Cuando tcpdump se esté ejecutando, será bastante rápido al leer los fotogramas entrantes. Mi hipótesis es que la configuración del búfer de anillo de paquetes de la NIC puede ser un poco pequeña; cuando tcpdump se está ejecutando, se vacía de manera más oportuna.
Si es suscriptor de Red Hat, este artículo de soporte es muy útilDescripción general de la recepción de paquetes. Tiene algunas cosas ahí que no creo que hayas considerado todavía.
Considere cómo su sistema maneja las IRQ; considere aumentar el 'dev_weight' de la interfaz de red (lo que significa que se leen más paquetes desde la NIC al espacio de usuario); observe la frecuencia con la que la aplicación lee el socket (¿puede usar un hilo dedicado? ¿Existen problemas conocidos/soluciones alternativas con respecto a la escalabilidad)?
Aumente el búfer de cuadros de NIC (usando el ethtool
comando: observe los --set-ring
argumentos, etc.).
Mire el "escalado del lado de recepción" y utilice al menos esa cantidad de subprocesos de recepción para leer el tráfico.
Me pregunto si tcpdump está haciendo algo interesante, como usar el soporte del kernel parabuffers de anillo de paquetes. Eso ayudaría a explicar el comportamiento que está viendo.
Respuesta2
¿Qué regulador de potencia estás usando? He visto comportamientos similares con gobernadores "bajo demanda" o "conservadores".
Intente utilizar el regulador de "rendimiento" y deshabilite cualquier función de ahorro de energía en el BIOS del servidor.
¿Cambia algo?
Respuesta3
Otra forma es ip_conntarck
el módulo. ¿Está seguro de que su Linux-box puede aceptar una nueva conexión? prueba a través de:
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_max
net.ipv4.netfilter.ip_conntrack_max = 65536
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_count
net.ipv4.netfilter.ip_conntrack_count = 29
tienes que probar
net.ipv4.netfilter.ip_conntrack_max > net.ipv4.netfilter.ip_conntrack_count
Si max == count, su conexión máxima está llena y su Linux-box no puede aceptar una nueva conexión.
Si no tiene ip_conntrack, puede cargarlo fácilmente a través demodprobe ip_conntrack
Respuesta4
Sospecho que el lado receptor simplemente no es capaz de manejar la velocidad de los paquetes y este es el motivo:
usando tcpdumpen el clientereduce los paquetes descartados: tcpdump está ralentizando el cliente y, por lo tanto, el servidor está viendo una tasa de empaquetador mucho más baja que aún puede manejar parcialmente. Debería poder confirmar esta hipótesis comprobando los contadores de paquetes RX/TX tanto en el cliente como en el servidor.
Mencionaste que aumentaste el tamaño de recepción/envío del búfer UDP, ¿podrías detallar cómo? Es importante que en el servidor cambies tanto rmem_maxyrmem_default, ejemplo:
sysctl -w net.core.rmem_max=524287 sysctl -w net.core.wmem_max=524287 sysctl -w net.core.rmem_default=524287 sysctl -w net.core.wmem_default=524287
Probando tu configuración
Detenga statsd y la aplicación del nodo, luego con el sistema inactivo úseloiperfpara probar la velocidad de paquetes que la red/kernel puede manejar. Si puede transmitir 40K paquetes/s con iperf pero no puede con statsd, entonces debe concentrar sus esfuerzos en ajustar statsd.
Otros sintonizables
Recuerda también sintonizarnet.core.netdev_max_backlog: número máximo de paquetes permitidos en cola cuando una interfaz particular recibe paquetes más rápido de lo que el kernel puede procesarlos.