TCP, un non-sens dans les centres de données ? « Il est temps de [le] remplacer », affirme John K. Ousterhout.
L’informaticien américain – auquel on doit notamment le langage de script Tcl – reconnaît les avancées effectuées en vue d’améliorer le protocole. Par exemple avec les technologies DCTCP et HPCC pour le contrôle de congestion. Il estime toutefois que les défauts sont trop nombreux et trop intrinsèquement liés pour pouvoir espérer les corriger tous.
TCP : un protocole qui ne connaît pas les messages
De quels défauts parle-t-on ? Entre autres, de l’orientation des flux. Alors que les applications « modernes » implémentent les RPC par des échanges de messages, TCP travaille avec des flux d’octets.
La transmission des messages sous cette forme implique des compromis. TCP, en particulier, ne gère pas nativement la délimitation des messages (indiquant leur début et leur fin). En conséquence, lorsque les applications lisent un flux, on n’est pas certain qu’elles reçoivent un message complet. Elles doivent donc marquer elles-mêmes le début et la fin des messages quand elles les sérialisent, à l’aide d’un préfixe. Et être également capable de traiter cette information en entrée, afin de reconstituer les messages. Un tel modèle ajoute la charge de travail, en particulier pour maintenir l’état des messages partiellement reçus.
Le modèle du flux perturbe significativement la répartition de charge, ajoute John Ousterhout. Il prend l’exemple d’une application utilisant plusieurs tâches pour servir les requêtes en provenance d’un ensemble de flux. Dans l’idéal, toutes les tâches attendraient qu’un message arrive sur un flux, et les messages seraient distribués entre tâches. Mais avec TCP, on n’est pas certain d’obtenir, à chaque opération de lecture, un message entier. Plusieurs parties d’un même message peuvent ainsi être reçues différentes par tâches.
Coordonner les tâches pour reconstituer le message étant trop gourmand en ressources, les applications TCP ont recours à d’autres mécanismes d’équilibrage de charge, moins « qualitatifs », où chaque flux est rattaché à une seule tâche. Une approche, exploitée avec memcached, consiste à effectuer une division statistique des flux entre les tâches. Le risque : qu’une tâche reçoit trop de requêtes entrantes. Autre approche, utilisée par RAMCloud : dédier une tâche à la lecture de tous les messages entrants, puis les répartiteurs. Le problème ? Cette tâche « maîtresse » devient un goulet d’étranglement. Et, chaque requête traversant deux tâches, la latence augmente.
Des connexions à entretenir…
Deuxième « défaut » de TCP : l’orientation des connexions. Le protocole exige l’ouverture et le maintien d’une connexion pour chaque nœud avec lequel une application communiquée. Une contrainte dans l’univers du centre de données, où les paires peuvent se compter par centaines, voire milliers. Résultat : du temps perdu… et de l’espace. Le noyau Linux, par exemple, réserve environ 2000 octets – hors tampons – à l’état de chaque socket TCP.
Pour limiter la surtaxe, on peut exploiter la mécanique du proxy, en dédiant ce rôle à un certain nombre de tâches. Chaque serveur peut alors partager une connexion entre toutes les tâches d’une application. Mais cela alourdit la charge. Facebook, par exemple, un substitut préféré UDP à TCP lorsque son manque de fiabilité peut être toléré.
TCP, en outre, requiert un aller-retour de plus entre les hôtes par rapport à l’option d’échange de messages. Ce qui n’est pas rien dans les environnements sans serveuroù les applications ont une durée de vie courte.
… et une bande passante à partager
Troisième « défaut » : la gestion du partage de la bande passante. Lorsqu’un lien est surchargé sur un hôte, TCP tente de la répartir entre les connexions actives. Ce type de planification a malheureusement un impact sur les performances : tous les messages tendent à arriver en retard. Des approches, comme SRPT (Shortest Remaining Processing Time), apportent une forme de solution en réservant la bande passante à une tâche. Mais il est délicat de l’implémenter avec TCP, encore une fois à défaut d’informations sur le début et la fin des messages.
Quatrième « défaut » : le contrôle de la congestion. Avec TCP, c’est l’expéditeur qui l’effectue : il peut réduire le taux de transmission des paquets.
Pour détecter la congestion, TCP s’appuie sur l’occupation du tampon. Dans le pire des cas, les files d’attente des commutateurs débordent et des paquets se perdent, entraînant des délais d’attente. De plus, les commutateurs génèrent des notifications ECN lorsque le fichier d’attente dépasse un certain seuil.
Outre la dépendance au signal « occupation du tampon », TCP n’est pas capable d’exploiter les fichiers d’attente prioritaires des commutateurs modernes. Tous les paquets ont droit au même traitement. Dans ce contexte, l’acheminement des messages longs peut perturber celui des tribunaux.
On se trouve en quelque sorte face à un dilemme. Pour maintenir une faible latence sur les messages courts, il faut conserver les fichiers d’attente à un niveau proche de zéro… au risque de sous-utiliser les tampons. Au contraire, solliciter les tampons évite de réduire la bande passante pour les messages longs, mais augmente le délai d’acheminement des courts.
TCP, un sens de l’ordre qui gène
Cinquième « défaut » : l’acheminement des paquets, qui doit impérativement se faire dans l’ordre.
Dans le centre de donnéesla pratique du pulvérisation de paquets est la plus efficace pour la répartition de charge : chaque paquet est routé indépendamment. Mais on ne peut l’employeur avec TCP, car elle est susceptible de changer l’ordre d’arrivée. Il faut se rabattre sur le routage à flux constant : tous les paquets d’une même connexion régularisée le même chemin. À la clé, un risque de surcharge au cœur du réseau, même lorsque la charge globale est faible. Deux gros flux convergents vers un même lien intermédiaire peuvent suffire à perturber la transmission.
Le problème se pose aussi sur la répartition de charge par logiciel. Linux, par exemple, équilibre le trafic en distribuant le traitement des paquets entrants entre de multiples cœurs. Chaque paquet est traité sur deux cœurs avant d’atteindre l’application (qui peut résider sur un troisième cœur). Pour assurer une livraison dans l’ordre, tous les paquets doivent suivre le même chemin… avec les risques d’engorgement que cela implique lorsque deux connexions actives vont vers le même cœur.
Homa, une alternative qui a tout pour elle ?
Plutôt que d’apporter des modifications graduelles ou de passer au « modèle message » (ce qui induirait de lourds changements d’API), John Ousterhout a avancé le protocole Homa. Il implémente les appels de procédures distants (RPC) et permet à plusieurs tâches de lire des messages sur un même socket.
L’homme ne nécessite pas de maintenir des connexions : une application peut utiliser un seul socket pour gérer les concurrents RPC avec de multiples paires. L’état est maintenu au niveau du socket, à hauteur d’environ 300 octets pour chaque RPC actif (espace libéré ensuite). C’est au destinataire que revient le contrôle de la congestion. Ce qui fait sens, assure John Ousterhout, le premier goulet d’étranglement étant le lien descendant. Dans les grandes lignes, l’expéditeur peut envoyer quelques paquets… et ne transmettre les autres qu’une fois que le destinataire l’y a autorisé.
La plupart des applications à grande échelle reposant sur des cadres RPC de type gRPC ou Apache Thrift, c’est une voie plus aisée que les API pour insérer Homa.
Photo d’illustration créée par IA