Indy Servers - IOCP Windows (2 / 3)

· Fonctionnalités

Depuis sgcWebSockets 2022.9.0, l'IOHandler IOCP du serveur Indy a été réécrit depuis zéro et les performances ont été améliorées. L'IOHandler IOCP n'est disponible que dans le package sgcWebSockets Enterprise.

Avec IOCP, tu peux éviter le problème « un thread par client » qui dégrade fortement les performances à mesure que le serveur gère plus de connexions. IOCP fournit quelques threads qui gèrent plusieurs clients. Les threads sont suspendus et n'utilisent pas de cycles CPU tant qu'il n'y a rien à traiter.

Configuration 

Pour activer IOCP sur les serveurs Indy, va dans la propriété IOHandlerOptions et sélectionne iohIOCP comme type d'IOHandler. 

Server.IOHandlerOptions.IOHandlerType := iohIOCP;
Server.IOHandlerOptions.IOCP.IOCPThreads := 0; // the number of IOCP threads will be calculated automatically using the number of processors.
Server.IOHandlerOptions.IOCP.WorkOpThreads := 0;

1. IOCPThreads sont les threads utilisés pour les requêtes asynchrones IOCP (opérations overlapped). Par défaut, la valeur est zéro, ce qui signifie que le nombre de threads est calculé en fonction du nombre de processeurs (sauf pour Delphi 7 et 2007 où le nombre de threads est défini à 32 parce que la fonction cpucount n'est pas prise en charge).

2. WorkOpThreads doit seulement être activé si tu veux que les connexions soient toujours traitées dans le même thread. Avec IOCP, les requêtes sont traitées par un pool de threads, et chaque requête (pour la même connexion) peut être traitée dans différents threads. Si tu veux gérer chaque connexion dans le même thread, définis dans WorkOpThreads le nombre de threads utilisés pour gérer ces requêtes. Cela impacte les performances du serveur ; il n'est recommandé de définir une valeur supérieure à zéro que si tu as besoin de cette fonctionnalité.

Activer IOCP sur les serveurs Windows est recommandé lorsque tu dois gérer des milliers de connexions. Si ton serveur ne gère que 100 connexions simultanées au maximum, tu peux rester avec le modèle de threads Indy par défaut.

Test de performances 

Un test simple montre les différences entre le modèle de threads Indy et IOCP. Le test se connecte au serveur via le protocole websocket ; l'usage CPU et la consommation mémoire sont présentés dans le tableau suivant. Le pourcentage d'usage CPU est mesuré pendant que le serveur est en IDLE.

Nb. connexions Indy IOHandler par défaut Indy IOHandler IOCP
100 0 % (4.1 Mo) 0 % (3.9 Mo)
5000 % (17.1 Mo)0 % (7.7 Mo)
10000 % (32.2 Mo)0 % (12.4 Mo)
15007.3 % (46.8 Mo)0 % (17.1 Mo)
200015.4 % (61.6 Mo)0 % (21.9 Mo)
250051.9 % (76.5 Mo)0 % (26.5 Mo)
300068.8 % (91.7 Mo)0 % (31.2 Mo)
350072.3 % (106 Mo)0 % (35.9 Mo)

Le serveur Indy a commencé à ralentir au-delà de 3000 connexions simultanées, très probablement à cause du thread context switch, et l'usage CPU était très élevé pendant que le serveur était inactif.

Le serveur IOCP n'utilisait pas de CPU lorsqu'il était en état idle et la consommation mémoire était également plus faible.

Le test suivant mesure le temps nécessaire pour connecter 3000 clients ; chacun envoie un message une fois connecté au serveur et le serveur fait écho à ce message.

Indy IOHandler par défaut Indy IOHandler IOCP
Connexion de 3000 clients et écho de message 15.32 secondes 6.89 secondes

Les tests de performances ont été réalisés sur un Windows Server 2022 avec 16 cœurs et 32 Go de RAM.