2 points par GN⁺ 2025-08-23 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Pour créer des serveurs web hautes performances, on utilisait jusqu’ici divers modèles orientés événements comme select(), poll(), epoll
  • Mais face aux limites de performance de ces appels système, io_uring est apparu en introduisant une approche où les requêtes sont placées dans une file que le noyau traite de façon asynchrone
  • kTLS confie au noyau le traitement du chiffrement TLS, ce qui permet des optimisations supplémentaires comme la possibilité d’utiliser sendfile() et l’offloading matériel
  • L’introduction des descriptorless files fournit une méthode optimisée pour io_uring sans transmettre directement de descripteurs de fichiers
  • Le projet open source tarweb, qui combine Rust, io_uring et kTLS, fournit du HTTPS sans appel système supplémentaire par requête, tout en abordant les questions de sûreté et de gestion mémoire

L’évolution de l’architecture des serveurs web hautes performances

  • Depuis le début des années 2000, la demande pour des serveurs web à très forte capacité a augmenté
  • Au départ, il était courant de créer un nouveau processus pour chaque requête, mais le coût élevé de cette approche a conduit à l’apparition de la technique de preforking
  • Ensuite, avec l’introduction des threads et l’adoption de select(), poll(), l’architecture a évolué vers une réduction du coût des changements de contexte
  • Toutefois, avec select() et poll(), plus le nombre de connexions augmente, plus il faut transmettre fréquemment de grands tableaux au noyau, ce qui limite la scalabilité

L’arrivée d’epoll

  • Sous Linux, epoll a été introduit pour permettre une gestion des connexions multiples plus efficace que les approches précédentes
  • epoll ne traite que les changements (deltas), ce qui réduit la consommation inutile de ressources
  • Tous les appels système ne disparaissent pas complètement, mais leur coût diminue fortement

Vue d’ensemble d’io_uring

  • io_uring ajoute les requêtes à une file en mémoire afin que le noyau puisse les traiter de manière asynchrone, au lieu d’appeler un appel système pour chaque requête
  • Par exemple, si accept() est placé dans la file, le noyau le traite puis renvoie le résultat dans la file de complétion
  • Le serveur web fonctionne en ajoutant des requêtes à la file et en consultant les résultats dans une autre zone mémoire
  • Pour éviter une boucle active (busy loop), si rien ne change dans la file, le serveur web et le noyau n’effectuent des appels système que lorsque c’est nécessaire, ce qui permet aussi d’économiser de l’énergie
  • Avec les bibliothèques appropriées, un serveur actif peut fonctionner sans appel système supplémentaire pendant le traitement des requêtes

Environnements multicœurs et NUMA

  • Compte tenu des CPU modernes multicœurs, il est pertinent d’adopter une stratégie d’un seul thread par cœur et de minimiser le partage des structures de données
  • Dans un environnement NUMA, l’optimisation consiste à faire en sorte que chaque thread n’accède qu’à la mémoire de son nœud local
  • Un équilibrage parfaitement uniforme de la répartition des requêtes demande encore des recherches supplémentaires

Allocation mémoire

  • Des allocations mémoire subsistent à la fois dans le noyau et dans le serveur web, et les allocations en espace utilisateur finissent elles aussi par impliquer des appels système
  • Côté serveur web, des blocs mémoire de taille fixe sont préalloués par connexion afin de prévenir la fragmentation et les pénuries
  • Côté noyau, des buffers d’entrée/sortie sont également nécessaires pour chaque connexion, avec certains ajustements possibles via les options de socket
  • En cas de manque de mémoire, cela peut conduire à des pannes graves

Présentation de kTLS (Kernel TLS)

  • kTLS est une fonctionnalité du noyau Linux qui prend en charge les opérations de chiffrement et de déchiffrement
  • Le handshake est traité par l’application, mais ensuite le noyau gère les transferts de données comme s’il s’agissait de texte brut
  • Cela permet d’utiliser sendfile(), réduisant ainsi les copies mémoire entre espace utilisateur et espace noyau
  • Si la carte réseau le prend en charge, il est même possible de déporter les opérations de chiffrement vers le matériel

Descriptorless Files

  • Cette approche vise à réduire la surcharge liée à la transmission directe de descripteurs de fichiers de l’espace utilisateur vers l’espace noyau
  • Avec register_files, on utilise des numéros de fichiers distincts, valables uniquement pour io_uring, et qui n’apparaissent pas dans /proc/pid/fd
  • Les limites ulimit du système continuent toutefois de s’appliquer

Présentation du projet tarweb

  • tarweb est un projet open source de serveur web d’exemple qui met en œuvre l’ensemble des technologies ci-dessus
  • Sa structure consiste à servir le contenu d’un unique fichier tar, en combinant des technologies modernes à hautes performances comme Rust, io_uring et kTLS
  • En usage réel, des problèmes de compatibilité entre io_uring et kTLS (comme l’absence de prise en charge de setsockopt) sont apparus, et certains ont été résolus via des Pull Requests
  • Le projet est encore inachevé, et la bibliothèque rustls de Rust peut effectuer des allocations mémoire pendant le handshake
  • Le point essentiel est qu’un service HTTPS est possible sans appel système supplémentaire par requête

Benchmarks et mesures de performance

  • L’auteur n’a pas encore réalisé de benchmarks suffisants et prévoit des tests de performance après avoir remis le code en ordre

Problèmes de sûreté avec io_uring et Rust

  • Contrairement aux appels système synchrones, avec io_uring, les buffers mémoire ne doivent pas être libérés avant l’événement de complétion
  • Le crate io-uring ne garantit pas la sûreté à la compilation en Rust, et les vérifications à l’exécution sont également insuffisantes
  • En cas de mauvaise utilisation, cela peut provoquer des problèmes graves comparables à ceux du C++, ce qui affaiblit la sûreté intrinsèque de Rust
  • Un crate distinct, safer-ring, exploitant activement le pinning et le borrow checker, est nécessaire
  • Ce sujet fait déjà l’objet de discussions dans la communauté

Références et liens supplémentaires

  • Ce contenu résume un billet discuté sur HackerNews au 2025-08-22

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.