2008-09-27 10 views
7

Parece haber varias opciones disponibles para programas que manejan grandes cantidades de conexiones de socket (como servicios web, sistemas p2p, etc.).¿Cómo manejar con mayor eficiencia un gran número de descriptores de archivos?

  1. Genera una hebra separada para controlar las E/S de cada socket.
  2. Utilice la llamada al sistema select para multiplexar las E/S en un único hilo.
  3. Utilice la llamada al sistema poll para multiplexar la E/S (reemplazando la selección).
  4. Use las llamadas al sistema epoll para evitar tener que enviar repetidamente sockets fd a través de los límites del usuario/sistema.
  5. Genera una serie de subprocesos de E/S que multiplexan un conjunto relativamente pequeño de la cantidad total de conexiones que usan la API de sondeo.
  6. Según el n. ° 5, excepto que utiliza la API epoll para crear un objeto epoll separado para cada subproceso de E/S independiente.

En una CPU multinúcleo, esperaría que el # 5 o el # 6 tuvieran el mejor rendimiento, pero no tengo datos duros que respalden esto. Buscando en la web apareció this página que describe las experiencias de los enfoques de prueba del autor # 2, # 3 y # 4 anteriores. Lamentablemente, esta página web parece tener alrededor de 7 años de antigüedad y no se encuentran actualizaciones recientes obvias.

Entonces mi pregunta es ¿cuáles de estos enfoques tienen las personas que son más eficientes y/o hay otro enfoque que funciona mejor que cualquiera de los enumerados anteriormente? Se apreciarán las referencias a gráficos de la vida real, libros blancos y/o grabaciones disponibles en la web.

+0

Creo que este es un problema resuelto y la respuesta está aquí - http://www.kegel.com/c10k.html – computinglife

Respuesta

0

Uso extensivamente epoll() y funciona bien. Tengo rutinariamente miles de enchufes activos y pruebo con hasta 131,072 enchufes. Y epoll() siempre puede manejarlo.

Uso múltiples hilos, cada uno de los cuales sondea en un subconjunto de sockets. Esto complica el código, pero aprovecha al máximo las CPU multinúcleo.

2

Según mi experiencia, tendrás la mejor ejecución con el n. ° 6.

También le recomiendo que busque en libevent para tratar de abstraer algunos de estos detalles. Por lo menos, podrá ver algunos de sus puntos de referencia benchmark results.

Además, ¿de cuántos sockets está hablando? Su enfoque probablemente no importe demasiado hasta que empiece a obtener al menos unos cientos de zócalos.

3

Hablando con mi experiencia con la ejecución de grandes servidores IRC, solíamos usar select() y poll() (porque epoll()/kqueue() no estaban disponibles). En alrededor de 700 clientes simultáneos, el servidor usaría el 100% de una CPU (el servidor irc no tenía multiproceso). Sin embargo, curiosamente el servidor aún funcionaría bien. En alrededor de 4.000 clientes, el servidor comenzaría a retrasarse.

La razón de esto fue que alrededor de 700.000 clientes, cuando volvíamos a seleccionar(), habría un cliente disponible para procesar. Los bucles for() bucles para descubrir qué cliente era consumirían la mayor parte de la CPU. A medida que obtuvimos más clientes, comenzamos a obtener más y más clientes que necesitaban procesamiento en cada llamada para seleccionar(), de modo que nos volviéramos más eficientes.

Pasando a epoll()/kqueue(), máquinas similares similares tratarían trivialmente a 10,000 clientes, con algunas (máquinas admitidamente más poderosas, pero aún máquinas que se considerarían pequeñas según los estándares actuales), han tenido 30,000 clientes sin romper a sudar.

Experimentos que he visto con SIGIO parecen sugerir que funciona bien para aplicaciones donde la latencia es extremadamente importante, donde solo hay unos pocos clientes activos haciendo muy poco trabajo individual.

Recomendaría usar epoll()/kqueue() sobre select()/poll() en casi cualquier situación. No he experimentado con dividir clientes entre hilos. Para ser sincero, nunca encontré un servicio que necesitara más trabajo de optimización en el procesamiento del cliente front-end para justificar la experimentación con hilos.

2

He pasado los 2 últimos años trabajando en ese tema específico (para el servidor web G-WAN, que viene con MUCHOS puntos de referencia y gráficos que exponen todo esto).

El modelo que funciona mejor en Linux es epoll con una cola de eventos (y, para el procesamiento pesado, varios subprocesos de trabajo).

Si tiene poco procesamiento (baja latencia de procesamiento) entonces usar un hilo será más rápido usando varios hilos.

La razón de esto es que epoll no escala en CPU multi-Core (el uso de varias colas de epoll concurrentes para E/S de conexión en la misma aplicación de modo de usuario ralentizará su servidor).

No miré seriamente el código de epoll en el kernel (solo me enfoqué en el modo de usuario hasta ahora) pero creo que la implementación de epoll en el núcleo está paralizada por bloqueos.

Es por esto que utilizar varios hilos golpea rápidamente la pared.

No hace falta decir que un estado de cosas tan pobre no debería durar si Linux quiere mantener su posición como uno de los kernels con mejor rendimiento.

Cuestiones relacionadas