Server Indy - Modello a thread (1 / 3)

· Funzionalità

I server Indy usano thread per gestire le connessioni client, ogni volta che un nuovo client si connette al server viene creato un nuovo thread che gestisce la connessione, quindi se hai 100 connessioni ci saranno 100 thread. Inoltre, Indy usa socket bloccanti, il che significa che quando leggi o scrivi, la funzione non ritorna finché non è completata.

Questo modello ha alcuni vantaggi, ad esempio è facile da programmare, perché il codice viene elaborato in sequenza. Ma come contro, se il numero di connessioni aumenta, le prestazioni peggiorano a causa del context switch dei thread. Il context switching è il processo di memorizzazione dello stato di un thread in modo che possa essere ripristinato per riprendere l'esecuzione in un momento successivo. Il rapido context switching tra i thread è costoso in termini di utilizzo della CPU. Se crei 1000 connessioni in un server, vedrai che la CPU sta lavorando anche se non vengono scambiati dati, questo uso della CPU è dovuto al context switch dei thread.

Alternative al modello Indy 

Invece di usare 1 thread per ogni connessione, ci sono alternative come IOCP (per Windows) o EPOLL (per Linux) che fanno uso di un pool di thread per gestire le connessioni e usano socket non bloccanti. Questo modello è molto più efficiente quando il numero di connessioni concorrenti è alto e scala molto meglio del modello a thread Indy predefinito.

IOCP (Windows) 

Le I/O completion port forniscono un modello di threading efficiente per l'elaborazione di più richieste di I/O asincrone su un sistema multiprocessore. Quando un processo crea una I/O completion port, il sistema crea un oggetto coda associato per i thread il cui unico scopo è servire queste richieste. I processi che gestiscono molte richieste di I/O asincrone concorrenti possono farlo più rapidamente ed efficientemente usando le I/O completion port insieme a un pool di thread pre-allocato, piuttosto che creando thread al momento in cui ricevono una richiesta di I/O.

Il modello IOCP usa socket non bloccanti, invece di usare Select fa uso della funzione AcceptEx e di un pool di thread per gestire le connessioni client.

Per abilitare IOCP sul server Indy di sgcWebSockets basta consultare il codice qui sotto.

oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.NotifyEvents := neNOSync;
oServer.IOHandlerOptions.IOHandlerType := iohIOCP;
oServer.Active := True;

Verrà creato un nuovo server WebSocket + HTTP e un pool di thread gestirà le connessioni, il numero di thread usati dipenderà dal numero di CPU dove è in esecuzione il server.

EPOLL (Linux) 

Epoll è una system call del kernel Linux per un meccanismo scalabile di notifica degli eventi I/O, introdotta per la prima volta nella versione 2.5.44 del kernel Linux. La sua funzione è monitorare più file descriptor per vedere se l'I/O è possibile su uno di essi. È pensato per sostituire le vecchie system call POSIX select e poll, per ottenere prestazioni migliori in applicazioni più esigenti, dove il numero di file descriptor monitorati è grande.

Consulta la seguente tabella che confronta le prestazioni per 100.000 operazioni di monitoraggio:

N. operazioni poll select epoll
10 0.61 0.73 0.41
1002.93.00.42
100035350.53
100009909300.66

Quindi usare epoll è davvero molto più veloce quando hai più di 10 o giù di lì file descriptor da monitorare.

Il modello EPOLL usa socket non bloccanti, invece di usare Select fa uso della funzione Accept asincrona e di un pool di thread per gestire le connessioni client.

Per abilitare EPOLL sul server Indy di sgcWebSockets basta consultare il codice qui sotto.

oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.NotifyEvents := neNOSync;
oServer.IOHandlerOptions.IOHandlerType := iohEPOLL;
oServer.Active := True;