Actualmente estoy experimentando con la creación de un servidor http. El servidor es multiproceso por un hilo de escucha utilizando select (...) y cuatro subprocesos de trabajo gestionados por un grupo de subprocesos. Actualmente estoy administrando alrededor de 14k-16k solicitudes por segundo con una longitud de documento de 70 bytes, un tiempo de respuesta de 6-10ms, en un Core I3 330M. Pero esto es sin keep-alive y cualquier socket que sirva, cierro inmediatamente cuando el trabajo está hecho.Problema al admitir sockets keep-alive en un servidor http de fabricación propia
EDIT: El trabajador enhebra los procesos 'trabajos' que se han enviado cuando se detecta actividad en un socket, es decir. solicitudes de servicio. Después de completar un 'trabajo', si no hay más 'trabajos', dormimos hasta que se envíen más 'trabajos' o si ya hay algunos disponibles, comenzamos a procesar uno de estos.
Mis problemas comenzaron cuando comencé a intentar implementar el soporte Keep-alive. Con keep-alive activado, solo administro solicitudes de 1.5k-2.2k por segundo con 100 sockets abiertos. Este número crece a alrededor de 12k con 1000 sockets abiertos. En ambos casos, el tiempo de respuesta es alrededor de 60-90 ms. Siento que esto es bastante extraño ya que mis suposiciones actuales dicen que las solicitudes deberían subir, no hacia abajo, y el tiempo de respuesta debería bajar, pero definitivamente no subir.
He intentado varias estrategias diferentes para la fijación del bajo rendimiento:
-
1. Llamada de selección (...)/pselect (...) con un valor de tiempo de espera para que podamos reconstruir nuestra estructura FD_SET y escuchar a los sockets adicionales que llegaron después de que bloqueamos, y el servicio de cualquier actividad de socket detectado. (aparte del bajo rendimiento, también existe el problema de que los sockets se cierran mientras estamos bloqueando, lo que resulta en select (...)/pselect (...) informando el descriptor de archivo incorrecto.)
-
2. Tener uno hilo de escucha que solo acepta nuevas conexiones y un hilo keep-alive que se notifica a través de un conducto de cualquier socket nuevo que llegó después de que bloqueamos y cualquier nueva actividad de socket, y reconstruir el FD_SET. (el mismo problema adicional aquí en '1.').
-
3. seleccione (...)/pselect (...) con un tiempo de espera, cuando se va a realizar un nuevo trabajo, separe la entrada de la lista vinculada para el socket que tiene actividad y vuelva a agregarla cuando la solicitud ha sido reparado. Se espera que la reconstrucción del FD_SET sea más rápida. De esta forma, también evitamos tratar de escuchar cualquier descripción de archivo incorrecta.
-
4. Combinado (2.) y (3.).
-
-. Probablemente algunos más, pero me escapan.
Los sockets de keep-alive se almacenan en una simple lista vinculada, cuyos métodos add/remove están rodeados por un bloqueo pthread_mutex, la función responsable de la reconstrucción de FD_SET también tiene este bloqueo.
Sospecho que es el bloqueo/desbloqueo constante del mutex el principal culpable aquí, he intentado perfilar el problema, pero ni gprof ni google-perftools han sido muy cooperativos, ya sea introduciendo inestabilidad extrema o simplemente rechazando para reunir todos los datos (sin embargo, podría ser que yo no sepa cómo usar las herramientas correctamente). Pero quitar los bloqueos pone en riesgo la lista enlazada en un estado no sano y probablemente se cuelgue o coloque el programa en un ciclo infinito. También he sospechado el tiempo de espera de selección (...)/pselect (...) cuando lo he usado, pero estoy bastante seguro de que este no era el problema, ya que el bajo rendimiento se mantiene incluso sin él.
No entiendo cómo debo manejar los enchufes para mantener vivo y me pregunto si la gente tiene alguna sugerencia sobre cómo solucionar el bajo rendimiento o si tiene alguna sugerencia sobre algún método alternativo que pueda usar. para continuar apoyando sockets keep-alive.
- Si necesita más información para poder responder a la pregunta correctamente, no dude en pedir, y voy a intentar mi mejor esfuerzo para proporcionarle la información necesaria y actualizar la pregunta con esta nueva información .
Para crear perfiles, podría usar 'oprofile', que debería ser menos intrusivo que' gprof'. – ninjalj
¿Se puede publicar el código que realiza el bloqueo? ¿Qué tipo de estructura de datos está protegiendo (lista vinculada?) Y qué operaciones sobre esa estructura de datos están protegidas con bloqueos (¿agregar/eliminar?) O qué? – johnnycrash
Estoy usando el servidor web "GoAhead" desarrollado en C y modificándolo según sea necesario. Puede usar eso como referencia. – AjayR