multithreading - TCP/IP-Resolviendo el C10K con el enfoque de subproceso por cliente
concurrency (3)
Después de leer el famoso artículo de C10k y buscar en la web cómo han evolucionado las cosas desde que se escribió, me gustaría saber si un servidor estándar de hoy en día puede manejar > 10000 conexiones simultáneas usando un hilo por conexión (posiblemente con la ayuda de un grupo de hilos para evitar el proceso de creación / eliminación).
Algunos detalles que pueden afectar el enfoque del problema:
- Entrada, procesamiento intermedio y salida.
- Longitud de cada conexión.
- Especificaciones técnicas del servidor (núcleos, procesadores, RAM, etc ...)
- Combinando este sistema con técnicas alternativas como AIO, sondeo, hilos verdes, etc ...
Obviamente no soy un experto en la materia, por lo que cualquier comentario o consejo será muy apreciado :)
Absolutamente. Un servidor estándar puede manejar más de 10K conexiones simultáneas usando el modelo con un hilo por conexión . Construí una aplicación de este tipo y, hace cinco años, se ejecutaba con más de 50 K de conexiones simultáneas por proceso en un servidor Linux estándar. Hoy en día, debería ser posible ejecutar la misma aplicación con más de 250K de conexiones concurrentes en el hardware actual.
Solo hay unas pocas cosas a tener en cuenta:
- Reutilizar hilos utilizando un grupo de hilos. No hay necesidad de eliminar subprocesos si no se utilizan, porque el uso de recursos debe optimizarse para las cargas pico.
- Tamaño de pila: Por defecto, cada hilo de Linux reserva 8 MB para su pila. Eso suma hasta 80 GB para 10K hilos. Debe establecer el tamaño de pila predeterminado en algún valor entre 64k y 512k, lo que no es un problema, porque la mayoría de las aplicaciones no requieren pilas de llamadas más profundas.
- Si las conexiones son de corta duración, optimice para nuevas conexiones creando varios sockets en el mismo punto final con la opción
SO_REUSEPORT
. - Aumente los límites de usuarios:
open files
(predeterminado 1.024),max user processes
- Aumente los límites del sistema, por ejemplo,
/proc/sys/kernel/pid_max
(32K predeterminado),/proc/sys/kernel/threads-max
, y/proc/sys/vm/max_map_count
(65K predeterminado).
La aplicación mencionada anteriormente fue diseñada inicialmente para manejar solo conexiones concurrentes de 2K. Sin embargo, con el crecimiento en uso, no tuvimos que realizar cambios significativos en el código para escalar hasta 50K conexiones.
Es posible que desee un seguimiento reciente sobre el tema: El secreto de 10 millones de conexiones simultáneas: el núcleo es el problema, no la solución .
Los enfoques habituales para los servidores son: (a) subproceso por conexión (a menudo con un grupo de subprocesos), o (b) subproceso único con IO asíncrono (a menudo con epoll o kqueue). Mi idea es que algunos elementos de estos enfoques pueden, y con frecuencia deberían, combinarse para usar IO asíncronas (con epoll o kqueue) y luego entregar la solicitud de conexión a un grupo de subprocesos para procesar. Este enfoque combinaría el envío eficiente de IO asíncronas con el paralelismo proporcionado por el conjunto de subprocesos.
He escrito un servidor de este tipo para la diversión (en C ++) que usa epoll en Linux y kqueue en FreeBSD y OSX junto con un grupo de subprocesos. Solo necesito ejecutarlo a fondo para realizar pruebas pesadas, hacer una limpieza de código y luego tirarlo en github (espero que pronto).