Alors que la plupart des serveurs sous Linux utilisent le service epoll pour gérer les E/S asynchrones, une nouvelle technologie est en train d’émerger et promet de se développer dans les années à venir : io_uring.

Fonctionnement

Développé par Jens Axboe depuis 2019, io_uring utilise une logique différente d’epoll pour éviter les copies de blocs mémoires dans le traitement des E/S.

Le fonctionnement basique est le suivant :

Image : Schéma explicatif du fonctionnement de io_uring

  1. un appel système asynchrone pour lire un fichier est fait par un programme (par exemple en python) ;
  2. la configuration/présence de la librairie io_uring dans le système fait que l’interpréteur/compilateur va utiliser la librairie io_uring ;
  3. l’instruction de lecture (await open(file)) via liburing/io_uring va mettre l’instruction readv dans une Submission Queue Entry (SQE). Cette structure de données va elle-même être mise en file dans la Submission Queue ;
  4. l’appel système io_uring_enter indique au kernel une nouvelle entrée, ou bien le kernel va scruter la queue (en mode poll) ;
  5. le système exécute l’instruction readv et place une structure Completion Queue Entry contentant le résultat du readv dans la Completion Queue ;
  6. le await readv est résolu et renvoie le résultat au programme.

Ce fonctionnement est détaillé dans cet article avec le code en C.

L’objectif est :

  1. de grouper les instructions relatives à un descripteur de fichier avant de déclencher io_uring_enter (ou le système va le faire en mode polling)
  2. d’éviter les copies de structures en partageant ces 2 buffers circulaires (Submission Queue/Completion Queue) entre le user space et le kernel space.

Efficacité

De nombreux benchmarks donnent des résultats impressionnants de io_uring par rapport à epoll. Comme dans ce tweet :

Dans ce benchmark, io_uring est 45% plus efficace avec un echo server TCP/IP. Comme les serveurs HTTP sont basés sur des sockets TCP/IP, on peut espérer des gains de performance significatifs.

Depuis ce tweet du 19 janvier 2020, les performances ont été encore améliorées :

passant de 3,4M IOPS (Input/Ouput Operations Per Second) sur un processeur, un coeur à 3,8M IOPS. Puis après avoir changé pour un processeur Ryzen 9 5950X, il a amélioré à 5.5M IOPS puis 6.1M IOPS et enfin 9M IOPS (toujours sur un proc/core):

Intégration dans le service d’Iroco ?

io_uring semble être une technologie prometteuse et beaucoup plus sobre. L’intégrer dans notre service serait alors un moyen d’en réduire davantage l’empreinte énergétique. C’est encore un modèle à éprouver dans des situations de production.

L’intégration de io_uring dans les serveurs mail dovecot/cyrus/postfix pourrait sans doute apporter des améliorations importantes de performance étant donné le nombre d’entrées sorties qui sont effectuées par ces serveurs. Les services auraient alors une empreinte énergétique encore plus faible.

Par suite, on peut aussi s’intéresser aux autres serveurs, comme les serveurs de persistence. Par exemple, les développeurs de Postgresql (la base de données d’Iroco) s’intéressent également à une implémentation du serveur qui utiliserait io_uring.

Nous suivons avec attention ces évolutions et nous essayerons aussi d’y participer.