Informatica per script kiddies 7 – Che succede quando andiamo su un sito

Eccoci di nuovo qui! Trovate qui tutti gli articoli della rubrica.

Oggi, invece, parliamo un po’ di come è fatto il web. Le cose possono ovviamente essere molto più semplici o molto più complesse di come le mostrerò qui, ma cercherò di dare un buon inizio per capire meglio come funzioni tutto l’accrocco, che non è sempre troppo chiaro.

Il web infatti nasce con un’idea molto semplice: dare a ogni risorsa un indirizzo composto dall’indirizzo del computer su cui risiede e dall’indirizzo della risorsa specifica. Digiti l’indirizzo in un browser (o clicchi su un link), e ottieni la risorsa. Le cose si sono però rapidamente fatte più complicate, principalmente perché i volumi di richieste sono diventati rapidamente molto grandi. Ma vediamo un po’ come funziona tutto.

Una premessa sugli indirizzi

Anche se è una cosa molto nota a molti, tocca prima di tutto fare un paio di premesse sulla struttura dell’indirizzamento delle risorse su web.

Una risorsa su Internet, e conseguentemente anche sul web, è identificata da uno URL, che è un particolare tipo di URI che mette come schema (la parte prima dei primi due punti nell’indirizzo) il protocollo di accesso alla risorsa (http, https, ftp…), seguito da un doppio slash e dal nome del server, a sua volta seguito dall’indirizzo della risorsa sul server.

Il “nome del server” può essere un indirizzo IP, o un vero e proprio nome, composto da stringhe separate da punti (come tldr.italyinformatica.org). Il nome si chiama “nome di dominio” (o nome DNS, che sta per domain name system), e ogni stringa a partire da destra è un livello. Quindi tldr.italyinformatica.org è un dominio di terzo livello, italyinformatica.org è di secondo e org è di primo.

La traduzione DNS

I nomi di dominio, purtroppo, sono una cosa pensata dalle persone ad uso delle persone: la rete, che utilizza solo indirizzi IP, se ne fa davvero poco. La prima cosa che succede quando digitiamo un dominio e premiamo invio, quindi, è quella che si chiama traduzione DNS, ovvero il cercare di capire a che indirizzo IP corrisponda il nome di dominio che abbiamo digitato.

Per prima cosa, il browser controlla se lo sa già. Il browser infatti conserva per un certo tempo le traduzioni in IP dei nomi richiesti piú recentemente, e nel caso usa la traduzione già nota.

Se non dovesse trovare nulla, il browser chiederà al sistema operativo, che a sua volta ha un archivio delle richieste recenti, fatte magari da altri software, e gli comunica l’indirizzo IP corretto.

Se nemmeno il sistema operativo ne sa nulla, il sistema stesso ha una lista di server esterni, i server DNS, a cui chiedere. A loro volta, questi server hanno una lista di cose che già sanno, oppure chiedono a ulteriori altri server, che a questo punto possono essere di due tipi:

  • Server autorevoli, ovvero server che sono riferimenti per una determinata “zona DNS”, ovvero solitamente per un dominio. Ci saranno i server autorevoli per il dominio di primo livello it, ad esempio. Se tali server sanno l’IP per il dominio di livello piú basso che gli viene chiesto lo restituiscono in risposta, altrimenti chiedono al server autorevole per la zona di rango inferiore, ad esempio quello autorevole per italyinformatica.org e via salendo di livello.
  • Server ricorsivi, ovvero server che rispondono con l’IP se lo hanno, oppure chiedono ai server che a loro volta hanno configurato come server che “ne sanno di più”.

Ognuno di questi due approcci ha svantaggi e vantaggi, ma non ne parlerò troppo qui (se qualcuno vuole scrivere un articolo sul DNS mi dica, è benvenutissimo in questa rubrica).

Insomma, la prima cosa che avviene quando premiamo invio non ha nulla a che fare con l’effettivo raggiungimento della risorsa: si chiede a qualcuno che indirizzo abbia davvero.

Raggiungere il server

A questo punto, conosciuto l’IP, il browser può effettivamente fare la richiesta per raggiungere il server dove si trova il sito. Tipicamente, l’IP che viene dato dal DNS non è davvero quello del server, ma è l’indirizzo di un sistema intermedio, che può essere di vario tipo ma è di solito un load balancer con eventuali funzioni di caching.

Il compito del load balancer è quello di non esporre direttamente un unico server, raggiunto da tutti, ma di distribuire il carico tra diverse macchine, con alcuni grandi vantaggi che vanno un po’ oltre il semplice alleggerire il carico sulle macchine. La presenza di un load balancer infatti evita che un malfunzionamento di un server ricada sul servizio (se “cade” un server, ci sono sempre gli altri), concetto che si chiama affidabilità, e permette di aggiungere senza altre modifiche infrastrutturali ulteriori server in caso di aumento del carico, concetto che si chiama scalabilità.

Se il load balancer ha funzionalità di caching (o, piú spesso, ha accesso a server di cache appositi), restituirà direttamente le risorse in cache senza disturbare uno dei server veri e propri.

A questo punto, la richiesta arriverà finalmente al server.

L’elaborazione

Se la richiesta arriva davvero fino al server senza essere sparata altrove dal load balancer, molto probabilmente è una richiesta che ha bisogno di essere elaborata. Il server, quindi, non ha al suo interno una risorsa da restituire, ma deve calcolarla appositamente per quella specifica richiesta.

Di solito, per farlo, necessita di leggere o scrivere dei dati, e farà quindi lui stesso richieste a una serie di server secondari. Di solito si tratta di server di storage (in sostanza server che permettono di leggere e scrivere file), database (server che permettono di leggere e scrivere dati strutturati) ed eventuali strutture complesse costruite per immagazzinare ed elaborare dati, le data warehouse. Inoltre, potrebbe effettuare richieste a normali sistemi terzi di vario genere, attraverso interfacce API, e richieste a suoi servizi interni che effettuano elaborazioni asincrone (tipicamente cose da mettere in coda, tipo “quando ti liberi fai questo e poi manda una notifica che hai finito, intanto io rispondo all’utente che stiamo lavorando per lui”).

Composta la risposta, la restituirà al browser che la ha richiesta. In genere la risposta contiene tutto il necessario a far sapere al browser cosa mostrare all’utente, senza però tutti i dati necessari. Cose come gli script, molti dei dati da fonti esterne (e non solo) e soprattutto le immagini non vengono incluse nella risposta.

Le richieste secondarie

Scaricata la risposta, quindi, il browser avrà poco più che tutto il necessario a scaricare i reali contenuti della pagina.

A questo punto, quindi, tutti i dati “a parte”, che chiamiamo un po’ impropriamente i media, verranno scaricati attraverso una serie di richieste idealmente simili a quella principale.

Tali richieste si dividono in richieste di contenuti statici (script, fogli di stile, media veri e propri) e richieste a contenuti dinamici (dati). Le seconde fanno un percorso sostanzialmente identico alla richiesta originale, attraverso un load balancer e verso un server. Le prime, invece, fanno una strada un po’ diversa.

Script, fogli di stile e media, e contenuti statici in generale, hanno infatti la caratteristica principale di essere, appunto, statici: tendono a non cambiare o a cambiare pochissimo nel tempo. Non c’è quindi bisogno alcuno di chiederli allo stesso server che fornisce contenuti elaborati.

In genere il loro URL non fa neanche riferimento al sistema dove risiede il “sito”, ma a un sistema a parte appositamente costruito, la CDN.

Le CDN sono delle grandi reti di server dislocati in giro per il mondo (e per i provider di connessione), e contenenti copie identiche (mirror) di una serie di contenuti statici, spesso comuni a moltissimi siti e sistemi diversi (uno script JavaScript potrebbe essere utilizzato da migliaia di diversi siti, e un logo da diverse decine). Quando una risorsa viene richiesta ad una CDN, meccanismi equiparabili – ma spesso non identici – a load balancer fanno sì che il contenuto venga servito dal server piú vicino (non geograficamente ma a livello di rete), in modo da ridurre al minimo sia il ritardo nel riceverlo sia il carico di rete “del mondo”. I media sono infatti spesso pesanti ed è meglio tengano occupato uno spezzone di rete piccolo. Se mi vedo un film su Netflix, insomma, è meglio che il film venga da un server nella stessa rete del mio provider di connessione che da un server negli Stati Uniti.

In tutto questo va tenuto conto che il browser ha sempre una sua cache interna, e se ha scaricato il logo o lo script tale venti minuti fa, non si sogna neanche di chiederlo alla CDN, lo serve e basta. Anche se lo ha scaricato per tutt’altro sito, ovviamente.

E non è finita

Una volta scaricata e rappresentata la pagina, oggigiorno, il browser non smette di lavorare: sia le interazioni dell’utente che il server continueranno probabilmente ad aggiungere contenuti che andranno comunicati al browser. Le cose derivanti dall’interazione dell’utente sono tipicamente altre micro-richieste che funzionano nella stessa maniera delle richieste precedenti, e finiscono su una CDN o a un server che le elabora. Esiste però un’eccezione: gli script presenti nella pagina possono richiedere la creazione di un canale di comunicazione a due vie con un server (tipicamente usato per inviare notifiche, ma non solo), attraverso il protocollo websockets. Su tale canale potranno continuare a transitare dati in entrambi i sensi, dal browser al server websockets e vice versa, aggiungendo così l’ultimo tipo di comunicazione che in genere avviene mentre visitiamo siti internet.

Spero così di aver chiarito un po’ sia cosa fa il nostro browser dopo che premiamo invio, sia soprattutto che architettura ci sia grossomodo dietro un sistema web di medie dimensioni, che chiarisce pure perché a volte le cose vadano storte in maniera “strana”, con siti parzialmente funzionanti. Per qualunque chiarimento, chiedete pure, che a questo giro abbiamo appena scalfito la superficie!