¿Cómo “escuchan” los servidores web las direcciones IP, interrumpen o sondean?

87

Estoy tratando de entender los detalles más bajos de los servidores web. Me pregunto si un servidor, por ejemplo Apache, está sondeando continuamente nuevas solicitudes o si funciona mediante algún tipo de sistema de interrupción. Si es una interrupción, ¿qué está provocando la interrupción? ¿Es el controlador de la tarjeta de red?

user2202911
fuente
1
La palabra clave para entender es "servidor" . En el modelo servidor-cliente (versus el modelo maestro-esclavo), el servidor espera las solicitudes de los clientes. Estas solicitudes son eventos que deben ser atendidos. Un servidor web es un programa de aplicación. Su pregunta combina la aplicación SW con la terminología HW (por ejemplo, interrupción y NIC), en lugar de mantener los conceptos relacionados en la misma capa de abstracción. El controlador NIC en realidad puede usar el sondeo a veces, por ejemplo, los controladores NAPI de Linux regresan al sondeo cuando hay una avalancha de paquetes. Pero eso es irrelevante para la aplicación de procesamiento de eventos SW.
aserrín
1
@sawdust Muy interesante. La pregunta realmente está destinada a comprender la conexión entre los procesos SW y HW
user2202911
1
Es muy similar a la forma en que los programas de línea de comandos (y otros programas GUI) escuchan el teclado. Especialmente en un sistema de ventanas, en el que el paso del núcleo recibe los datos del dispositivo del teclado y se los entrega al administrador de ventanas, que identifica la ventana que tiene el foco y proporciona los datos a esa ventana.
G-Man
@ G-Man: Teoría, sí. En realidad, la mayoría de los mecanógrafos no escriben a 1 Gbit / s, lo que justifica tener dos arquitecturas diferentes. Uno limpio, flexible y lento, uno torpe pero de alta velocidad.
MSalters

Respuestas:

181

La respuesta corta es: algún tipo de sistema de interrupción. Esencialmente, usan el bloqueo de E / S, lo que significa que duermen (bloquean) mientras esperan nuevos datos.

  1. El servidor crea un socket de escucha y luego bloquea mientras espera nuevas conexiones. Durante este tiempo, el núcleo pone el proceso en un estado de suspensión interrumpible y ejecuta otros procesos. Este es un punto importante: tener la encuesta de proceso continuamente desperdiciaría la CPU. El kernel puede usar los recursos del sistema de manera más eficiente al bloquear el proceso hasta que haya trabajo que hacer.

  2. Cuando llegan nuevos datos a la red, la tarjeta de red emite una interrupción.

  3. Al ver que hay una interrupción de la tarjeta de red, el núcleo, a través del controlador de la tarjeta de red, lee los nuevos datos de la tarjeta de red y los almacena en la memoria. (Esto debe hacerse rápidamente y generalmente se maneja dentro del controlador de interrupciones).

  4. El núcleo procesa los datos recién llegados y los asocia con un socket. Un proceso que está bloqueando en ese socket se marcará como ejecutable, lo que significa que ahora es elegible para ejecutarse. No necesariamente se ejecuta de inmediato (el núcleo puede decidir ejecutar otros procesos aún).

  5. En su tiempo libre, el núcleo activará el proceso del servidor web bloqueado. (Ya que ahora es ejecutable).

  6. El proceso del servidor web continúa ejecutándose como si no hubiera pasado el tiempo. Su llamada de sistema de bloqueo regresa y procesa cualquier dato nuevo. Entonces ... vaya al paso 1.

Greg Bowser
fuente
18
+1 para una delimitación clara del núcleo frente al proceso del servidor web.
Russell Borogove
13
No puedo creer que algo tan complejo como esto pueda resumirse de manera tan clara y simple, pero lo hiciste. +1
Brandon
8
+1 Gran respuesta. Además, los pasos entre 2 y 3 pueden volverse un poco más complejos con NIC, SO y controladores modernos. Por ejemplo, con NAPI en Linux, los paquetes no se reciben realmente en el contexto de interrupción. En cambio, el kernel dice "Ok, NIC, entiendo que tienes datos. Deja de molestarme (desactiva la fuente de interrupción), y volveré en breve para tomar este paquete y cualquier paquete posterior que pueda llegar antes que yo".
Jonathon Reinhart
8
Golpe leve: no es realmente necesario bloquear. Tan pronto como el proceso del servidor haya creado un socket de escucha, el kernel aceptará SYN en ese puerto, incluso mientras no esté bloqueado por dentro accept. Son (¡afortunadamente, o apestaría totalmente!) Tareas independientes que se ejecutan asincrónicamente. A medida que entran las conexiones, se colocan en una cola de donde las acceptsaca. Solo si no hay ninguno, se bloquea.
Damon
3
"lee los nuevos datos de la tarjeta de red y los almacena en la memoria. (Esto debe hacerse rápidamente y generalmente se maneja dentro del controlador de interrupciones)." ¿No se hace con acceso directo a la memoria?
Siyuan Ren
9

Hay bastantes detalles "inferiores".

Primero, considere que el núcleo tiene una lista de procesos y, en cualquier momento, algunos de estos procesos se están ejecutando y otros no. El kernel le permite a cada proceso en ejecución una porción de tiempo de CPU, luego lo interrumpe y pasa al siguiente. Si no hay procesos ejecutables, entonces el núcleo probablemente emitirá una instrucción como HLT a la CPU que suspende la CPU hasta que haya una interrupción de hardware.

En algún lugar del servidor hay una llamada al sistema que dice "dame algo que hacer". Hay dos amplias categorías de formas en que esto se puede hacer. En el caso de Apache, llama accepta un socket que Apache ha abierto anteriormente, probablemente escuchando en el puerto 80. El núcleo mantiene una cola de intentos de conexión y se agrega a esa cola cada vez que se recibe un TCP SYN . La forma en que el núcleo sabe que se recibió un TCP SYN depende del controlador del dispositivo; Para muchas NIC probablemente haya una interrupción de hardware cuando se reciben datos de la red.

acceptle pide al kernel que me devuelva la próxima iniciación de conexión. Si la cola no estaba vacía, acceptsolo regresa de inmediato. Si la cola está vacía, el proceso (Apache) se elimina de la lista de procesos en ejecución. Cuando se inicia una conexión más tarde, el proceso se reanuda. Esto se llama "bloqueo", porque para el proceso que lo llama, accept()parece una función que no regresa hasta que tiene un resultado, lo que podría pasar en algún momento a partir de ahora. Durante ese tiempo, el proceso no puede hacer nada más.

Una vez que acceptregresa, Apache sabe que alguien está intentando iniciar una conexión. Luego llama a fork para dividir el proceso de Apache en dos procesos idénticos. Uno de estos procesos continúa para procesar la solicitud HTTP, el otro llama acceptnuevamente para obtener la siguiente conexión. Por lo tanto, siempre hay un proceso maestro que no hace más que llamar accepty generar subprocesos, y luego hay un subproceso para cada solicitud.

Esta es una simplificación: es posible hacer esto con subprocesos en lugar de procesos, y también es posible hacerlo de forkantemano para que haya un proceso de trabajo listo cuando se recibe una solicitud, lo que reduce la sobrecarga de inicio. Dependiendo de cómo esté configurado Apache, puede hacer cualquiera de estas cosas.

Esa es la primera categoría amplia de cómo hacerlo, y se llama bloqueo de E / S porque el sistema llama como accepty ready writeque operan en sockets suspenderá el proceso hasta que tengan algo que devolver.

La otra forma amplia de hacerlo se llama IO sin bloqueo o basada en eventos o asincrónica . Esto se implementa con llamadas al sistema como selecto epoll. Cada uno de ellos hace lo mismo: les das una lista de sockets (o, en general, descriptores de archivos) y lo que quieres hacer con ellos, y el núcleo se bloquea hasta que esté listo para hacer una de esas cosas.

Con este modelo, puede decirle al núcleo (con epoll): "Indíqueme cuándo hay una nueva conexión en el puerto 80 o nuevos datos para leer en cualquiera de estas 9471 otras conexiones que he abierto". epollbloquea hasta que una de esas cosas esté lista, entonces lo haces. Entonces repites. Las llamadas al sistema como accepty ready writeno cuadra, en parte porque cada vez que se llama a ellos, epollacabo de decir que están dispuestos de modo que no habría razón para bloquear, y también porque cuando se abre la toma o el archivo que especifica que ellos quieren en modo sin bloqueo, por lo que esas llamadas fallarán en EWOULDBLOCKlugar de bloquearse.

La ventaja de este modelo es que solo necesita un proceso. Esto significa que no tiene que asignar una pila y estructuras de kernel para cada solicitud. Nginx y HAProxy usan este modelo, y es una gran razón por la que pueden manejar tantas más conexiones que Apache en hardware similar.

Phil Frost
fuente