11 points par dalinaum 2023-03-03 | 4 commentaires | Partager sur WhatsApp

L’équipe de recommandation de Kakao développe une nouvelle plateforme destinée à remplacer la plateforme de machine learning existante.

Avec Python, le langage principal de l’équipe, il était un peu difficile d’atteindre à la fois de bonnes performances et un haut niveau de sûreté pour l’application.

L’équipe a introduit Rust dans une application de métriques utilisateurs afin de vérifier s’il était pertinent d’implémenter l’application en Rust.

  • Rust traite les tâches environ 1,9 fois plus vite que Python
  • En consommation mémoire, Python utilise environ 4,5 fois plus que Rust
  • L’utilisation CPU de Python est jusqu’à 3 fois plus élevée que celle de Rust, et environ 2 fois plus élevée en moyenne
  • Avec asyncio pour Python et tokio pour Rust, appliqués chacun aux applications de leur langage, même dans un environnement mono-thread où le traitement asynchrone était implémenté de façon identique, la vitesse de traitement des messages en Rust était environ 10 fois plus rapide qu’en Python.

L’un des grands inconvénients de Rust a été son coût d’apprentissage élevé.

Même lors du développement en Python, les annotations de type étaient imposées. En implémentant l’application de métriques utilisateurs en deux versions, l’équipe n’a pas fortement ressenti d’écart de temps de développement entre Python et Rust.

La plus grande différence perçue en matière de productivité concernait le temps de compilation. (y compris le temps de téléchargement des packages dans Docker)

  • Rust : environ 340 secondes
  • Python : environ 100 secondes

En Python, les données créées par des bibliothèques sans informations de type prennent le type Any, pour lequel la vérification de type est ignorée. Cela réduit la précision globale de la vérification de type dans le projet.

Il y avait aussi des différences comme l’usage des exceptions en Python et du type enum Result en Rust.

Outils de développement
Dans le cas de Rust, cargo fournit de nombreuses fonctionnalités par défaut.
Les outils de développement Python étaient très aboutis et relativement simples à utiliser une fois installés.

4 commentaires

 
jongpak 2023-03-03

Je n’ai d’expérience ni avec Python ni avec Rust, mais en me basant uniquement sur l’article… je n’arrive pas vraiment à percevoir de grands avantages à l’adoption de Rust.

Ce n’est pas que Rust soit mauvais, mais les expérimentations menées pour justifier son adoption paraissent aussi assez faibles
(se baser sur le résultat du traitement de seulement 50 messages pour affirmer que c’est plusieurs fois plus rapide donc plusieurs fois meilleur, ça me semble être une démonstration vraiment fragile…)

Et puis la comparaison ne porte même pas sur une logique de traitement identique (synchrone vs asynchrone)…
[une bibliothèque Python qui prend en charge le traitement asynchrone des messages mais avec peu de références] vs [le langage Rust, dont le coût d’apprentissage est élevé et dont la maintenance présente un risque si elle repose sur peu de personnes]
Quand on met ces deux situations côte à côte, je me demande aussi si la question de la pérennité à long terme a vraiment été étudiée sérieusement (du moins, c’est l’impression que le texte m’a laissée)

Par nature, l’ETL semble souvent nécessiter des tests courts et fréquents ; dans ce contexte, 100 secondes de build contre 300 secondes, ça ressemble à un gros goulot d’étranglement pour le développement…
L’article mentionne que les builds incrémentaux sont excellents, mais remplace cette explication par un simple lien…

En pratique, ils ont probablement fait beaucoup de recherches et d’évaluations, mais au moins à la lecture du texte… on ne comprend pas vraiment en quoi l’adoption de Rust a concrètement amélioré les choses, quels effets étaient attendus, ni quel problème cela a réellement résolu, et il est difficile d’y adhérer.


Personnellement, j’ai déjà vu des cas où une technologie était choisie parce que c’était « la techno à la mode du moment » ou pour ajouter une ligne sur un CV, mais au final, dans la plupart des cas, l’équipe n’était même pas capable de la maintenir, et cela finissait en dette technique.

  • Par exemple, insister sur Kafka ou sur un traitement asynchrone alors que la charge est faible et qu’un traitement séquentiel ne poserait absolument aucun problème
  • Appliquer une solution asynchrone parce qu’on dit que c’est bien, sans tenir compte du contexte de l’équipe, puis se retrouver avec un système très difficile à dépanner et qui devient au final un nouveau legacy…
  • Dire qu’adopter tel ooo récemment à la mode apporterait tel ou tel avantage… puis, dès qu’un autre ooo encore plus à la mode apparaît, affirmer que c’est désormais lui qu’il faut adopter…

Bien sûr, je ne dis pas que cet article sur Rust est dans ce cas, et j’espère que ce n’est pas le cas…
Mais après avoir vu à plusieurs reprises que ce sont les membres de l’équipe qui subissent les conséquences de technologies adoptées sans réflexion sérieuse, je crois que cela me rend plus prudent quand je lis ce genre d’articles de promotion technologique.

 
ehlegeth 2023-03-03

À première vue, cela ressemble essentiellement à une tâche d’ETL. Je me demande si vous n’avez pas envisagé Java, qui a aussi des atouts dans ce domaine aux côtés de Python, et s’il y a une raison de l’avoir écarté au profit de Rust, j’aimerais la connaître.

 
kayws426 2023-03-03

Il est dommage qu’une partie des données de comparaison des performances ait été obtenue à partir de tests à petite échelle.

 
ehlegeth 2023-03-03

La portée d’un test de performance varie beaucoup selon la nature de la charge de travail, donc c’est dommage qu’il n’y ait pas d’explication sur la conception du test ni sur la manière dont les chiffres ont été obtenus.
Par exemple, je me demande si, après avoir traité 5 millions d’éléments, vous avez calculé une moyenne arithmétique en prenant comme base le traitement de 50 éléments, et dans ce cas, comment l’utilisation mémoire a été mesurée, ou encore comment la différence d’utilisation CPU a été évaluée. (Le temps est probablement du wall-clock time, n’est-ce pas ?)
Par ailleurs, il y a cette interprétation selon laquelle, « en regardant l’utilisation CPU, l’essentiel de l’écart de performance entre les deux langages provient des opérations d’entrée/sortie (Input Output, ci-après IO), à savoir la consommation de messages Kafka et l’enregistrement de documents MongoDB ». Mais dans les résultats, vous dites que le wall-clock time de Rust était environ deux fois plus court, tandis que l’utilisation CPU (CPU time ?) était de 1/4,5 ; du coup, je ne comprends pas très bien la logique : est-ce que vous parlez d’une différence de méthode d’implémentation liée à l’I/O, ou bien d’une différence dans la manière de traiter des données d’I/O nécessitant beaucoup de CPU ? En réalité, l’avantage de Rust sur les tâches CPU-intensive est déjà bien connu, donc si c’est le second cas, il ne me semble pas vraiment nécessaire de mentionner la différence entre bibliothèques. Au contraire, si l’expérience portait sur une tâche CPU-intensive, on aurait plutôt dû observer un écart bien plus important, comme dans la comparaison asyncio/tokio mentionnée dans l’article ; j’ai donc l’impression qu’il faudrait plutôt interpréter les résultats comme un écart de performance atténué à cause de l’I/O.