In che modo i server Web “ascoltano” indirizzi IP, interrompono o eseguono il polling?


87

Sto cercando di capire i dettagli inferiori dei server Web. Mi chiedo se un server, ad esempio Apache, esegua continuamente il polling per nuove richieste o se funzioni con una sorta di sistema di interruzione. Se si tratta di un interrupt, cosa sta scatenando l'interrupt, è il driver della scheda di rete?


1
La parola chiave da capire è "server" . Nel modello server-client (rispetto al modello master-slave) il server attende le richieste dai client. Queste richieste sono eventi che devono essere gestiti. Un server web è un programma applicativo. La tua domanda combina l'applicazione SW con la terminologia HW (ad es. Interrupt e NIC), piuttosto che mantenere i concetti correlati sullo stesso livello di astrazione. Il driver della scheda di rete può effettivamente utilizzare il polling a volte, ad esempio i driver NAPI Linux regrediscono al polling quando c'è un flusso di pacchetti. Ciò è irrilevante per il software applicativo di elaborazione degli eventi.
segatura

1
@sawdust Molto interessante. La domanda ha davvero lo scopo di comprendere la connessione tra i processi SW e HW
user2202911

1
È molto simile al modo in cui i programmi della riga di comando (e altri programmi con interfaccia grafica) ascoltano la tastiera. Soprattutto in un sistema a finestre, in cui hai il passaggio del kernel che riceve i dati dal dispositivo a tastiera e li consegna al gestore delle finestre, che identifica la finestra che ha lo stato attivo e fornisce i dati a quella finestra.
G-Man,

@ G-Man: I teoria, sì. In realtà la maggior parte dei dattilografi non digita a 1 Gbit / s, il che giustifica avere due diverse architetture. Uno pulito, flessibile e lento, uno goffo ma ad alta velocità.
Salterio del

Risposte:


181

La risposta breve è: una sorta di sistema di interruzione. In sostanza, usano l'I / O di blocco, nel senso che dormono (bloccano) mentre attendono nuovi dati.

  1. Il server crea un socket di ascolto e quindi si blocca in attesa di nuove connessioni. Durante questo periodo, il kernel mette il processo in uno stato di sospensione interrompibile ed esegue altri processi. Questo è un punto importante: avere il polling di processo continuamente sprecerebbe CPU. Il kernel è in grado di utilizzare le risorse di sistema in modo più efficiente bloccando il processo fino a quando non c'è lavoro da fare.

  2. Quando arrivano nuovi dati sulla rete, la scheda di rete emette un interrupt.

  3. Vedendo che c'è un interrupt dalla scheda di rete, il kernel, tramite il driver della scheda di rete, legge i nuovi dati dalla scheda di rete e li memorizza. (Questo deve essere fatto rapidamente ed è generalmente gestito all'interno del gestore di interrupt.)

  4. Il kernel elabora i dati appena arrivati ​​e li associa a un socket. Un processo che sta bloccando su quel socket sarà contrassegnato come eseguibile, il che significa che ora è idoneo per l'esecuzione. Non si esegue necessariamente immediatamente (il kernel può decidere di eseguire ancora altri processi).

  5. A suo piacimento, il kernel riattiverà il processo del server web bloccato. (Dal momento che ora è eseguibile.)

  6. Il processo del server web continua l'esecuzione come se non fosse trascorso alcun tempo. La sua chiamata di sistema bloccante ritorna ed elabora tutti i nuovi dati. Quindi ... vai al passaggio 1.


18
+1 per una chiara definizione del kernel rispetto al processo del server web.
Russell Borogove,

13
Non posso credere che qualcosa di così complesso possa essere riassunto in modo così chiaro e semplice, ma l'hai fatto. +1
Brandon,

8
+1 Ottima risposta. Inoltre, i passaggi tra 2 e 3 possono diventare un po 'più complessi con moderne schede di rete, sistemi operativi e driver. Ad esempio, con NAPI su Linux, i pacchetti non vengono effettivamente ricevuti in un contesto di interrupt. Invece, il kernel dice "Okay NIC, ho capito che hai dei dati. Smetti di infastidirmi (disabilita la fonte di interruzione), e tornerò presto per prendere questo pacchetto e tutti i pacchetti successivi che potrebbero arrivare prima di me."
Jonathon Reinhart,

8
Leggero nitpick: non è davvero necessario bloccare. Non appena il processo del server ha creato un socket di ascolto, il kernel accetterà i SYN su quella porta, anche se non sei bloccato all'interno accept. Sono (per fortuna, o farebbe schifo!) Attività indipendenti, che eseguono in modo asincrono. Quando arrivano le connessioni, vengono inserite in una coda da cui le acceptestrae. Solo se non ce ne sono, si blocca.
Damon,

3
"legge i nuovi dati dalla scheda di rete e li memorizza nella memoria. (Questo deve essere fatto rapidamente e generalmente è gestito all'interno del gestore di interrupt.)" Non è fatto con accesso diretto alla memoria?
Siyuan Ren,

9

Ci sono molti dettagli "inferiori".

Innanzitutto, considera che il kernel ha un elenco di processi e, in un dato momento, alcuni di questi processi sono in esecuzione e altri no. Il kernel consente a ciascun processo in esecuzione una parte del tempo della CPU, quindi lo interrompe e passa al successivo. Se non ci sono processi eseguibili, il kernel probabilmente invierà un'istruzione come HLT alla CPU che sospende la CPU fino a quando non si verifica un interrupt di processo.

Da qualche parte nel server c'è una chiamata di sistema che dice "dammi qualcosa da fare". Esistono due grandi categorie di modi in cui ciò può essere fatto. Nel caso di Apache, chiama acceptun socket che Apache ha precedentemente aperto, probabilmente in ascolto sulla porta 80. Il kernel mantiene una coda di tentativi di connessione e si aggiunge a quella coda ogni volta che viene ricevuto un SYN TCP . Il modo in cui il kernel sa che è stato ricevuto un SYN TCP dipende dal driver del dispositivo; per molte schede di rete è probabilmente presente un interrupt di processo alla ricezione dei dati di rete.

acceptchiede al kernel di restituirmi la prossima iniziazione della connessione. Se la coda non era vuota, acceptritorna immediatamente. Se la coda è vuota, il processo (Apache) viene rimosso dall'elenco dei processi in esecuzione. Quando in seguito viene avviata una connessione, il processo viene ripreso. Questo si chiama "blocco", perché al processo che lo chiama, accept()sembra una funzione che non ritorna fino a quando non ha un risultato, che potrebbe essere tra qualche tempo. Durante quel periodo il processo non può fare nient'altro.

Una volta acceptrestituito, Apache sa che qualcuno sta tentando di avviare una connessione. Quindi chiama fork per dividere il processo Apache in due processi identici. Uno di questi processi continua a elaborare la richiesta HTTP, l'altro chiama acceptnuovamente per ottenere la connessione successiva. Pertanto, esiste sempre un processo principale che non fa altro che chiamare accepte generare sottoprocessi, quindi esiste un processo secondario per ogni richiesta.

Questa è una semplificazione: è possibile farlo con i thread anziché con i processi, ed è anche possibile farlo in forkanticipo, quindi c'è un processo di lavoro pronto per iniziare quando viene ricevuta una richiesta, riducendo così il sovraccarico di avvio. A seconda di come è configurato Apache, può fare una di queste cose.

Questa è la prima vasta categoria di come farlo, e si chiama blocco IO perché il sistema chiama come accepte reade writeche operano su socket sospenderà il processo fino a quando non hanno qualcosa da restituire.

L'altro modo ampio per farlo è chiamato IO non bloccante o basato su eventi o asincrono . Questo è implementato con chiamate di sistema come selecto epoll. Ognuno di loro fa la stessa cosa: tu dai loro un elenco di socket (o in generale, descrittori di file) e cosa vuoi fare con loro, e il kernel si blocca fino a quando non è pronto a fare una di quelle cose.

Con questo modello, potresti dire al kernel (con epoll), "Dimmi quando c'è una nuova connessione sulla porta 80 o nuovi dati da leggere su una di queste 9471 altre connessioni che ho aperto". epollsi blocca fino a quando una di queste cose è pronta, quindi lo fai. Quindi ripeti. Chiamate di sistema come accepte reade writenon a blocchi, in parte perché ogni volta che li chiami, epollappena detto che sono pronti così non ci sarebbe alcun motivo per bloccare, e anche perché quando si apre la presa o il file si specifica che le si vuole in modalità non bloccante, quindi quelle chiamate falliranno EWOULDBLOCKinvece di bloccare.

Il vantaggio di questo modello è che è necessario un solo processo. Ciò significa che non è necessario allocare uno stack e le strutture del kernel per ogni richiesta. Nginx e HAProxy usano questo modello, ed è un grande motivo per cui possono gestire così tante più connessioni di Apache su hardware simile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.