Le Blog Amazon Web Services
La programmation durable avec Rust
Rust est un langage de programmation implémenté sous la forme d’un ensemble de projets open source. Il combine les performances et l’efficacité des ressources des langages de programmation système comme C avec la sécurité mémoire de Java. Rust a commencé en 2006 en tant que projet personnel de Graydon Hoare, avant de devenir un projet de recherche Mozilla en 2010. Rust 1.0 a été lancé en 2015. En 2020, le support de Rust est passé de Mozilla à la Rust Foundation, une organisation à but non lucratif créée en partenariat entre Amazon Web Services (AWS), Google, Huawei, Microsoft et Mozilla. La mission de la Fondation est de soutenir la croissance et l’innovation de Rust. Les entreprises membres de celle-ci sont passées des 5 à 27 en un an.
Chez AWS, Rust est rapidement devenu essentiel à la construction d’infrastructures à grande échelle. Firecracker est une technologie de virtualisation open source qui alimente AWS Lambda et d’autres offres serverless. Il a été lancé publiquement en 2018 en tant que premier produit AWS notable implémenté avec Rust. Nous utilisons Rust pour fournir des services tels qu’Amazon Simple Storage Service (Amazon S3), Amazon Elastic Compute Cloud (Amazon EC2), Amazon CloudFront, et plus encore. En 2020, nous avons lancé Bottlerocket, un système d’exploitation pour conteneur basé sur Linux et écrit en Rust. Nos équipes Amazon EC2 utilisent également Rust pour le système AWS Nitro, y compris dans les applications sensibles, telles que Nitro Enclaves.
Chez AWS, nous pensons que les leaders créent plus qu’ils ne consomment et laissent toujours les choses en meilleur état qu’ils ne les ont trouvées.
En 2019, AWS était fier de devenir un sponsor du projet Rust (article en anglais). En 2020, nous avons commencé à embaucher des contributeurs de Rust (article en anglais) et nous sommes associés à Google, Huawei, Microsoft et Mozilla pour créer la Rust Foundation, avec pour mission de soutenir le développement du language. AWS investit dans Rust, un langage qui, selon nous, devrait être utilisé pour créer des solutions durables et sécurisées.
L’efficience énergétique dans le cloud
Source : AIE (2021), Demande mondiale d’énergie des centres de données par type de datacenters, 2010-2022, https://www.iea.org/data-and-statistics/charts/global-data-centre-energy-demand-by-data-centre-type-2010-2022. Tous droits réservés.
Dans le monde, les centres de données consomment environ 200 térawattheures par an. Cela représente environ 1% de toute la consommation énergétique mondiale. Si vous regardez le graphique de la consommation d’énergie, la ligne du haut est presque plate depuis 2010. C’est contre-intuitif compte tenu de la croissance du Big Data, du Machine Learning et de l’IoT (Internet des objets) que notre industrie a connue au cours de la même période.
Le deuxième détail intéressant est que même si la ligne supérieure du graphique est plate, à l’intérieur du graphique, la distribution entre les datacenters traditionnels (clients opérants eux-mêmes on-premises), cloud et hyperscale (mise à disposition de ressources à la demande) a radicalement changé au cours de la même période. Ces datacenters cloud et hyperscale ont mis en œuvre d’énormes améliorations en matière d’efficacité énergétique, et la migration vers le cloud a maintenu l’équilibre de la consommation énergétique totale des datacenters malgré la croissance massive du stockage et du calcul pendant plus d’une décennie.
Il y a eu trop d’améliorations de l’efficacité des centres de données pour toutes les énumérer, mais en voici quelques exemples. En matière de calcul, nous avons amélioré l’efficacité du matériel et mis en œuvre une utilisation plus intelligente des ressources pour réduire les temps d’inactivité. Nous avons ralenti la croissance de nos serveurs grâce à la prise en charge du multi-instance et du multi-tenant, et nous avons amélioré la densité et l’efficacité des disques pour le stockage. Nous avons également adopté des matériaux de construction et des systèmes de refroidissement plus économes en énergie.
Malgré toutes ces améliorations, des questions demeurent. Premièrement, le statu quo est-il suffisant ? Est-ce assez de maintenir la consommation d’énergie des datacenters à 1% de la consommation mondiale d’énergie ? La deuxième question qui se pose est de savoir si les innovations en matière d’efficacité énergétique continueront à suivre le rythme de la croissance du stockage et du calcul à l’avenir. Compte tenu de l’explosion que nous connaissons des drones, des robots de livraison et des véhicules autonomes, de la quantité de données générées, de traitement, d’entrainement et d’inférence de Machine Learning nécessaires pour prendre en charge ces technologies, il semble peu probable que les innovations en matière d’efficacité énergétique soient en mesure de suivre le rythme de la demande.
Les améliorations de l’efficacité énergétique dont nous avons parlées jusqu’à présent relèvent de la responsabilité d’AWS, mais tout comme la sécurité, la durabilité est une responsabilité partagée. Les clients d’AWS sont responsables des choix d’efficacité énergétique dans les politiques de stockage, la conception de logiciels et l’utilisation du calcul, tandis qu’AWS est en charge de l’efficacité du matériel, de la mise en commun des ressources pour augmenter l’utilisation des serveurs et des systèmes de refroidissement. Nous faisons également d’énormes investissements dans les énergies renouvelables.
AWS est sur la voie pour que 100% de nos datacenters soient alimentés par des énergies renouvelables d’ici 2025. Cependant, même les énergies renouvelables ont un impact sur l’environnement. Il faudra environ deux cent mille hectares de panneaux solaires pour générer les 200 TWh d’énergie utilisés par les datacenters. L’extraction, la fabrication et la gestion de ces nombreux panneaux solaires ont un impact environnemental non négligeable. Ainsi, comme Peter DeSantis, SVP Infrastructure AWS, le rappelait, « L’énergie la plus verte est celle que nous n’utilisons pas. »
Les énergies renouvelables ne doivent pas remplacer l’efficacité énergétique en tant que principe de conception. De la même manière que l’excellence opérationnelle, la sécurité et la fiabilité ont été des principes de conception logicielle depuis toujours, la durabilité doit être un principe dans la conception des logiciels d’aujourd’hui et de demain. C’est pourquoi AWS a annoncé un sixième pilier pour la durabilité dans le cadre AWS Well-Architected Framework.
En pratique, cela se traduit par des choix à faire tels que l’assouplissement des SLA pour les fonctions non critiques ou encore la priorisation de l’efficacité de l’utilisation des ressources. Nous pouvons tirer parti de la virtualisation et permettre des cycles de renouvellement des serveurs plus longs, mettre en cache avec des TTLs aussi élevés que possible. Il faut également classifier les données et mettre en place des politiques de cycle de vie automatisées qui suppriment les données quand cela est possible. Lorsque nous choisissons des algorithmes de cryptographie ou de compression, nous devons inclure l’efficacité dans nos critères de décision. Enfin, nous pouvons choisir d’implémenter nos logiciels dans des langages de programmation économes en énergie tel que Rust.
Langages de programmation économes en énergie
Il y a quelques années, une étude a été publiée (en anglais), examinant la corrélation entre la consommation d’énergie, les performances et l’usage mémoire. C’est une conversation courante en matière de durabilité. Pour avoir de la visibilité sur la consommation énergétique ou l’impact des émissions carbone d’une application, existe-t-il une métrique qui peut servir de proxy ? Pouvons-nous, en consultant les dashboards de monitoring qui nous donnent les coûts d’infrastructure, les performances, la mémoire, etc. en extraire des informations pour déduire quelque chose sur les tendances de la consommation d’énergie ?
Cette étude a mis en œuvre 10 problèmes de référence dans 27 langages de programmation différents et a mesuré le temps d’exécution, la consommation d’énergie et l’utilisation maximale de la mémoire. C et Rust ont nettement surpassé les autres langages en termes d’efficacité énergétique. Ils étaient environ 50% plus efficaces que Java et 98% plus efficaces que Python.
Sans surprise, C et Rust sont plus efficaces que d’autres langages. Ce qui est notable, c’est l’ampleur de cette différence. L’adoption généralisée de C et de Rust pourrait réduire la consommation d’énergie du calcul de 50%, même avec une estimation prudente.
Donc la question est pourquoi ne pas plus utiliser le C plus souvent ? Le langage et les outils de développement sont extrêmement matures et la taille de la communauté des développeurs est bien plus importante que pour Rust. Lors de son discours au Open Source Summit en 2021, Linus Torvalds, le créateur de Linux, a reconnu que l’implémentation de code en C peut être à double tranchant. En tant que programmeur C de longue date, Linus Torvalds sait que « Les interactions de type subtiles du C ne sont pas toujours logiques et sont des pièges pour à peu près tout le monde ».
Linus Torvalds considère Rust comme le seul langage qui pourrait être une solution. Rust offre l’efficacité énergétique de C tout en fournissant la simplicité des langages modernes et en évitant le risque de comportement imprédictible. Nous pouvons ainsi réduire de moitié la consommation d’énergie sans perdre les avantages de la sécurité des accès mémoire.
Plusieurs analyses ont conclu que plus de 70% des vulnérabilités qui se produisent en C/C++ seraient évitées en implémentant ces mêmes solutions en Rust. En fait, l’Internet Security Research Group (ISRG), l’organisation à but non lucratif qui soutient le projet Let’s Encrypt, l’autorité de certification de 300 millions de sites Web (chiffre dont on peut voir l’évolution sur Let’s Encrypt Stats), a pour objectif de déplacer toutes les infrastructures sensibles pour la sécurité d’Internet vers des langages sécurisés en mémoire. Les projets en cours incluent la prise en charge de Rust dans le noyau (kernel) Linux et la migration de curl vers les implémentations en Rust de TLS et HTTP.
En se penchant à nouveau sur cette étude, nous avons des mesures qui vont au delà de la simple consommation d’énergie. La colonne du milieu montre que les résultats sur le temps d’exécution pour Rust et C sont très similaires. Les deux langages s’exécutent beaucoup plus rapidement que les autres. Ainsi, lorsque vous choisissez d’implémenter votre logiciel en Rust pour ses avantages de durabilité et de sécurité, vous bénéficiez également des performances optimisées du C.
Témoignages de clients utilisant Rust
Source : https://medium.com/tenable-techblog/optimizing-700-cpus-away-with-rust-dc7a000dbdb2
Tenable.io est un fournisseur de solutions de cybersécurité offrant des outils de visibilité sur les vulnérabilités. Ils disposent d’un agent filtrant les métriques inutiles. Celui-ci a été écrit en JavaScript et fonctionnait en production depuis quelques mois lorsque les performances ont commencé à se dégrader en raison du passage à l’échelle. Tenable.io a donc décidé de réécrire ce filtre dans un langage plus efficace et a choisi Rust pour ses performances et sa sécurité. Le résultat a été une diminution d’environ 50% de la latence réseau à la fois à la médiane et au P95.
Ces améliorations de performances de 50% sont excellentes, d’autres graphiques de cette migration nous montrent que Tenable.io a également constaté une réduction de 75% de l’utilisation processeur et 95% pour celle de la mémoire. Ce sont des économies substantielles, non seulement budgétaires mais aussi énergétiquement. Ces diminutions montrent une solution durable et économe en énergie.
Rust est utilisé aujourd’hui pour mettre des logiciels en production, mais les développeurs ne choisissent pas Rust pour réduire les émissions de carbone. Lorsque nous leur demandons pourquoi ils ont commencé à utiliser Rust, la réponse de loin la plus courante est : les performances d’exécution. Que ce soit parce que Rust est plus rapide ou parce que Rust a des temps de latence plus fiables, il s’agit presque exclusivement de son apport sur les performances.
Discord a construit son service en utilisant principalement Python, Go et Elixir, mais ils ont eu un problème avec l’un de leurs principaux services codés en Go. Bien qu’assez simple, il connaissait une latence importante. Étant donné que Go est un langage de programmation qui utilise un garbage collector (ramasse-miettes), lorsque des objets sont créés et publiés, de temps en temps, le garbage collector doit arrêter l’exécution du programme et exécuter une passe de récupération d’emplacements mémoire. Pendant que le GC (Garbage Collector) est en cours d’exécution, le processus est incapable de répondre aux demandes. On peut constater les pics sur les graphiques CPU et temps de réponse lorsqu’il est en cours d’exécution.
GO Rust
Pour résoudre le problème, Discord a décidé de tenter la réécriture du service en Rust, en voici les résultats. A gauche, l’implémentation en Go à droite, celle en Rust. Alors que le pic GC a disparu sur le graphique Rust, la différence vraiment étonnante est l’ampleur du changement. En effet, les graphiques Go et Rust utilisent des unités différentes.
La version Rust est dans l’ensemble 10 fois plus rapide avec les latences maximales d’un facteur 100. Ce sont des améliorations tout à fait incroyables car le serveur est capable de répondre aux demandes beaucoup plus efficacement, avec moins de ressources, réduisant donc la quantité d’énergie utilisée. Bien que Discord n’ait pas décidé d’utiliser Rust pour réduire la consommation d’énergie, l’impact est quand même là.
Encore une fois, Rust n’est pas le premier langage efficace. C existe depuis longtemps, mais Rust est le premier langage de programmation grand public efficace sans compromettre la sécurité. 70% de toutes les vulnérabilités de sécurité avec C et C++ sont dues à une insécurité de la mémoire, et Rust permet d’obtenir de meilleures performances sans prendre de risques.
La recette secrète de Rust
La plupart des langages assurent la sécurité de la mémoire en la gérant automatiquement au moment de l’exécution avec un garbage collector. Les récupérateurs de mémoire suivent les références d’emplacements mémoire et lorsqu’il n’y a plus de référence à cet emplacement, la mémoire associée peut être libérée.
Au lieu d’utiliser un garbage collector pour maintenir la sécurité, Rust utilise la propriété (ownership) et la vérification des emprunts (borrowing). La propriété est assez simple mais a des implications profondes pour le reste du langage de programmation Rust. Dans Rust, toute la mémoire appartient à une seule variable. Cette variable est appelée son propriétaire. Il ne peut y avoir qu’un seul propriétaire à la fois, mais la propriété des données peut être transmise.
Tout d’abord, ci-dessus un exemple de passage de message avec Go. À gauche, nous créons une variable gift
, puis l’envoyons via le channel. Sur une autre routine à droite, la variable est reçue et ouverte. Le garbage collector de Go va gérer la mémoire pour nous. Cependant, dans la partie gauche du code, nous avons accidentellement ouvert la variable après l’avoir envoyée dans la channel. Etant ouverte deux fois, cela entraînera un bug.
Voici le même exemple de passage de message avec Rust. La variable gift est créée et attribuée. Disons que la variable gift
possède les données. La propriété de gift
est transmise au channel. Le consommateur du channel reçoit la variable, en prend possession et peut l’ouvrir. Si nous essayons de l’ouvrir après l’avoir envoyé dans le channel, le compilateur lèvera une erreur car nous violons les règles de propriété. Ainsi, nous voyons comment Rust nous aide à prévenir les bugs.
Étant donné que Rust applique la règle selon laquelle une seule variable possède les données, lorsque cette variable sort de la portée sans transmettre la propriété, il n’y a aucun moyen d’accéder aux données. Rust en profite et libère automatiquement la mémoire à ce stade. Il n’est pas nécessaire de le faire manuellement.
Le modèle de propriété de Rust fait partie du système de types et est basé sur un concept appelé types affines. Un type affine impose une règle selon laquelle chaque variable est utilisée au plus une fois. La clé est de définir ce que signifie utilisé. Dans le contexte de Rust, une utilisation consiste soit à déplacer les données, soit à les supprimer. En utilisant des types affines, le compilateur Rust est capable de raisonner sur un programme et d’appliquer ses règles de propriété.
Le système de type affine utilisé par Rust est basé sur le travail effectué au début des années 1990, lorsque certaines personnes ont tenté de concevoir un Lisp (langage appartenant à la famille Lisp) sans garbage collector mémoire. Bien qu’ils aient réussi, ils ont constaté qu’ils perdaient beaucoup en performance d’exécution, en raison de la copie excessive introduite par l’impossibilité d’avoir plusieurs références au même morceau mémoire.
Cela nous amène à la deuxième innovation qui a permis à Rust d’exister : le vérificateur d’emprunt. Lors de l’écriture de programmes plus importants, nous avons tendance à utiliser des couches abstractions pour aider à l’organisation du code. Une couche d’abstraction que vous connaissez probablement est la fonction. Les fonctions nécessitent souvent des arguments. Avec uniquement la propriété, pour appeler une fonction, nous aurions besoin de transmettre la propriété des données à la fonction et la fonction devrait retransmettre la propriété des données lors du retour. Cela nécessite de copier de la mémoire et a été la source de problèmes de performances de Lisp sans garbage collector mémoire.
Pour résoudre ce problème, Rust nous permet d’emprunter des données. Donc, si nous avons la variable gift, nous la possédons. Si elle est empruntée, elle doit être rendue à son propriétaire par la suite. De plus, pendant son emprunt, la propriété ne peut être cédée. Plus important encore, le compilateur Rust applique ces règles, de sorte que celui qui emprunte la variable ne peut pas la garder. Lors de l’emprunt de données, la mémoire n’a pas besoin d’être copiée. La mémoire reste à son emplacement et un pointeur est passé. Le pointeur est garanti valide. Lorsque vous mettez tout cela ensemble, vous avez un système efficace, qui empêche les bugs, même si le programme grandit et devient plus complexe.
Bien que le système empêche l’insécurité de la mémoire, il peut également empêcher les bugs liés à la concurrence d’accès aux données. Une concurrence d’accès se produit lorsque deux threads ou plus tentent d’accéder simultanément aux mêmes données et qu’au moins l’un de ces accès est une mutation. Le système de type utilisé par Rust, qui modélise la propriété et l’emprunt est capable de maintenir la même garantie sur plusieurs threads, permettant une utilisation plus agressive de la concurrence.
Synchrone Parallèle
Voici un exemple de la facilité avec laquelle il possible de parraléliser une application en Rust. Nous avons une fonction qui parcourt un tableau de nombres et additionne tous les nombres pairs. Il s’agit d’une opération hautement parallélisable et pour les très grands tableaux, nous pourrions voir la fonction devenir beaucoup plus rapide en ajoutant de la parallélisation.
La version de gauche montre une version à un seul thread et la version de droite vous montre la version parallèle utilisant la bibliothèque Rayon. Il est étonnant de voir à quel point les fonctions sont similaires. Vous obtenez toute la puissance de la parallélisation, sans les risques, en écrivant presque le même code. La seule différence est que nous utilisons la méthode par_iter()
au lieu de iter()
.
La version parallèle répartira le calcul sur de nombreux threads, tout en évitant de copier le tableau de nombres passé en argument. Rayon est en mesure de fournir cette API en toute sécurité grâce au système de contrôle de propriété et d’emprunt de Rust. Toutes les vérifications pour garantir la sécurité ont lieu au moment de la compilation.
Commencer avec Rust
Nous espèrons que nous avons éveillé votre curiosité sur Rust et que vous entamerez votre chemin vers la durabilité dans le cloud. Alors, par où commencer ? La bonne nouvelle est que tout le contenu nécessaire est disponible en ligne.
Tout d’abord, vous devrez apprendre le langage de programmation Rust. The Rust book est excellent pour débuter. Cela vous aidera à installer la chaîne d’outils Rust et à apprendre le langage. Le site Web propose également des exercices et de nombreux exemples de code à lire. Si vous êtes bloqués à un moment donné, avez des questions ou avez besoin d’éclaircissements, vous pourrez poster sur le forum des utilisateurs ou parler directement sur le serveur communautaire Discord. Le serveur Discord est généralement le moyen le plus rapide d’obtenir de l’aide. Il y a toujours des personnes actives qui peuvent répondre aux questions en temps réel.
Une fois que vous avez parcouru le site Web de Rust, vous devriez être suffisamment à l’aise pour commencer à construire des choses, mais il existe une autre ressource que nous voulons appeler pour aller plus loin. The Crust of Rust est une excellente chaîne YouTube de Jon Gjenset. Il va dans la profondeur sur divers sujets liés à Rust, en ouvrant le capot et en expliquant comment les choses fonctionnent. Ses vidéos durent plusieurs heures, mais le retour que nous avons est qu’elles sont précieuses pour apprendre Rust.
Le futur de Rust
Rust est difficile à apprendre. Sur plus de 8 000 développeurs ayant répondu à l’enquête auprès des utilisateurs de Rust en 2020, seuls une centaine environ se sont identifiés comme « experts », et parmi les répondants qui ont déclaré qu’ils n’utilisaient plus Rust, 55% ont cité l’apprentissage ou la productivité comme raison d’abandon du langage.
Il faut aux ingénieurs expérimentés 3 à 6 mois d’études, soutenus par l’accès à des experts en la matière, pour devenir productifs avec Rust. Certains ingénieurs ont comparé l’apprentissage de Rust à celui de la marche, et bien que beaucoup d’entre eux l’aiment une fois qu’ils sont productifs, beaucoup d’ingénieurs décident de ne pas l’apprendre ou d’abandonner l’effort avant qu’ils ne deviennent productifs. L’impact potentiel de Rust sur la durabilité et la sécurité ne se matérialisera que si le language est adopté à grande échelle.
SlashData, État de la nation développeur Q3 2021 (State of the Developer Nation)
Aucun développeur, service ou entreprise ne peut avoir seul un impact substantiel sur la durabilité. L’adoption de Rust, c’est comme le recyclage; cela n’a d’impact que si nous participons tous. Pour parvenir à une large adoption, nous allons devoir développer la communauté des développeurs.
La communauté de développeurs Rust a été celle avec la croissance la plus rapide au cours des deux dernières années, mais sur la base des tendances historiques, nous savons que sur le demi-million de développeurs qui ont rejoint la communauté Rust au cours des 12 derniers mois et que la plupart d’entre eux ne maîtrisent pas encore le langage. Nous avons du travail à faire sur l’expérience développeur en Rust.
La question qui se pose est quelle expérience développeur ? Les ingénieurs travaillant sur le noyau Linux ont une expérience de développement idéale très différente de celle d’un ingénieur créant un service de base de données ou d’un ingénieur livrant un site Web de vente au détail. Nous pouvons identifier les utilisateurs de Rust en examinant trois dimensions.
La première distinction est leur raison d’en venir à Rust. Choisissent-ils Rust pour la performance ? La sécurité ? la durabilité ? La deuxième distinction est le domaine. Travaillent-ils dans un environnement embarqué avec des ressources restreintes ? Dans l’apprentissage automatique avec des travaux de longue durée qui contiennent d’énormes quantités de données dans des calculs incrémentiels ? La troisième distinction est l’expérience développeur. Sont-ils programmeurs système ? Peut-être n’ont-ils travaillé qu’avec des langages à typage dynamique ?
Rust est une technologie incroyable pour soutenir et sécuriser notre industrie. Il y a encore beaucoup de travail à faire avant que tout le monde puisse utiliser Rust, et la Rust Foundation s’attelle à créer des plateformes pour une collaboration plus efficace et intersectorielle sur ce travail. Nous espérons que vous vous joindrez à nous.
Article original rédigé par Shane Miller anciennement leader de l’équipe Rust AWS et siégant à la fondation Rust et Carl Lerche, Principal Engineer. Adapté en français par Eloi Ancellin, Solutions Architect dans les équipes AWS France.