<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Florentin Dubois, Author at Clever Cloud</title>
	<atom:link href="https://www.clever.cloud/fr/blog/author/florentin-duboisclever-cloud-com/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>From Code to Product</description>
	<lastBuildDate>Wed, 15 Jul 2026 14:46:38 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://cdn.clever-cloud.com/uploads/2023/03/cropped-cropped-favicon-32x32.png</url>
	<title>Florentin Dubois, Author at Clever Cloud</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Magnetar : un client Apache Pulsar en Rust conçu pour la simulation déterministe</title>
		<link>https://www.clever.cloud/fr/blog/engineering-fr/2026/07/15/magnetar-client-apache-pulsar-rust-simulation-deterministe/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Wed, 15 Jul 2026 14:46:37 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Rust]]></category>
		<guid isPermaLink="false">https://www.clever.cloud/?p=24982</guid>

					<description><![CDATA[<p><img width="2400" height="1065" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.15 Clever Cloud Bannière Blog Magnetar FR" decoding="async" fetchpriority="high" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png 2400w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1368x607.png 1368w" sizes="(max-width: 2400px) 100vw, 2400px" /></p><!-- wp:paragraph -->
<p><a href="https://apple.github.io/foundationdb/testing.html">FoundationDB</a> a rendu cette idée célèbre. Au lieu de s'appuyer seulement sur des tests unitaires et des tests end-to-end sur un vrai cluster, le projet exécute des workloads distribués dans un monde simulé, où le temps, les fautes réseau, les pannes de processus et les décisions d'ordonnancement peuvent être explorés puis rejoués à partir d'une seed. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">TigerBeetle</a> pousse une discipline complémentaire : rendre les invariants explicites dans le code, vérifier en continu la forme de l'état et transformer une corruption silencieuse en panne locale et bruyante.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous appliquons cette direction à des logiciels d'infrastructure en Rust. <a href="https://github.com/PierreZ/moonpool">Moonpool</a>, développé par Pierre Zemb, donne aux systèmes Rust un environnement de simulation déterministe où le temps, le réseau, les tâches, l'aléa et le stockage peuvent être virtualisés derrière des traits de providers. <a href="https://github.com/CleverCloud/magnetar">Magnetar</a> est l'application de cette approche à un client <a href="https://pulsar.apache.org/">Apache Pulsar</a>. C’est d’ailleurs, l’approche que nous prenons au sein de notre reverse proxy <a href="https://www.clever.cloud/fr/blog/entreprise/2026/07/01/sozu-2-1-0-load-balancing-udp-edge-programmable/">Sōzu</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est un driver Apache Pulsar écrit en Rust, depuis zéro. Il repose sur un coeur protocolaire sans-io, un moteur de production Tokio et un moteur Moonpool pour la simulation déterministe. Cette première release publique s'adresse aux ingénieurs qui veulent essayer Magnetar, évaluer son architecture, comparer son comportement avec les clients Pulsar existants et contribuer à structurer un écosystème Pulsar Rust plus solide.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'objectif n'est pas seulement d'exposer une API Rust autour de Pulsar. L'objectif est de construire un client dont les comportements difficiles peuvent être inspectés, rejoués et forcés à échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Un client Pulsar fait partie du système distribué</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>On pourrait être tenté de considérer une bibliothèque cliente comme la partie simple d'un système distribué. Le broker porterait la réplication, le stockage, l'ownership et la coordination. Le client se contenterait de se connecter, d'envoyer des messages, d'en recevoir et de les acquitter.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette vision ne tient pas face à un vrai client Apache Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client Pulsar sérieux doit gérer les producers, consumers, readers, topics partitionnés, consumers multi-topics, subscriptions par pattern, transactions, schémas, authentification, routage proxy, lookup broker, failover de cluster, reconnect, backoff, batching, chunking, ack grouping, suivi des messages non acquittés, negative acknowledgements, retry-letter et dead-letter flows, observabilité et une longue liste de Pulsar Improvement Proposals.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les bugs difficiles ne viennent pas seulement d'une commande mal encodée. Ils viennent souvent du temps et de l'ordre. Un broker tombe pendant qu'un publish est en vol. Une reconnexion arrive alors qu'un consumer a des acknowledgements en attente. Un refresh de token se produit pendant un reset de session. Un lookup via proxy pointe vers un nouveau broker alors que l'ancienne connexion se vide encore. Un topic migre et le client doit reconstruire assez d'état pour continuer sans prétendre que l'ancienne session existe toujours.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie qu'un client Pulsar n'est pas seulement un wrapper pratique autour d'une socket. Il fait partie du système distribué. Il possède un état qui doit rester cohérent pendant que le monde autour de lui change.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si cet état est caché dans des tâches runtime, des files de channels, des horloges implicites et des accidents de timing, alors le client devient plus difficile à raisonner précisément au moment où cette précision compte le plus. Magnetar part de l'hypothèse inverse : rendre l'état protocolaire explicite, le piloter à travers des frontières étroites et garder l'I/O à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">De l'écosystème Pulsar Rust à Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar vient d'une expérience concrète avec l'écosystème Pulsar Rust, notamment la maintenance et l'usage de <a href="https://github.com/streamnative/pulsar-rs">pulsar-rs</a>. Ce travail compte. Il a donné aux utilisateurs Rust un client Apache Pulsar et a créé le contexte pratique dans lequel l'étape suivante pouvait être évaluée.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar n'est pas une critique de ce qui existait avant lui. C'est une continuation du même écosystème, avec un point de départ architectural différent. Après avoir travaillé sur des usages Pulsar réels, la direction est devenue plus claire : un driver Pulsar Rust doit rendre la frontière protocole/runtime plus nette, rendre les comportements difficiles reproductibles, suivre la parité explicitement et faire de la testabilité une contrainte de conception.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar ne commence pas par le builder public. Il commence par le protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API utilisateur compte, et cette première release expose déjà une surface large. Mais pour un client distribué, la question plus profonde est ce qui se passe sous cette API lorsque le broker bouge, que la connexion tombe, que l'horloge avance, qu'un timeout se déclenche, qu'une subscription est reconstruite ou que la même trace est rejouée sous un autre runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Le coeur sans-io</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le coeur de Magnetar est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-proto">magnetar-proto</a>. C'est une machine d'état protocolaire synchrone. Elle n'a pas de socket. Elle ne dépend pas de Tokio. Elle ne lance pas de tâches. Elle n'utilise pas async. Elle ne lit pas l'horloge hôte sur le chemin chaud du protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sa forme suit la même idée générale qui a rendu <a href="https://github.com/quinn-rs/quinn/tree/main/quinn-proto">quinn-proto</a> influent dans le monde réseau Rust : injecter des octets, récupérer des octets à transmettre, récupérer des événements sémantiques et demander à la machine d'état quand son prochain timer expire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Conceptuellement, l'interface ressemble à ceci :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>&gt; connection.handle_bytes(now, bytes);

connection.poll_transmit(&amp;mut out);
connection.poll_event();
connection.poll_timeout();</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette petite forme est un grand choix d'architecture.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>handle_bytes permet à un moteur d'injecter les octets du wire dans la machine d'état. poll_transmit draine les frames sortantes. poll_event produit les événements sémantiques auxquels le runtime doit réagir : challenges d'authentification, résultats de lookup, checksum mismatch, signaux de reconnexion ou transitions protocolaire. poll_timeout permet au runtime de savoir quand réveiller la machine d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La machine d'état ne décide pas d'où viennent les octets. Elle ne sait pas si le réseau est un vrai stream TCP, un stream TLS, un pipe d'octets dans un simulateur ou un broker scripté dans un harnais différentiel. Elle ne décide pas non plus ce que "maintenant" veut dire. Le moteur lui passe le temps.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les traits publics de magnetar-proto suivent la même règle. Ce ne sont pas des services runtime cachés derrière des callbacks async. Ce sont de petits contrats protocolaires, placés aux endroits où la machine d'état a besoin d'une décision ou d'une transformation : <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/auth.rs">AuthProvider</a> produit les octets d'authentification, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/schema/mod.rs">Schema</a> définit l'encodage, le décodage, les données de schéma et les hooks de schéma résolu par le broker, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/crypto.rs">MessageEncryptor et MessageDecryptor</a> décrivent la crypto de payload sur des octets et de la metadata de message, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/service_url.rs">ServiceUrlProvider</a> expose l'URL de service courante pour le failover, et <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/health_probe.rs">HealthProbe</a> utilise un contrat de type poll au lieu d'attacher le crate protocolaire à un runtime async. Le motif est volontaire : le coeur protocolaire peut demander des faits, des octets ou un état de readiness, tandis que l'I/O, le cache, le refresh, les probes réseau et le scheduler restent à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette séparation n'est pas seulement une affaire de propreté. C'est ce qui rend le protocole testable sans broker, sans socket et sans runtime async. Un bug protocolaire peut être réduit à une fixture : injecter ces octets à cet instant, récupérer ces sorties, vérifier cet event stream et rejouer la même séquence.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un client Apache Pulsar, cela compte parce que le protocole wire ne se limite pas au chemin heureux. Il comprend la création de producers, la subscription de consumers, les acks, nacks, transactions, erreurs broker, redirects, challenges d'authentification, migrations de topics, markers de replicated subscriptions, metadata de schémas, batching, chunking et chemins de fermeture. Chacun de ces éléments porte de l'état. Chaque transition d'état est plus facile à raisonner lorsqu'elle n'est pas mélangée aux lectures de socket, au scheduling de tâches et aux wakeups spécifiques d'un runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'interdiction des channels comme contrainte d'architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar fait aussi un choix Rust async peu courant : les primitives de channels sont interdites dans le workspace.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'architecture directe d'un client réseau ressemble souvent à ceci : future producer vers channel, channel vers driver task, driver task vers channel, channel vers future consumer. Cela peut fonctionner, mais cela disperse l'état entre des files et des tâches. La backpressure devient implicite. Les sémantiques de fermeture dépendent de la bibliothèque de channel. Des futures abandonnées peuvent laisser des messages dans des endroits difficiles à inspecter. La question de debug devient : où est passé ce message ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar utilise un autre motif. L'état vit dans la machine d'état protocolaire et dans la connexion partagée détenue par le runtime. Les futures utilisateur enregistrent des wakers dans des slabs indexés par identifiants d'opération. Le driver possède la boucle d'I/O, injecte les octets dans la machine d'état, draine les frames sortantes et réveille les futures correspondantes lorsque les outcomes arrivent.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas une interdiction esthétique des channels. C'est une manière de garder la propriété de l'état explicite. Lorsque le driver reconstruit des producers après une reconnexion, lorsqu'un consumer attend un message, lorsqu'un ack outcome est livré ou lorsqu'une opération en attente échoue parce qu'une session a disparu, l'état pertinent est dans la machine d'état et peut y être inspecté.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce design a des compromis. Il met plus de pression sur la correction de la machine d'état. Il impose un ordre de locks précis. Il demande aux reviewers de comprendre l'enregistrement des wakers et les chemins de réveil. Mais il rend aussi le comportement beaucoup plus facile à simuler, rejouer et comparer entre runtimes.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Deux moteurs, une machine d'état</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar livre deux moteurs qui pilotent le même coeur protocolaire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur par défaut est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-tokio">magnetar-runtime-tokio</a>. C'est le chemin d'exécution de production : TCP, TLS via tokio-rustls, tâches driver, temps réel, vraies sockets et surface publique PulsarClient que la plupart des utilisateurs rencontreront en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le second moteur est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-moonpool">magnetar-runtime-moonpool</a>. Il pilote la même machine d'état magnetar-proto::Connection à travers des providers Moonpool. Au lieu d'inscrire le runtime en dur, Moonpool expose des traits de providers pour le réseau, le temps, le spawning de tâches, l'aléa et le stockage. Avec un bundle de providers proche de la production, le moteur peut exécuter de vraies I/O. Avec des providers de simulation, ces mêmes catégories peuvent être virtualisées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est là que la simulation déterministe devient pratique. Le client peut être piloté dans un monde où le temps avance sous contrôle, où les livraisons réseau peuvent être réordonnées ou interrompues, où les tâches s'exécutent sous un scheduler déterministe, où l'aléa est seedé et où les pannes peuvent être rejouées depuis la même seed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas un mock. Un mock remplace généralement un composant par un comportement simplifié. C'est utile pour beaucoup de tests unitaires, mais ce n'est pas la même chose que d'exercer un vrai client dans des interleavings difficiles.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas non plus un test end-to-end classique. Un e2e exécute le vrai système, ce qui est indispensable, mais il utilise souvent du temps réel, un vrai réseau et des pannes difficiles à reproduire une fois le timing passé.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool occupe un autre espace. Il garde le code proche du chemin réel d'exécution tout en virtualisant les providers qui rendent le comportement distribué difficile à reproduire. Le but n'est pas d'éviter les e2e. Le but est d'ajouter un régime où les pannes ne sont plus des anecdotes. Elles deviennent des seeds.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur Moonpool de Magnetar utilise la même machine d'état protocolaire que le moteur Tokio. Le chemin TLS est lui aussi piloté de façon à préserver la frontière de simulation : au lieu de s'appuyer sur tokio-rustls, le moteur Moonpool pilote directement rustls::ClientConnection au-dessus du pipe d'octets. Cela maintient les handshakes TLS sous le même contrôle déterministe que le reste du réseau simulé.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Tests différentiels : faire converger les moteurs</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Deux moteurs ne sont utiles que s'ils ne deviennent pas silencieusement deux clients différents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar inclut donc un harnais différentiel. Il exécute une trace, par exemple connect, open producer, send, subscribe, receive, ack, seek et close, contre les moteurs Tokio et Moonpool, puis compare les event streams visibles par l'utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que le moteur Moonpool sert à trouver des bugs difficiles à exposer avec du temps réel et de vraies sockets. Pour que cette recherche ait du sens, le moteur simulé doit rester aligné avec le moteur de production à la frontière utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si Tokio et Moonpool divergent, le simulateur devient moins fiable. Si le harnais différentiel les maintient alignés, alors une seed rouge dans le monde simulé pointe beaucoup plus probablement vers une propriété réelle du client, et non vers une implémentation séparée réservée aux tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi pour cela que la politique de validation de Magnetar est stricte sur la couverture cross-runtime. Les changements comportementaux doivent exercer la couche sans-io, le runtime Tokio, le runtime Moonpool, l'équivalence différentielle et la surface e2e lorsque c'est applicable. C'est plus de travail qu'un seul test unitaire. C'est aussi le coût pour faire de la simulation déterministe un vrai outil d'ingénierie, pas une expérience annexe.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La parité Java comme contrat de crédibilité</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La simulation ne remplace pas la largeur fonctionnelle. Elle rend cette largeur moins fragile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apache Pulsar possède un <a href="https://pulsar.apache.org/docs/">client Java</a> mature, et pour beaucoup d'utilisateurs ce client définit ce que signifie "un client Pulsar". Le produce/consume de base ne suffit pas. Un client crédible doit couvrir les comportements sur lesquels les applications s'appuient : batching, compression, transactions, schémas, topics partitionnés, consumers multi-topics et par pattern, retries, dead-letter flows, providers d'authentification, support proxy, failover, opérations admin et PIPs qui structurent les usages modernes de Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar suit la parité avec le client Java comme un contrat public. Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> porte la matrice de parité et le statut moteur par moteur. L'article n'a pas besoin de recopier cette matrice, mais son existence est importante. Elle donne aux utilisateurs un moyen d'évaluer le projet comme client Pulsar, et non comme une expérience étroite autour d'un seul chemin heureux.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi la première release publique de Magnetar est plus large qu'une démo minimale. Elle inclut la fondation protocolaire, la façade publique, les moteurs runtime, le support admin, les providers d'authentification, la crypto de messages, le travail CLI, les hooks d'observabilité et une liste croissante de surfaces PIP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La raison de suivre la parité est simple : les utilisateurs ne choisissent pas une bibliothèque cliente uniquement parce que son architecture interne est élégante. Ils la choisissent parce qu'elle peut représenter le système qu'ils exécutent réellement. L'architecture rend cette surface maintenable. La parité la rend utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Au-delà de la production et de la consommation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'expression "client Pulsar" peut masquer une large surface fonctionnelle. Vus de l'extérieur, les premiers exemples paraissent généralement modestes : construire un client, créer un producer, envoyer un payload, souscrire avec un consumer, recevoir un message, l'acquitter. Ces exemples sont utiles parce qu'ils montrent le point d'entrée. Ils ne suffisent pas à évaluer le client.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les vraies applications Pulsar dépendent de comportements qui n'apparaissent qu'une fois la première démo fonctionnelle. Un producer peut avoir besoin de batching, de compression, de chunking, de modes d'accès, de sequence ids, de timeouts d'envoi, de propriétés par message, de transactions, d'interceptors et de statistiques de latence. Un consumer peut avoir besoin de batch receive, d'acquittements cumulatifs, d'acquittements par index de batch, de nack backoff, de gestion des timeouts d'ack, de retry topics, de dead-letter topics, de seek, de pause/resume, de modes de souscription et de comportements par partition. Les applications avec des schémas stricts ont besoin d'Avro, de JSON, de Protobuf, de Protobuf-native, de KeyValue, de schémas primitifs et de la sémantique de résolution de schéma côté broker. Les déploiements avec des exigences de sécurité ont besoin d'authentification par token, de mTLS, d'OAuth2, de SASL, de Kerberos/GSSAPI, d'Athenz, de choix de provider TLS, et d'un moyen de raisonner sur le comportement de la crypto sans forcer chaque build à embarquer tous les providers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces fonctionnalités ne sont pas des cases à cocher indépendantes. Elles interagissent. Le batching interagit avec la compression et les timeouts d'envoi. Le chunking interagit avec les sequence ids et la redélivrance. Les transactions interagissent avec les acquittements. La reconnexion interagit avec les producers, les consumers, les lookups, le routage proxy et le failover. L'observabilité doit décrire le comportement sans laisser fuiter de secrets ni noyer les opérateurs en période de churn.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail fonctionnel et le travail d'architecture de Magnetar sont liés. Plus la surface devient complète, plus il est important que l'état protocolaire soit explicite et que la frontière avec le runtime reste étroite. Un client large bâti sur un état accidentel devient plus difficile à maintenir à mesure qu'il devient plus utile. Un client large bâti sur un état rejouable donne aux mainteneurs une meilleure chance d'empêcher la croissance fonctionnelle de se transformer en comportement caché.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La validation comme architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La stratégie de test de Magnetar est volontairement stratifiée, parce que chaque couche attrape une classe différente de bugs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La couche sans-io permet de tester le comportement protocolaire sans sockets ni tâches async. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">documentation de test du projet</a> mentionne aujourd'hui plus de 270 tests unitaires dans magnetar-proto. Ces tests exercent directement la machine d'état : octets en entrée, événements en sortie, buffers de transmission en sortie, transitions d'état vérifiées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'intégration runtime exercent la colle que les tests purement protocolaires ne peuvent pas couvrir. Les moteurs Tokio et Moonpool ont chacun leur surface d'intégration, et le projet impose une parité runtime afin qu'un moteur ne prenne pas silencieusement du retard sur l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le pack de chaos déterministe cible les ordonnancements de panne qui ont motivé l'architecture : reconnect, failover, timers en horloge virtuelle, ordre des handshakes TLS, publishes en vol, migration de broker et comportements réseau adversariaux. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> décrit un sweep Moonpool quotidien avec 128 seeds aléatoires fraîchement générées en parallèle. Le chiffre compte moins que ce qu'il représente : le client est poussé dans des ordonnancements qu'un humain n'écrirait pas à la main.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'équivalence différentielle comparent les deux mondes runtime. Ils posent une question directe : si la même trace est exécutée dans Tokio et Moonpool, l'utilisateur observe-t-il le même comportement ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests end-to-end restent nécessaires. Ils gardent Magnetar honnête face à un vrai broker Apache Pulsar. La simulation rend des pannes reproductibles, mais elle ne remplace pas la compatibilité avec le système que les utilisateurs déploient.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ensemble, ces couches ne sont pas une cérémonie. Elles font partie de l'architecture. Le but n'est pas d'accumuler de grands nombres de tests. Le but est d'appliquer la pression de validation exactement là où les clients distribués échouent : état protocolaire, frontières runtime, logique de reconnexion, timing, équivalence et comportement face à un vrai broker.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que la reproductibilité change concrètement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La valeur pratique de la simulation déterministe n'est pas seulement de rendre les tests plus sophistiqués. Elle change la boucle de debug.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsqu'un test end-to-end traditionnel échoue à cause du timing, la première question est souvent de savoir si l'échec est reproductible. S'il ne l'est pas, on ajoute des sleeps, des logs, des timeouts plus larges ou des boucles de retry. Certaines de ces modifications sont utiles. Beaucoup ne font que déplacer la panne ailleurs. La panne reste une histoire : "on l'a vue une fois en CI".</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avec une simulation déterministe, la panne doit devenir un artefact. Cet artefact est une seed, une trace et une transition d'état rejouable. La question passe de "peut-on la refaire apparaître ?" à "quel invariant cet ordonnancement a-t-il violé ?"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette différence compte pour une bibliothèque cliente. Les bugs de client se trouvent souvent à la frontière entre le code utilisateur et le broker. Ils sont faciles à attribuer au mauvais endroit. Un publish peut échouer parce que le broker a fermé la connexion, parce que le client a perdu un outcome, parce que le chemin de reconnexion a reconstruit le producer trop tard, parce qu'un ack a réveillé le mauvais waiter, parce qu'un timeout a frappé un état de session périmé, ou parce que la tâche runtime est morte après que le protocole a déjà changé d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si tout ce comportement est dispersé entre des tâches, des channels, des timers et des sockets, un rapport de panne est difficile à réduire. Si la machine d'état protocolaire est explicite, si la frontière runtime est étroite et si la même séquence peut être rejouée avec des providers contrôlés, le rapport devient beaucoup plus petit : cette seed, cette trace, cet ordre d'événements, cet invariant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar traite la reproductibilité comme une partie du design du client. Le but n'est pas seulement de trouver plus de bugs. Le but est que les bugs trouvés coûtent moins cher à comprendre et soient plus sûrs à corriger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela change aussi la revue de code. Un reviewer peut demander si un comportement est couvert à la bonne couche. Est-ce une transition protocolaire pure ? Alors le test sans-io doit injecter des octets et vérifier des événements. Est-ce de la colle runtime ? Alors Tokio et Moonpool doivent avoir une couverture équivalente. Est-ce un comportement observable partagé par les deux moteurs ? Alors le harnais différentiel doit comparer les event streams. Est-ce de la compatibilité broker ? Alors un e2e doit toucher un vrai broker Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces questions sont plus précises que "a-t-on ajouté des tests ?" Elles relient le test au modèle de panne.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Par où commencer la lecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour les ingénieurs qui découvrent Magnetar, le meilleur point d'entrée n'est pas un fichier unique. C'est la relation entre les documents et le code.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> donne la surface publique : ce que le client expose, quelles fonctionnalités sont implémentées, comment la matrice de parité Java est suivie, quels PIPs sont supportés et comment les deux moteurs sont positionnés. C'est le contrat utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> explique la forme située sous ce contrat. Il montre la topologie de crates, le sens des dépendances, la frontière sans-io, la boucle driver, le modèle d'événements, les chemins producer et consumer, les moteurs runtime, les sites TLS, les schémas, la couverture PIP et la stratégie de validation. C'est la carte du système.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">série d'ADR</a> explique pourquoi le système a cette forme. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">ADR-0004</a> documente la séparation sans-io. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0003-no-channels-rule.md">ADR-0003</a> documente l'interdiction des channels. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0011-clock-injection-sans-io.md">ADR-0011</a> documente l'injection d'horloge. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">ADR-0010</a> documente la décision de parité Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0019-engine-scope-and-moonpool-parity.md">ADR-0019</a> documente la relation entre le moteur de production Tokio et le moteur Moonpool par rapport à cet objectif de parité. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">ADR-0024</a> documente la politique de test cross-runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que Magnetar n'est volontairement pas seulement un dépôt de code. C'est un ensemble de décisions d'ingénierie avec une trace publique. Si vous n'êtes pas d'accord avec le design, les ADR donnent la bonne surface de discussion. Si vous voulez contribuer une fonctionnalité, la matrice de parité et la politique de validation indiquent ce que "terminé" veut dire. Si vous voulez évaluer le travail de simulation, la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> et le harnais différentiel montrent comment le même coeur protocolaire est piloté dans plusieurs mondes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette première release doit donc se lire de deux manières. Comme utilisateur Pulsar, regardez la surface cliente et la matrice de parité. Comme ingénieur infrastructure Rust, regardez la frontière de machine d'état et la stratégie de simulation. Ce qui rend Magnetar intéressant, c'est que ces deux lectures sont censées se renforcer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que donne la première release publique</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Cette première release publique est un point d'entrée technique. Elle s'adresse aux ingénieurs qui veulent essayer Magnetar, lire l'architecture, inspecter les ADR, comparer le comportement avec les clients Pulsar existants et contribuer à structurer l'écosystème Pulsar Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API cliente de haut niveau commence par une forme attendue :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>let client = PulsarClient::builder()
    .service_url("pulsar://localhost:6650")
    .build()
    .await?;

let producer = client
    .producer("persistent://public/default/orders")
    .create()
    .await?;</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette API est importante, parce que le client doit être utilisable. Mais la release est aussi une invitation à inspecter les couches inférieures. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> pour la matrice fonctionnelle. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> pour le design sans-io. Lire les <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">ADR</a> pour les décisions derrière l'interdiction des channels, les moteurs remplaçables, l'injection d'horloge, la parité Java, la parité Moonpool, les choix de providers TLS et la validation cross-runtime. Lire la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> si la simulation déterministe appliquée à un vrai client réseau vous intéresse.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le point important pour cet article est la direction : Magnetar est public pour que les ingénieurs puissent évaluer à la fois la surface cliente et le modèle d'ingénierie qui la porte.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Vous pouvez consulter la première release publique de Magnetar <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.0.0">v1.0.0</a>, ainsi que la dernière release à ce jour, la version <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.2.0">v1.2.0</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi cela dépasse Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar est un client Apache Pulsar. C'est aussi un exemple concret de la manière dont nous voulons construire davantage de logiciel d'infrastructure en Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les systèmes distribués échouent par transitions d'état. Certaines de ces transitions sont évidentes et faciles à tester. Beaucoup ne le sont pas. Elles apparaissent lorsque le temps avance au mauvais endroit, lorsqu'un retry chevauche un chemin de fermeture, lorsqu'un broker coupe une connexion après avoir accepté une partie de la session, lorsqu'un callback est enregistré juste après une notification, ou lorsqu'un chemin de reconnexion reconstruit un handle mais pas un autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>On peut essayer de traquer ces bugs après coup. C'est parfois inévitable. Mais l'architecture peut rendre cette traque plus facile ou plus difficile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client avec un coeur protocolaire pur, des événements explicites, du temps injecté, une I/O remplaçable, des seeds déterministes et une comparaison cross-runtime donne de meilleurs outils aux ingénieurs. Il permet de réduire une panne à une trace. Il permet de rejouer cette trace. Il permet de demander si une panne simulée correspond au runtime de production. Il permet d'ajouter un invariant là où une dérive silencieuse de l'état pouvait se cacher.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la direction prise par Magnetar. Rendre le protocole explicite. Rendre le runtime remplaçable. Rendre les pannes reproductibles. Faire de la correction quelque chose que le code doit démontrer en continu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Merci à Pierre Zemb pour Moonpool et pour cette direction de simulation déterministe en Rust, ainsi qu'aux contributeurs et mainteneurs de l'écosystème Pulsar Rust dont le travail a rendu l'étape suivante possible.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est open source. Le code, les notes d'architecture, les ADR et la documentation vivent sur <a href="https://github.com/CleverCloud/magnetar">github.com/CleverCloud/magnetar</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Magnetar</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Dépôt Magnetar</strong>. Dépôt public du client Apache Pulsar Rust. <a href="https://github.com/CleverCloud/magnetar">https://github.com/CleverCloud/magnetar</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>README Magnetar</strong>. Surface publique, matrice de parité Java, PIPs supportés, couverture par moteur et statut. <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">https://github.com/CleverCloud/magnetar/blob/main/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Architecture Magnetar</strong>. Rationale sans-io, topologie de crates, driver loop, machine d'état protocolaire et tests. <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Index de documentation Magnetar</strong>. Moteur Moonpool, testing, CLI, observabilité, logging, features PIP. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/README.md">https://github.com/CleverCloud/magnetar/blob/main/docs/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation du moteur Moonpool</strong>. Moteur de simulation déterministe, chaos pack, harnais différentiel, modèle de providers. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test</strong>. Catégories de tests et commandes de validation. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0004</strong>. magnetar-proto sans-io et moteurs d'I/O remplaçables. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0010</strong>. Parité complète avec le client Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0024</strong>. Politique de tests et couverture cross-runtime. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Écosystème</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>pulsar-rs</strong>. Client Apache Pulsar Rust existant. <a href="https://github.com/streamnative/pulsar-rs">https://github.com/streamnative/pulsar-rs</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Apache Pulsar</strong>. Plateforme distribuée de messaging et streaming. <a href="https://pulsar.apache.org/">https://pulsar.apache.org/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Client Java Apache Pulsar</strong>. Surface de référence pour de nombreux utilisateurs Pulsar. <a href="https://pulsar.apache.org/docs/">https://pulsar.apache.org/docs/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Simulation déterministe</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie centré sur les assertions. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Simulation déterministe pour systèmes Rust, développée par Pierre Zemb. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Crate du moteur de simulation Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></description>
										<content:encoded><![CDATA[<p><img width="2400" height="1065" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.15 Clever Cloud Bannière Blog Magnetar FR" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png 2400w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1368x607.png 1368w" sizes="(max-width: 2400px) 100vw, 2400px" /></p><!-- wp:paragraph -->
<p><a href="https://apple.github.io/foundationdb/testing.html">FoundationDB</a> a rendu cette idée célèbre. Au lieu de s'appuyer seulement sur des tests unitaires et des tests end-to-end sur un vrai cluster, le projet exécute des workloads distribués dans un monde simulé, où le temps, les fautes réseau, les pannes de processus et les décisions d'ordonnancement peuvent être explorés puis rejoués à partir d'une seed. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">TigerBeetle</a> pousse une discipline complémentaire : rendre les invariants explicites dans le code, vérifier en continu la forme de l'état et transformer une corruption silencieuse en panne locale et bruyante.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous appliquons cette direction à des logiciels d'infrastructure en Rust. <a href="https://github.com/PierreZ/moonpool">Moonpool</a>, développé par Pierre Zemb, donne aux systèmes Rust un environnement de simulation déterministe où le temps, le réseau, les tâches, l'aléa et le stockage peuvent être virtualisés derrière des traits de providers. <a href="https://github.com/CleverCloud/magnetar">Magnetar</a> est l'application de cette approche à un client <a href="https://pulsar.apache.org/">Apache Pulsar</a>. C’est d’ailleurs, l’approche que nous prenons au sein de notre reverse proxy <a href="https://www.clever.cloud/fr/blog/entreprise/2026/07/01/sozu-2-1-0-load-balancing-udp-edge-programmable/">Sōzu</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est un driver Apache Pulsar écrit en Rust, depuis zéro. Il repose sur un coeur protocolaire sans-io, un moteur de production Tokio et un moteur Moonpool pour la simulation déterministe. Cette première release publique s'adresse aux ingénieurs qui veulent essayer Magnetar, évaluer son architecture, comparer son comportement avec les clients Pulsar existants et contribuer à structurer un écosystème Pulsar Rust plus solide.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'objectif n'est pas seulement d'exposer une API Rust autour de Pulsar. L'objectif est de construire un client dont les comportements difficiles peuvent être inspectés, rejoués et forcés à échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Un client Pulsar fait partie du système distribué</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>On pourrait être tenté de considérer une bibliothèque cliente comme la partie simple d'un système distribué. Le broker porterait la réplication, le stockage, l'ownership et la coordination. Le client se contenterait de se connecter, d'envoyer des messages, d'en recevoir et de les acquitter.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette vision ne tient pas face à un vrai client Apache Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client Pulsar sérieux doit gérer les producers, consumers, readers, topics partitionnés, consumers multi-topics, subscriptions par pattern, transactions, schémas, authentification, routage proxy, lookup broker, failover de cluster, reconnect, backoff, batching, chunking, ack grouping, suivi des messages non acquittés, negative acknowledgements, retry-letter et dead-letter flows, observabilité et une longue liste de Pulsar Improvement Proposals.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les bugs difficiles ne viennent pas seulement d'une commande mal encodée. Ils viennent souvent du temps et de l'ordre. Un broker tombe pendant qu'un publish est en vol. Une reconnexion arrive alors qu'un consumer a des acknowledgements en attente. Un refresh de token se produit pendant un reset de session. Un lookup via proxy pointe vers un nouveau broker alors que l'ancienne connexion se vide encore. Un topic migre et le client doit reconstruire assez d'état pour continuer sans prétendre que l'ancienne session existe toujours.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie qu'un client Pulsar n'est pas seulement un wrapper pratique autour d'une socket. Il fait partie du système distribué. Il possède un état qui doit rester cohérent pendant que le monde autour de lui change.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si cet état est caché dans des tâches runtime, des files de channels, des horloges implicites et des accidents de timing, alors le client devient plus difficile à raisonner précisément au moment où cette précision compte le plus. Magnetar part de l'hypothèse inverse : rendre l'état protocolaire explicite, le piloter à travers des frontières étroites et garder l'I/O à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">De l'écosystème Pulsar Rust à Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar vient d'une expérience concrète avec l'écosystème Pulsar Rust, notamment la maintenance et l'usage de <a href="https://github.com/streamnative/pulsar-rs">pulsar-rs</a>. Ce travail compte. Il a donné aux utilisateurs Rust un client Apache Pulsar et a créé le contexte pratique dans lequel l'étape suivante pouvait être évaluée.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar n'est pas une critique de ce qui existait avant lui. C'est une continuation du même écosystème, avec un point de départ architectural différent. Après avoir travaillé sur des usages Pulsar réels, la direction est devenue plus claire : un driver Pulsar Rust doit rendre la frontière protocole/runtime plus nette, rendre les comportements difficiles reproductibles, suivre la parité explicitement et faire de la testabilité une contrainte de conception.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar ne commence pas par le builder public. Il commence par le protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API utilisateur compte, et cette première release expose déjà une surface large. Mais pour un client distribué, la question plus profonde est ce qui se passe sous cette API lorsque le broker bouge, que la connexion tombe, que l'horloge avance, qu'un timeout se déclenche, qu'une subscription est reconstruite ou que la même trace est rejouée sous un autre runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Le coeur sans-io</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le coeur de Magnetar est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-proto">magnetar-proto</a>. C'est une machine d'état protocolaire synchrone. Elle n'a pas de socket. Elle ne dépend pas de Tokio. Elle ne lance pas de tâches. Elle n'utilise pas async. Elle ne lit pas l'horloge hôte sur le chemin chaud du protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sa forme suit la même idée générale qui a rendu <a href="https://github.com/quinn-rs/quinn/tree/main/quinn-proto">quinn-proto</a> influent dans le monde réseau Rust : injecter des octets, récupérer des octets à transmettre, récupérer des événements sémantiques et demander à la machine d'état quand son prochain timer expire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Conceptuellement, l'interface ressemble à ceci :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>&gt; connection.handle_bytes(now, bytes);

connection.poll_transmit(&amp;mut out);
connection.poll_event();
connection.poll_timeout();</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette petite forme est un grand choix d'architecture.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>handle_bytes permet à un moteur d'injecter les octets du wire dans la machine d'état. poll_transmit draine les frames sortantes. poll_event produit les événements sémantiques auxquels le runtime doit réagir : challenges d'authentification, résultats de lookup, checksum mismatch, signaux de reconnexion ou transitions protocolaire. poll_timeout permet au runtime de savoir quand réveiller la machine d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La machine d'état ne décide pas d'où viennent les octets. Elle ne sait pas si le réseau est un vrai stream TCP, un stream TLS, un pipe d'octets dans un simulateur ou un broker scripté dans un harnais différentiel. Elle ne décide pas non plus ce que "maintenant" veut dire. Le moteur lui passe le temps.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les traits publics de magnetar-proto suivent la même règle. Ce ne sont pas des services runtime cachés derrière des callbacks async. Ce sont de petits contrats protocolaires, placés aux endroits où la machine d'état a besoin d'une décision ou d'une transformation : <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/auth.rs">AuthProvider</a> produit les octets d'authentification, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/schema/mod.rs">Schema</a> définit l'encodage, le décodage, les données de schéma et les hooks de schéma résolu par le broker, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/crypto.rs">MessageEncryptor et MessageDecryptor</a> décrivent la crypto de payload sur des octets et de la metadata de message, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/service_url.rs">ServiceUrlProvider</a> expose l'URL de service courante pour le failover, et <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/health_probe.rs">HealthProbe</a> utilise un contrat de type poll au lieu d'attacher le crate protocolaire à un runtime async. Le motif est volontaire : le coeur protocolaire peut demander des faits, des octets ou un état de readiness, tandis que l'I/O, le cache, le refresh, les probes réseau et le scheduler restent à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette séparation n'est pas seulement une affaire de propreté. C'est ce qui rend le protocole testable sans broker, sans socket et sans runtime async. Un bug protocolaire peut être réduit à une fixture : injecter ces octets à cet instant, récupérer ces sorties, vérifier cet event stream et rejouer la même séquence.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un client Apache Pulsar, cela compte parce que le protocole wire ne se limite pas au chemin heureux. Il comprend la création de producers, la subscription de consumers, les acks, nacks, transactions, erreurs broker, redirects, challenges d'authentification, migrations de topics, markers de replicated subscriptions, metadata de schémas, batching, chunking et chemins de fermeture. Chacun de ces éléments porte de l'état. Chaque transition d'état est plus facile à raisonner lorsqu'elle n'est pas mélangée aux lectures de socket, au scheduling de tâches et aux wakeups spécifiques d'un runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'interdiction des channels comme contrainte d'architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar fait aussi un choix Rust async peu courant : les primitives de channels sont interdites dans le workspace.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'architecture directe d'un client réseau ressemble souvent à ceci : future producer vers channel, channel vers driver task, driver task vers channel, channel vers future consumer. Cela peut fonctionner, mais cela disperse l'état entre des files et des tâches. La backpressure devient implicite. Les sémantiques de fermeture dépendent de la bibliothèque de channel. Des futures abandonnées peuvent laisser des messages dans des endroits difficiles à inspecter. La question de debug devient : où est passé ce message ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar utilise un autre motif. L'état vit dans la machine d'état protocolaire et dans la connexion partagée détenue par le runtime. Les futures utilisateur enregistrent des wakers dans des slabs indexés par identifiants d'opération. Le driver possède la boucle d'I/O, injecte les octets dans la machine d'état, draine les frames sortantes et réveille les futures correspondantes lorsque les outcomes arrivent.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas une interdiction esthétique des channels. C'est une manière de garder la propriété de l'état explicite. Lorsque le driver reconstruit des producers après une reconnexion, lorsqu'un consumer attend un message, lorsqu'un ack outcome est livré ou lorsqu'une opération en attente échoue parce qu'une session a disparu, l'état pertinent est dans la machine d'état et peut y être inspecté.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce design a des compromis. Il met plus de pression sur la correction de la machine d'état. Il impose un ordre de locks précis. Il demande aux reviewers de comprendre l'enregistrement des wakers et les chemins de réveil. Mais il rend aussi le comportement beaucoup plus facile à simuler, rejouer et comparer entre runtimes.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Deux moteurs, une machine d'état</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar livre deux moteurs qui pilotent le même coeur protocolaire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur par défaut est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-tokio">magnetar-runtime-tokio</a>. C'est le chemin d'exécution de production : TCP, TLS via tokio-rustls, tâches driver, temps réel, vraies sockets et surface publique PulsarClient que la plupart des utilisateurs rencontreront en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le second moteur est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-moonpool">magnetar-runtime-moonpool</a>. Il pilote la même machine d'état magnetar-proto::Connection à travers des providers Moonpool. Au lieu d'inscrire le runtime en dur, Moonpool expose des traits de providers pour le réseau, le temps, le spawning de tâches, l'aléa et le stockage. Avec un bundle de providers proche de la production, le moteur peut exécuter de vraies I/O. Avec des providers de simulation, ces mêmes catégories peuvent être virtualisées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est là que la simulation déterministe devient pratique. Le client peut être piloté dans un monde où le temps avance sous contrôle, où les livraisons réseau peuvent être réordonnées ou interrompues, où les tâches s'exécutent sous un scheduler déterministe, où l'aléa est seedé et où les pannes peuvent être rejouées depuis la même seed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas un mock. Un mock remplace généralement un composant par un comportement simplifié. C'est utile pour beaucoup de tests unitaires, mais ce n'est pas la même chose que d'exercer un vrai client dans des interleavings difficiles.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas non plus un test end-to-end classique. Un e2e exécute le vrai système, ce qui est indispensable, mais il utilise souvent du temps réel, un vrai réseau et des pannes difficiles à reproduire une fois le timing passé.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool occupe un autre espace. Il garde le code proche du chemin réel d'exécution tout en virtualisant les providers qui rendent le comportement distribué difficile à reproduire. Le but n'est pas d'éviter les e2e. Le but est d'ajouter un régime où les pannes ne sont plus des anecdotes. Elles deviennent des seeds.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur Moonpool de Magnetar utilise la même machine d'état protocolaire que le moteur Tokio. Le chemin TLS est lui aussi piloté de façon à préserver la frontière de simulation : au lieu de s'appuyer sur tokio-rustls, le moteur Moonpool pilote directement rustls::ClientConnection au-dessus du pipe d'octets. Cela maintient les handshakes TLS sous le même contrôle déterministe que le reste du réseau simulé.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Tests différentiels : faire converger les moteurs</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Deux moteurs ne sont utiles que s'ils ne deviennent pas silencieusement deux clients différents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar inclut donc un harnais différentiel. Il exécute une trace, par exemple connect, open producer, send, subscribe, receive, ack, seek et close, contre les moteurs Tokio et Moonpool, puis compare les event streams visibles par l'utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que le moteur Moonpool sert à trouver des bugs difficiles à exposer avec du temps réel et de vraies sockets. Pour que cette recherche ait du sens, le moteur simulé doit rester aligné avec le moteur de production à la frontière utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si Tokio et Moonpool divergent, le simulateur devient moins fiable. Si le harnais différentiel les maintient alignés, alors une seed rouge dans le monde simulé pointe beaucoup plus probablement vers une propriété réelle du client, et non vers une implémentation séparée réservée aux tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi pour cela que la politique de validation de Magnetar est stricte sur la couverture cross-runtime. Les changements comportementaux doivent exercer la couche sans-io, le runtime Tokio, le runtime Moonpool, l'équivalence différentielle et la surface e2e lorsque c'est applicable. C'est plus de travail qu'un seul test unitaire. C'est aussi le coût pour faire de la simulation déterministe un vrai outil d'ingénierie, pas une expérience annexe.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La parité Java comme contrat de crédibilité</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La simulation ne remplace pas la largeur fonctionnelle. Elle rend cette largeur moins fragile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apache Pulsar possède un <a href="https://pulsar.apache.org/docs/">client Java</a> mature, et pour beaucoup d'utilisateurs ce client définit ce que signifie "un client Pulsar". Le produce/consume de base ne suffit pas. Un client crédible doit couvrir les comportements sur lesquels les applications s'appuient : batching, compression, transactions, schémas, topics partitionnés, consumers multi-topics et par pattern, retries, dead-letter flows, providers d'authentification, support proxy, failover, opérations admin et PIPs qui structurent les usages modernes de Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar suit la parité avec le client Java comme un contrat public. Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> porte la matrice de parité et le statut moteur par moteur. L'article n'a pas besoin de recopier cette matrice, mais son existence est importante. Elle donne aux utilisateurs un moyen d'évaluer le projet comme client Pulsar, et non comme une expérience étroite autour d'un seul chemin heureux.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi la première release publique de Magnetar est plus large qu'une démo minimale. Elle inclut la fondation protocolaire, la façade publique, les moteurs runtime, le support admin, les providers d'authentification, la crypto de messages, le travail CLI, les hooks d'observabilité et une liste croissante de surfaces PIP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La raison de suivre la parité est simple : les utilisateurs ne choisissent pas une bibliothèque cliente uniquement parce que son architecture interne est élégante. Ils la choisissent parce qu'elle peut représenter le système qu'ils exécutent réellement. L'architecture rend cette surface maintenable. La parité la rend utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Au-delà de la production et de la consommation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'expression "client Pulsar" peut masquer une large surface fonctionnelle. Vus de l'extérieur, les premiers exemples paraissent généralement modestes : construire un client, créer un producer, envoyer un payload, souscrire avec un consumer, recevoir un message, l'acquitter. Ces exemples sont utiles parce qu'ils montrent le point d'entrée. Ils ne suffisent pas à évaluer le client.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les vraies applications Pulsar dépendent de comportements qui n'apparaissent qu'une fois la première démo fonctionnelle. Un producer peut avoir besoin de batching, de compression, de chunking, de modes d'accès, de sequence ids, de timeouts d'envoi, de propriétés par message, de transactions, d'interceptors et de statistiques de latence. Un consumer peut avoir besoin de batch receive, d'acquittements cumulatifs, d'acquittements par index de batch, de nack backoff, de gestion des timeouts d'ack, de retry topics, de dead-letter topics, de seek, de pause/resume, de modes de souscription et de comportements par partition. Les applications avec des schémas stricts ont besoin d'Avro, de JSON, de Protobuf, de Protobuf-native, de KeyValue, de schémas primitifs et de la sémantique de résolution de schéma côté broker. Les déploiements avec des exigences de sécurité ont besoin d'authentification par token, de mTLS, d'OAuth2, de SASL, de Kerberos/GSSAPI, d'Athenz, de choix de provider TLS, et d'un moyen de raisonner sur le comportement de la crypto sans forcer chaque build à embarquer tous les providers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces fonctionnalités ne sont pas des cases à cocher indépendantes. Elles interagissent. Le batching interagit avec la compression et les timeouts d'envoi. Le chunking interagit avec les sequence ids et la redélivrance. Les transactions interagissent avec les acquittements. La reconnexion interagit avec les producers, les consumers, les lookups, le routage proxy et le failover. L'observabilité doit décrire le comportement sans laisser fuiter de secrets ni noyer les opérateurs en période de churn.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail fonctionnel et le travail d'architecture de Magnetar sont liés. Plus la surface devient complète, plus il est important que l'état protocolaire soit explicite et que la frontière avec le runtime reste étroite. Un client large bâti sur un état accidentel devient plus difficile à maintenir à mesure qu'il devient plus utile. Un client large bâti sur un état rejouable donne aux mainteneurs une meilleure chance d'empêcher la croissance fonctionnelle de se transformer en comportement caché.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La validation comme architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La stratégie de test de Magnetar est volontairement stratifiée, parce que chaque couche attrape une classe différente de bugs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La couche sans-io permet de tester le comportement protocolaire sans sockets ni tâches async. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">documentation de test du projet</a> mentionne aujourd'hui plus de 270 tests unitaires dans magnetar-proto. Ces tests exercent directement la machine d'état : octets en entrée, événements en sortie, buffers de transmission en sortie, transitions d'état vérifiées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'intégration runtime exercent la colle que les tests purement protocolaires ne peuvent pas couvrir. Les moteurs Tokio et Moonpool ont chacun leur surface d'intégration, et le projet impose une parité runtime afin qu'un moteur ne prenne pas silencieusement du retard sur l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le pack de chaos déterministe cible les ordonnancements de panne qui ont motivé l'architecture : reconnect, failover, timers en horloge virtuelle, ordre des handshakes TLS, publishes en vol, migration de broker et comportements réseau adversariaux. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> décrit un sweep Moonpool quotidien avec 128 seeds aléatoires fraîchement générées en parallèle. Le chiffre compte moins que ce qu'il représente : le client est poussé dans des ordonnancements qu'un humain n'écrirait pas à la main.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'équivalence différentielle comparent les deux mondes runtime. Ils posent une question directe : si la même trace est exécutée dans Tokio et Moonpool, l'utilisateur observe-t-il le même comportement ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests end-to-end restent nécessaires. Ils gardent Magnetar honnête face à un vrai broker Apache Pulsar. La simulation rend des pannes reproductibles, mais elle ne remplace pas la compatibilité avec le système que les utilisateurs déploient.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ensemble, ces couches ne sont pas une cérémonie. Elles font partie de l'architecture. Le but n'est pas d'accumuler de grands nombres de tests. Le but est d'appliquer la pression de validation exactement là où les clients distribués échouent : état protocolaire, frontières runtime, logique de reconnexion, timing, équivalence et comportement face à un vrai broker.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que la reproductibilité change concrètement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La valeur pratique de la simulation déterministe n'est pas seulement de rendre les tests plus sophistiqués. Elle change la boucle de debug.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsqu'un test end-to-end traditionnel échoue à cause du timing, la première question est souvent de savoir si l'échec est reproductible. S'il ne l'est pas, on ajoute des sleeps, des logs, des timeouts plus larges ou des boucles de retry. Certaines de ces modifications sont utiles. Beaucoup ne font que déplacer la panne ailleurs. La panne reste une histoire : "on l'a vue une fois en CI".</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avec une simulation déterministe, la panne doit devenir un artefact. Cet artefact est une seed, une trace et une transition d'état rejouable. La question passe de "peut-on la refaire apparaître ?" à "quel invariant cet ordonnancement a-t-il violé ?"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette différence compte pour une bibliothèque cliente. Les bugs de client se trouvent souvent à la frontière entre le code utilisateur et le broker. Ils sont faciles à attribuer au mauvais endroit. Un publish peut échouer parce que le broker a fermé la connexion, parce que le client a perdu un outcome, parce que le chemin de reconnexion a reconstruit le producer trop tard, parce qu'un ack a réveillé le mauvais waiter, parce qu'un timeout a frappé un état de session périmé, ou parce que la tâche runtime est morte après que le protocole a déjà changé d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si tout ce comportement est dispersé entre des tâches, des channels, des timers et des sockets, un rapport de panne est difficile à réduire. Si la machine d'état protocolaire est explicite, si la frontière runtime est étroite et si la même séquence peut être rejouée avec des providers contrôlés, le rapport devient beaucoup plus petit : cette seed, cette trace, cet ordre d'événements, cet invariant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar traite la reproductibilité comme une partie du design du client. Le but n'est pas seulement de trouver plus de bugs. Le but est que les bugs trouvés coûtent moins cher à comprendre et soient plus sûrs à corriger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela change aussi la revue de code. Un reviewer peut demander si un comportement est couvert à la bonne couche. Est-ce une transition protocolaire pure ? Alors le test sans-io doit injecter des octets et vérifier des événements. Est-ce de la colle runtime ? Alors Tokio et Moonpool doivent avoir une couverture équivalente. Est-ce un comportement observable partagé par les deux moteurs ? Alors le harnais différentiel doit comparer les event streams. Est-ce de la compatibilité broker ? Alors un e2e doit toucher un vrai broker Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces questions sont plus précises que "a-t-on ajouté des tests ?" Elles relient le test au modèle de panne.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Par où commencer la lecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour les ingénieurs qui découvrent Magnetar, le meilleur point d'entrée n'est pas un fichier unique. C'est la relation entre les documents et le code.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> donne la surface publique : ce que le client expose, quelles fonctionnalités sont implémentées, comment la matrice de parité Java est suivie, quels PIPs sont supportés et comment les deux moteurs sont positionnés. C'est le contrat utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> explique la forme située sous ce contrat. Il montre la topologie de crates, le sens des dépendances, la frontière sans-io, la boucle driver, le modèle d'événements, les chemins producer et consumer, les moteurs runtime, les sites TLS, les schémas, la couverture PIP et la stratégie de validation. C'est la carte du système.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">série d'ADR</a> explique pourquoi le système a cette forme. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">ADR-0004</a> documente la séparation sans-io. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0003-no-channels-rule.md">ADR-0003</a> documente l'interdiction des channels. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0011-clock-injection-sans-io.md">ADR-0011</a> documente l'injection d'horloge. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">ADR-0010</a> documente la décision de parité Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0019-engine-scope-and-moonpool-parity.md">ADR-0019</a> documente la relation entre le moteur de production Tokio et le moteur Moonpool par rapport à cet objectif de parité. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">ADR-0024</a> documente la politique de test cross-runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que Magnetar n'est volontairement pas seulement un dépôt de code. C'est un ensemble de décisions d'ingénierie avec une trace publique. Si vous n'êtes pas d'accord avec le design, les ADR donnent la bonne surface de discussion. Si vous voulez contribuer une fonctionnalité, la matrice de parité et la politique de validation indiquent ce que "terminé" veut dire. Si vous voulez évaluer le travail de simulation, la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> et le harnais différentiel montrent comment le même coeur protocolaire est piloté dans plusieurs mondes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette première release doit donc se lire de deux manières. Comme utilisateur Pulsar, regardez la surface cliente et la matrice de parité. Comme ingénieur infrastructure Rust, regardez la frontière de machine d'état et la stratégie de simulation. Ce qui rend Magnetar intéressant, c'est que ces deux lectures sont censées se renforcer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que donne la première release publique</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Cette première release publique est un point d'entrée technique. Elle s'adresse aux ingénieurs qui veulent essayer Magnetar, lire l'architecture, inspecter les ADR, comparer le comportement avec les clients Pulsar existants et contribuer à structurer l'écosystème Pulsar Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API cliente de haut niveau commence par une forme attendue :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>let client = PulsarClient::builder()
    .service_url("pulsar://localhost:6650")
    .build()
    .await?;

let producer = client
    .producer("persistent://public/default/orders")
    .create()
    .await?;</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette API est importante, parce que le client doit être utilisable. Mais la release est aussi une invitation à inspecter les couches inférieures. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> pour la matrice fonctionnelle. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> pour le design sans-io. Lire les <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">ADR</a> pour les décisions derrière l'interdiction des channels, les moteurs remplaçables, l'injection d'horloge, la parité Java, la parité Moonpool, les choix de providers TLS et la validation cross-runtime. Lire la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> si la simulation déterministe appliquée à un vrai client réseau vous intéresse.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le point important pour cet article est la direction : Magnetar est public pour que les ingénieurs puissent évaluer à la fois la surface cliente et le modèle d'ingénierie qui la porte.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Vous pouvez consulter la première release publique de Magnetar <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.0.0">v1.0.0</a>, ainsi que la dernière release à ce jour, la version <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.2.0">v1.2.0</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi cela dépasse Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar est un client Apache Pulsar. C'est aussi un exemple concret de la manière dont nous voulons construire davantage de logiciel d'infrastructure en Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les systèmes distribués échouent par transitions d'état. Certaines de ces transitions sont évidentes et faciles à tester. Beaucoup ne le sont pas. Elles apparaissent lorsque le temps avance au mauvais endroit, lorsqu'un retry chevauche un chemin de fermeture, lorsqu'un broker coupe une connexion après avoir accepté une partie de la session, lorsqu'un callback est enregistré juste après une notification, ou lorsqu'un chemin de reconnexion reconstruit un handle mais pas un autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>On peut essayer de traquer ces bugs après coup. C'est parfois inévitable. Mais l'architecture peut rendre cette traque plus facile ou plus difficile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client avec un coeur protocolaire pur, des événements explicites, du temps injecté, une I/O remplaçable, des seeds déterministes et une comparaison cross-runtime donne de meilleurs outils aux ingénieurs. Il permet de réduire une panne à une trace. Il permet de rejouer cette trace. Il permet de demander si une panne simulée correspond au runtime de production. Il permet d'ajouter un invariant là où une dérive silencieuse de l'état pouvait se cacher.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la direction prise par Magnetar. Rendre le protocole explicite. Rendre le runtime remplaçable. Rendre les pannes reproductibles. Faire de la correction quelque chose que le code doit démontrer en continu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Merci à Pierre Zemb pour Moonpool et pour cette direction de simulation déterministe en Rust, ainsi qu'aux contributeurs et mainteneurs de l'écosystème Pulsar Rust dont le travail a rendu l'étape suivante possible.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est open source. Le code, les notes d'architecture, les ADR et la documentation vivent sur <a href="https://github.com/CleverCloud/magnetar">github.com/CleverCloud/magnetar</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Magnetar</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Dépôt Magnetar</strong>. Dépôt public du client Apache Pulsar Rust. <a href="https://github.com/CleverCloud/magnetar">https://github.com/CleverCloud/magnetar</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>README Magnetar</strong>. Surface publique, matrice de parité Java, PIPs supportés, couverture par moteur et statut. <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">https://github.com/CleverCloud/magnetar/blob/main/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Architecture Magnetar</strong>. Rationale sans-io, topologie de crates, driver loop, machine d'état protocolaire et tests. <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Index de documentation Magnetar</strong>. Moteur Moonpool, testing, CLI, observabilité, logging, features PIP. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/README.md">https://github.com/CleverCloud/magnetar/blob/main/docs/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation du moteur Moonpool</strong>. Moteur de simulation déterministe, chaos pack, harnais différentiel, modèle de providers. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test</strong>. Catégories de tests et commandes de validation. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0004</strong>. magnetar-proto sans-io et moteurs d'I/O remplaçables. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0010</strong>. Parité complète avec le client Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0024</strong>. Politique de tests et couverture cross-runtime. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Écosystème</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>pulsar-rs</strong>. Client Apache Pulsar Rust existant. <a href="https://github.com/streamnative/pulsar-rs">https://github.com/streamnative/pulsar-rs</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Apache Pulsar</strong>. Plateforme distribuée de messaging et streaming. <a href="https://pulsar.apache.org/">https://pulsar.apache.org/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Client Java Apache Pulsar</strong>. Surface de référence pour de nombreux utilisateurs Pulsar. <a href="https://pulsar.apache.org/docs/">https://pulsar.apache.org/docs/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Simulation déterministe</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie centré sur les assertions. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Simulation déterministe pour systèmes Rust, développée par Pierre Zemb. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Crate du moteur de simulation Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Sōzu 2.1.0 : load balancing UDP pour l&#8217;edge programmable</title>
		<link>https://www.clever.cloud/fr/blog/entreprise/2026/07/01/sozu-2-1-0-load-balancing-udp-edge-programmable/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Wed, 01 Jul 2026 08:08:01 +0000</pubDate>
				<category><![CDATA[Entreprise]]></category>
		<guid isPermaLink="false">https://www.clever.cloud/?p=24845</guid>

					<description><![CDATA[<p><img width="2500" height="1109" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.01 Clever Cloud Bannière Blog Sōzu 2.1.0 FR" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr.png 2500w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1536x681.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-2048x908.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1368x607.png 1368w" sizes="(max-width: 2500px) 100vw, 2500px" /></p><!-- wp:paragraph -->
<p>Nous portons ce projet et en sommes le principal contributeur (<a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>). Avec <a href="https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/">Sōzu 2.0</a>, nous expliquions comment le proxy passait du reverse proxy vers l'edge programmable : nouveau multiplexer HTTP/2, sécurité renforcée par défaut, surface d'observabilité plus riche, politiques de trafic, durcissement opérationnel et agilité cryptographique.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.0.2 est arrivé quelques jours plus tard avec une release plus courte, mais très révélatrice. Elle ajoutait une défense en profondeur face à la classe HTTP/2 bomb et corrigeait la fondation temporelle nécessaire à la reconstruction de spans OpenTelemetry fiables depuis les access logs. Cette version montrait la façon dont nous voulons exploiter l'edge : lorsqu'une classe d'attaque protocolaire apparaît, le proxy doit en absorber autant que possible ; lorsque l'observabilité est subtilement fausse, il faut corriger la fondation avant de construire le produit par-dessus.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 est l'étape suivante de cette histoire. L'un des chantiers que nous annoncions comme étant sur l'établi pour la 2.0 a atterri : <strong>le load balancer UDP</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas simplement une case protocolaire de plus. Sōzu prenait déjà en charge HTTP, HTTPS et TCP. Avec la 2.1.0, UDP entre dans le même modèle : le même plan de contrôle reconfigurable à chaud, la même posture d'exploitation, la même discipline de métriques et le même processus de release open source. Sōzu s'élargit ainsi depuis l'edge web vers un load balancer d'infrastructure plus général, capable de placer des services datagrammes comme DNS, syslog, NTP et des workloads UDP génériques derrière le proxy, sans imposer un deuxième load balancer en frontal.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour Clever Cloud, cela compte parce que le réseau d'une plateforme ne se limite pas à HTTP. <a href="https://www.clever.cloud/fr/clever-kubernetes-engine/">Kubernetes managé</a> et <a href="https://www.clever.cloud/fr/paas/">PaaS</a> ont tous deux besoin d'une histoire propre pour le trafic de transport direct. Pour les opérateurs qui exécutent Sōzu eux-mêmes, cela signifie qu'un même composant peut couvrir davantage de surface L4/L7 tout en conservant les propriétés de conception qui rendent Sōzu utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi UDP compte encore</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Une grande partie du trafic visible sur le web passe par HTTP, et l'on pourrait être tenté de traiter tout le reste comme un cas particulier. Une vraie plateforme ne peut pas se le permettre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>DNS est UDP par défaut. Syslog s'exécute souvent sur UDP. NTP utilise UDP. Beaucoup de protocoles internes ou d'infrastructure utilisent des datagrammes parce qu'ils sont simples, sensibles à la latence, ou suffisamment proches d'un modèle requête/réponse pour qu'une connexion TCP complète soit inutile. Les plateformes Kubernetes et PaaS doivent également exposer proprement des services de transport direct, pas seulement des applications web terminées en HTTP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avant Sōzu 2.1.0, un opérateur voulant un edge unique pour HTTP, TCP et UDP devait généralement composer plusieurs systèmes. Sōzu couvrait HTTP et TCP, tandis qu'un autre composant traitait UDP. Cette séparation a un coût opérationnel : deux modèles de health check, deux façons d'observer le trafic, deux cycles de release, deux surfaces de panne, deux configurations, et deux endroits où l'état de routage peut diverger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'enjeu du support UDP de première classe dans Sōzu, c'est la convergence. Un listener UDP existe désormais au même niveau que les listeners tcp, http et https. Les frontends et backends UDP font partie de la même mécanique de commandes, de configuration et d'état. Les opérateurs disposent de métriques spécifiques à UDP au niveau du proxy, au lieu de traiter le trafic datagramme comme un phénomène extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le bénéfice utilisateur n'est pas que chaque application aurait soudainement besoin d'UDP. Il est que la plateforme peut faire converger plus de classes de trafic sous un même modèle opérationnel : reconfiguration à chaud, health checks, métriques, discipline de release et composant d'edge unique qui peut évoluer vers des fonctionnalités produit, plutôt que rester un assemblage d'exceptions par protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce qui est disponible dans Sōzu 2.1.0</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 ajoute un nouveau type de listener protocol = "udp" aux côtés des listeners HTTP, HTTPS et TCP. Il est opt-in. Les configurations existantes ne deviennent pas UDP par accident, et les consommateurs de sozu-command-lib peuvent passer de 2.0.2 à 2.1.0 sans réécrire leurs intégrations.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'idée centrale consiste à représenter le trafic UDP sous forme de <strong>flows virtuels</strong>. UDP n'a pas de connexion, pas de stream, pas de boucle accept(). Un datagramme arrive sur une socket. Il n'existe pas de socket par client créée par le noyau, comme en TCP. Sōzu reconstruit donc en espace utilisateur la partie utile d'une connexion : un flow identifié par l'adresse source du client, avec la possibilité d'inclure le port source lorsque c'est le bon modèle d'affinité pour le workload.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Une fois ce flow établi, Sōzu peut prendre les décisions qu'un load balancer doit prendre pour n'importe quel transport :</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>quel backend porte ce client ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>combien de temps le flow doit rester vivant ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>que faire lorsqu'un backend devient unhealthy ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>comment délester en surcharge ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>quelles métriques et quels logs émettre.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>La release ajoute deux algorithmes adaptés à l'affinité de flow UDP. Le choix recommandé est <strong>HRW</strong>, aussi appelé rendezvous hashing. HRW possède une propriété très utile dans un système reconfigurable à chaud : lorsque l'ensemble des backends change, il minimise les déplacements sans nécessiter de table pré-calculée. Sōzu propose également <strong>Maglev</strong> en option, pour les ensembles de backends plus grands ou les débits élevés où un lookup O(1) devient plus intéressant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu peut aussi envoyer des informations <strong>PROXY protocol v2</strong> aux backends UDP. Cela transporte la véritable adresse client vers le backend, qui n'a pas à considérer le proxy comme seul pair visible. Par défaut, Sōzu l'envoie sur le premier datagramme d'un flow, avec une option pour l'envoyer sur chaque datagramme lorsque le backend a besoin de ce contexte à chaque fois.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les health checks font partie du design UDP, et non d'une rustine. Un backend UDP peut être vérifié via une sonde TCP compagnon, qui est le signal pratique courant pour les services où UDP nu ne fournit pas d'état "connecté" fiable. Sōzu peut aussi utiliser une sonde UDP applicative lorsque cela a du sens. Les checks prennent en charge l'hystérésis rise/fall et une sémantique fail-open, afin qu'une panne transitoire ou globale de health check ne transforme pas automatiquement le trafic en trou noir.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Enfin, UDP obtient sa propre surface de métriques : datagrammes entrants et sortants, octets entrants et sortants, flows actifs, flows créés, évincés ou délestés, datagrammes droppés par raison, santé des backends et durée des flows. C'est le même principe que pour l'observabilité de la 2.0 : une fonctionnalité n'est exploitable en production que lorsque les opérateurs peuvent voir ce qu'elle fait.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">UDP est facile à mal ajouter</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La difficulté du load balancing UDP n'est pas de recevoir un datagramme et de l'envoyer ailleurs. La difficulté est de décider quel état existe autour de ce datagramme.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>TCP donne au proxy un cycle de vie de connexion. HTTP lui donne des requêtes, des réponses, des headers et des status codes. UDP lui donne des paquets. Ces paquets peuvent arriver dans le désordre. Ils peuvent disparaître. Un client peut cesser d'envoyer sans rien fermer, puisqu'il n'y a rien à fermer. Un backend peut devenir unhealthy alors qu'un flow virtuel pointe encore vers lui. Une reconfiguration peut arriver pendant que des flows existent. Un listener peut atteindre son plafond de flows. Un timeout peut se déclencher juste après le rafraîchissement d'un flow. Ce ne sont pas des cas exotiques. C'est la forme normale du trafic datagramme sous charge.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail UDP de Sōzu 2.1.0 porte autant sur la testabilité que sur la fonctionnalité.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le coeur UDP est structuré autour d'une séparation <strong>sans-io</strong>. Le coeur pur porte la table des flows, les décisions d'admission, les timers, la politique de teardown et les demandes de load balancing. La coquille impure porte les sockets, le buffer pool, les health checks, les appels système et l'émission des métriques. Le coeur n'a pas de socket, pas de lecture d'horloge murale dans le datapath, pas de source d'aléa cachée. Le temps et les seeds sont injectés.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette forme compte parce qu'elle rend le coeur simulable de manière déterministe. La même seed produit la même séquence. La même horloge virtuelle saute aux mêmes instants. La même tempête de reconfiguration se produit à la même étape. Une panne peut imprimer une seed et être rejouée exactement.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 embarque un harnais de simulation déterministe, dans l'esprit FoundationDB/VOPR, pour le coeur UDP. Le sweep par défaut exécute <strong>256 seeds</strong>, chacune pilotant une charge adversariale randomisée : datagrammes client, réponses backend, résolutions backend périmées, rafales de reconfiguration, changements de plafond de flows, sauts d'horloge, drains et teardown de masse. Après chaque action, le harnais draine les sorties du coeur et vérifie les invariants du modèle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Par-dessus, la release contient un travail de densité d'assertions inspiré de TigerBeetle TigerStyle. À travers le proxy, le plan de contrôle et le supervisor, Sōzu porte désormais environ <strong>1100 </strong><strong>debug_assert!</strong> et plusieurs sweeps d'invariants. Ces assertions sont compilées hors des builds de release, mais elles sont actives dans les tests, le fuzzing, les tests end-to-end, les simulations et les builds de développement. Elles transforment une dérive d'état silencieuse en échec local et bruyant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces chiffres sont utiles parce qu'ils ne mesurent pas du volume. Le nombre de lignes de code ne prouve pas la fiabilité. Un sweep de 256 seeds et des invariants denses disent autre chose : le code est poussé dans des transitions d'état adversariales, et les structures de données doivent prouver en continu qu'elles restent cohérentes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un proxy, cette distinction est essentielle. Un compteur faux n'est pas seulement un compteur faux. Il peut signifier qu'un flow fuit. Un timer périmé n'est pas seulement un timer. Il peut signifier qu'un backend continue de recevoir du trafic alors que l'état prétend le contraire. Une divergence silencieuse entre une table de routage et un slab n'est pas qu'une incohérence interne. C'est le genre de défaut qui devient un symptôme de production plusieurs couches plus loin que le bug réel.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La simulation déterministe comme direction</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le simulateur UDP indique aussi la direction que nous voulons donner à l'ingénierie de Sōzu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>FoundationDB a rendu célèbre la simulation déterministe dans le logiciel d'infrastructure : exécuter le système dans un monde simulé, injecter des fautes, explorer des milliers d'ordonnancements et rendre chaque panne reproductible depuis une seed. TigerBeetle pousse une discipline complémentaire : énoncer les invariants directement dans le code, affirmer l'espace positif et l'espace négatif, et rendre l'état illégal impossible à ignorer pendant les tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 applique ces idées au coeur UDP. Le prochain chantier architectural consiste à faire entrer davantage de Sōzu dans cette forme : plus de composants sans-io, plus d'horloges injectées et de frontières déterministes, plus de couches simulables sur les parties pertinentes du modèle OSI avant de les exposer comme comportement de production.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est également pour cela que <a href="https://github.com/PierreZ/moonpool">Moonpool</a> compte pour Clever Cloud. Moonpool, développé par PierreZ, est le moteur de simulation déterministe que nous utilisons chez Clever Cloud pour cette direction en Rust. La version 0.7.0 est désormais disponible publiquement sur crates.io, avec moonpool et moonpool-sim. Le harnais UDP de Sōzu est aujourd'hui un simulateur synchrone in-tree, adapté au coeur UDP pur, mais la direction générale est la même : workloads déterministes, temps virtuel, seeds reproductibles, et systèmes réseau que l'on peut faire échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le premier bénéfice est la fiabilité. Nous voulons moins de bugs de coin dans le code protocolaire et la reconfiguration. Le deuxième bénéfice est la vitesse de développement. Lorsque davantage de proxy est structuré en machines d'état pures avec des frontières d'I/O explicites, les nouveaux comportements protocole et load balancing deviennent plus sûrs à faire évoluer. Le troisième bénéfice est l'exploitabilité. Hot reload, surcharge et panne deviennent plus faciles à raisonner parce que le code a été exercé sous ces formes exactes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la couche située sous l'edge programmable. Les boutons exposés aux utilisateurs ne valent la peine d'exister que si la mécanique qui les porte est suffisamment déterministe pour inspirer confiance.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que cela rend possible</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour Kubernetes managé, le support UDP donne à Sōzu un meilleur socle pour les services de transport direct. Une plateforme peut proposer du trafic web, des services TCP et des services UDP dans un modèle de load balancing plus cohérent, plutôt que de séparer les responsabilités entre composants sans lien.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour le PaaS, cela ouvre la voie à des fonctionnalités produit autour des workloads datagrammes sans repartir d'une pile opérationnelle séparée. Des services proches de DNS, des flux proches de syslog, des sondes proches de NTP et des applications UDP génériques peuvent être pensés avec le vocabulaire du même proxy : listeners, clusters, backends, health, métriques et reconfiguration à chaud.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour les opérateurs Sōzu hors Clever Cloud, cela signifie que le projet couvre davantage de surface d'edge infrastructure. Si vous utilisez déjà Sōzu parce que vous voulez un proxy open source, reconfigurable à chaud, avec des releases signées et un code Rust auditable, la 2.1.0 élargit la classe de trafic que vous pouvez placer sous ce modèle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La conséquence côté observabilité est également importante. Le trafic UDP dispose désormais de métriques natives dans le proxy. Vous pouvez demander combien de flows sont actifs, combien ont été délestés, pourquoi des datagrammes ont été droppés, si les backends sont healthy et combien de temps vivent les flows. C'est ce qui transforme une fonctionnalité protocolaire en capacité exploitable.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La fiabilité vient aussi de ce qui entoure UDP</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le titre de cette release est UDP, mais la 2.1.0 continue aussi le travail opérationnel de la 2.0.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La reconfiguration à chaud est l'une des promesses centrales de Sōzu, donc la correction du replay d'état compte. Cette release corrige un cas où un listener dont la configuration changeait tout en restant actif pouvait être rejoué comme une suppression suivie d'un ajout sans réémettre l'activation. Ce type de bug explique précisément pourquoi le modèle d'état doit être testé comme un cycle de vie, et pas seulement comme une somme de commandes isolées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La release corrige aussi un panic par underflow arithmétique dans le pattern trie pour des hostnames dont le segment le plus à gauche est une regex. Elle corrige enfin la chaîne de release en pinning le binaire cosign sur la ligne 2.x, après un changement d'outillage ayant cassé le flux des artefacts de signature pendant la release 2.0.2.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce ne sont pas les parties de la release que les utilisateurs verront en premier. Elles font pourtant partie du produit. À l'échelle de Clever Cloud, la tranquillité opérationnelle est un bénéfice client. Un proxy qui se reconfigure correctement, signe ses artefacts de manière prévisible et transforme ses cas limites en tests laisse les applications continuer à servir du trafic pendant que la plateforme bouge sous elles.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La suite</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le support UDP va continuer à mûrir avec l'usage réel. Il y aura de la place pour du travail de performance, du batching et du retour d'expérience opérationnel. Mais la direction plus large est architecturale : rendre davantage de Sōzu déterministe, davantage sans-io lorsque cela a du sens, et davantage de modes de panne reproductibles avant qu'ils ne deviennent des incidents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la leçon de Sōzu 2.1.0. L'edge programmable n'est pas seulement un ensemble de toggles exposés aux utilisateurs. C'est aussi une manière de construire du logiciel d'infrastructure : protocole par protocole, machine d'état par machine d'état, avec assez d'observabilité pour l'exploiter et assez de simulation pour lui faire confiance.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu est un projet open source publié sous AGPL-3.0, avec sa command library sous LGPL-3.0. Le code, les notes de release, les issues et les discussions de conception vivent sur <a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>. Merci aux contributeurs et aux opérateurs qui poussent le projet vers un edge plus large, plus sûr et plus programmable.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Sōzu</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Notes de release Sōzu 2.1.0</strong>. Load balancing UDP de première classe, simulation déterministe, densité d'assertions, CI et documentation. <a href="https://github.com/sozu-proxy/sozu/releases/tag/2.1.0">https://github.com/sozu-proxy/sozu/releases/tag/2.1.0</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC et master plan UDP de Sōzu</strong>. Issue publique de conception pour le load balancing UDP de première classe. <a href="https://github.com/sozu-proxy/sozu/issues/1273">https://github.com/sozu-proxy/sozu/issues/1273</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>PR d'implémentation UDP de Sōzu</strong>. Implémentation des listeners UDP de première classe et du load balancing associé. <a href="https://github.com/sozu-proxy/sozu/pull/1274">https://github.com/sozu-proxy/sozu/pull/1274</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Issue historique sur le load balancing UDP</strong>. Issue publique ouverte en 2020. <a href="https://github.com/sozu-proxy/sozu/issues/654">https://github.com/sozu-proxy/sozu/issues/654</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Sōzu 2.0 : du reverse proxy à l'edge programmable</strong>. Article de release jalon. <a href="https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/">https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de configuration Sōzu</strong>. Listeners UDP, clusters UDP, health checks, PROXY protocol et métriques. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/configure.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/configure.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test Sōzu</strong>. Doctrine de test : unit, e2e, fuzz, simulation déterministe et gardes de régression. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/testing.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de simulation UDP Sōzu</strong>. Sweep par défaut de 256 seeds et knobs de replay. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/udp_simulation.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/udp_simulation.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Protocoles et algorithmes</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Spécification PROXY protocol v2</strong>. Propagation de l'adresse client à travers les proxies. <a href="https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt">https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Rendezvous hashing / HRW</strong>. Sélection avec affinité et perturbation minimale lorsque l'ensemble des backends change. <a href="https://en.wikipedia.org/wiki/Rendezvous_hashing">https://en.wikipedia.org/wiki/Rendezvous_hashing</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Maglev: A Fast and Reliable Software Network Load Balancer</strong>. Papier Google décrivant le consistent hashing Maglev. <a href="https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/">https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Tests</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie assertion-first. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Moonpool</strong>. Simulation déterministe pour systèmes distribués en Rust. <a href="https://crates.io/crates/moonpool">https://crates.io/crates/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Moteur de simulation du framework Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Développé par PierreZ. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[<p><img width="2500" height="1109" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.01 Clever Cloud Bannière Blog Sōzu 2.1.0 FR" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr.png 2500w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1536x681.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-2048x908.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-01-clever-cloud-banniere-blog-sozu-2-1-0-fr-1368x607.png 1368w" sizes="auto, (max-width: 2500px) 100vw, 2500px" /></p><!-- wp:paragraph -->
<p>Nous portons ce projet et en sommes le principal contributeur (<a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>). Avec <a href="https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/">Sōzu 2.0</a>, nous expliquions comment le proxy passait du reverse proxy vers l'edge programmable : nouveau multiplexer HTTP/2, sécurité renforcée par défaut, surface d'observabilité plus riche, politiques de trafic, durcissement opérationnel et agilité cryptographique.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.0.2 est arrivé quelques jours plus tard avec une release plus courte, mais très révélatrice. Elle ajoutait une défense en profondeur face à la classe HTTP/2 bomb et corrigeait la fondation temporelle nécessaire à la reconstruction de spans OpenTelemetry fiables depuis les access logs. Cette version montrait la façon dont nous voulons exploiter l'edge : lorsqu'une classe d'attaque protocolaire apparaît, le proxy doit en absorber autant que possible ; lorsque l'observabilité est subtilement fausse, il faut corriger la fondation avant de construire le produit par-dessus.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 est l'étape suivante de cette histoire. L'un des chantiers que nous annoncions comme étant sur l'établi pour la 2.0 a atterri : <strong>le load balancer UDP</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas simplement une case protocolaire de plus. Sōzu prenait déjà en charge HTTP, HTTPS et TCP. Avec la 2.1.0, UDP entre dans le même modèle : le même plan de contrôle reconfigurable à chaud, la même posture d'exploitation, la même discipline de métriques et le même processus de release open source. Sōzu s'élargit ainsi depuis l'edge web vers un load balancer d'infrastructure plus général, capable de placer des services datagrammes comme DNS, syslog, NTP et des workloads UDP génériques derrière le proxy, sans imposer un deuxième load balancer en frontal.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour Clever Cloud, cela compte parce que le réseau d'une plateforme ne se limite pas à HTTP. <a href="https://www.clever.cloud/fr/clever-kubernetes-engine/">Kubernetes managé</a> et <a href="https://www.clever.cloud/fr/paas/">PaaS</a> ont tous deux besoin d'une histoire propre pour le trafic de transport direct. Pour les opérateurs qui exécutent Sōzu eux-mêmes, cela signifie qu'un même composant peut couvrir davantage de surface L4/L7 tout en conservant les propriétés de conception qui rendent Sōzu utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi UDP compte encore</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Une grande partie du trafic visible sur le web passe par HTTP, et l'on pourrait être tenté de traiter tout le reste comme un cas particulier. Une vraie plateforme ne peut pas se le permettre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>DNS est UDP par défaut. Syslog s'exécute souvent sur UDP. NTP utilise UDP. Beaucoup de protocoles internes ou d'infrastructure utilisent des datagrammes parce qu'ils sont simples, sensibles à la latence, ou suffisamment proches d'un modèle requête/réponse pour qu'une connexion TCP complète soit inutile. Les plateformes Kubernetes et PaaS doivent également exposer proprement des services de transport direct, pas seulement des applications web terminées en HTTP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avant Sōzu 2.1.0, un opérateur voulant un edge unique pour HTTP, TCP et UDP devait généralement composer plusieurs systèmes. Sōzu couvrait HTTP et TCP, tandis qu'un autre composant traitait UDP. Cette séparation a un coût opérationnel : deux modèles de health check, deux façons d'observer le trafic, deux cycles de release, deux surfaces de panne, deux configurations, et deux endroits où l'état de routage peut diverger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'enjeu du support UDP de première classe dans Sōzu, c'est la convergence. Un listener UDP existe désormais au même niveau que les listeners tcp, http et https. Les frontends et backends UDP font partie de la même mécanique de commandes, de configuration et d'état. Les opérateurs disposent de métriques spécifiques à UDP au niveau du proxy, au lieu de traiter le trafic datagramme comme un phénomène extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le bénéfice utilisateur n'est pas que chaque application aurait soudainement besoin d'UDP. Il est que la plateforme peut faire converger plus de classes de trafic sous un même modèle opérationnel : reconfiguration à chaud, health checks, métriques, discipline de release et composant d'edge unique qui peut évoluer vers des fonctionnalités produit, plutôt que rester un assemblage d'exceptions par protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce qui est disponible dans Sōzu 2.1.0</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 ajoute un nouveau type de listener protocol = "udp" aux côtés des listeners HTTP, HTTPS et TCP. Il est opt-in. Les configurations existantes ne deviennent pas UDP par accident, et les consommateurs de sozu-command-lib peuvent passer de 2.0.2 à 2.1.0 sans réécrire leurs intégrations.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'idée centrale consiste à représenter le trafic UDP sous forme de <strong>flows virtuels</strong>. UDP n'a pas de connexion, pas de stream, pas de boucle accept(). Un datagramme arrive sur une socket. Il n'existe pas de socket par client créée par le noyau, comme en TCP. Sōzu reconstruit donc en espace utilisateur la partie utile d'une connexion : un flow identifié par l'adresse source du client, avec la possibilité d'inclure le port source lorsque c'est le bon modèle d'affinité pour le workload.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Une fois ce flow établi, Sōzu peut prendre les décisions qu'un load balancer doit prendre pour n'importe quel transport :</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>quel backend porte ce client ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>combien de temps le flow doit rester vivant ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>que faire lorsqu'un backend devient unhealthy ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>comment délester en surcharge ;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>quelles métriques et quels logs émettre.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>La release ajoute deux algorithmes adaptés à l'affinité de flow UDP. Le choix recommandé est <strong>HRW</strong>, aussi appelé rendezvous hashing. HRW possède une propriété très utile dans un système reconfigurable à chaud : lorsque l'ensemble des backends change, il minimise les déplacements sans nécessiter de table pré-calculée. Sōzu propose également <strong>Maglev</strong> en option, pour les ensembles de backends plus grands ou les débits élevés où un lookup O(1) devient plus intéressant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu peut aussi envoyer des informations <strong>PROXY protocol v2</strong> aux backends UDP. Cela transporte la véritable adresse client vers le backend, qui n'a pas à considérer le proxy comme seul pair visible. Par défaut, Sōzu l'envoie sur le premier datagramme d'un flow, avec une option pour l'envoyer sur chaque datagramme lorsque le backend a besoin de ce contexte à chaque fois.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les health checks font partie du design UDP, et non d'une rustine. Un backend UDP peut être vérifié via une sonde TCP compagnon, qui est le signal pratique courant pour les services où UDP nu ne fournit pas d'état "connecté" fiable. Sōzu peut aussi utiliser une sonde UDP applicative lorsque cela a du sens. Les checks prennent en charge l'hystérésis rise/fall et une sémantique fail-open, afin qu'une panne transitoire ou globale de health check ne transforme pas automatiquement le trafic en trou noir.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Enfin, UDP obtient sa propre surface de métriques : datagrammes entrants et sortants, octets entrants et sortants, flows actifs, flows créés, évincés ou délestés, datagrammes droppés par raison, santé des backends et durée des flows. C'est le même principe que pour l'observabilité de la 2.0 : une fonctionnalité n'est exploitable en production que lorsque les opérateurs peuvent voir ce qu'elle fait.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">UDP est facile à mal ajouter</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La difficulté du load balancing UDP n'est pas de recevoir un datagramme et de l'envoyer ailleurs. La difficulté est de décider quel état existe autour de ce datagramme.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>TCP donne au proxy un cycle de vie de connexion. HTTP lui donne des requêtes, des réponses, des headers et des status codes. UDP lui donne des paquets. Ces paquets peuvent arriver dans le désordre. Ils peuvent disparaître. Un client peut cesser d'envoyer sans rien fermer, puisqu'il n'y a rien à fermer. Un backend peut devenir unhealthy alors qu'un flow virtuel pointe encore vers lui. Une reconfiguration peut arriver pendant que des flows existent. Un listener peut atteindre son plafond de flows. Un timeout peut se déclencher juste après le rafraîchissement d'un flow. Ce ne sont pas des cas exotiques. C'est la forme normale du trafic datagramme sous charge.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail UDP de Sōzu 2.1.0 porte autant sur la testabilité que sur la fonctionnalité.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le coeur UDP est structuré autour d'une séparation <strong>sans-io</strong>. Le coeur pur porte la table des flows, les décisions d'admission, les timers, la politique de teardown et les demandes de load balancing. La coquille impure porte les sockets, le buffer pool, les health checks, les appels système et l'émission des métriques. Le coeur n'a pas de socket, pas de lecture d'horloge murale dans le datapath, pas de source d'aléa cachée. Le temps et les seeds sont injectés.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette forme compte parce qu'elle rend le coeur simulable de manière déterministe. La même seed produit la même séquence. La même horloge virtuelle saute aux mêmes instants. La même tempête de reconfiguration se produit à la même étape. Une panne peut imprimer une seed et être rejouée exactement.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 embarque un harnais de simulation déterministe, dans l'esprit FoundationDB/VOPR, pour le coeur UDP. Le sweep par défaut exécute <strong>256 seeds</strong>, chacune pilotant une charge adversariale randomisée : datagrammes client, réponses backend, résolutions backend périmées, rafales de reconfiguration, changements de plafond de flows, sauts d'horloge, drains et teardown de masse. Après chaque action, le harnais draine les sorties du coeur et vérifie les invariants du modèle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Par-dessus, la release contient un travail de densité d'assertions inspiré de TigerBeetle TigerStyle. À travers le proxy, le plan de contrôle et le supervisor, Sōzu porte désormais environ <strong>1100 </strong><strong>debug_assert!</strong> et plusieurs sweeps d'invariants. Ces assertions sont compilées hors des builds de release, mais elles sont actives dans les tests, le fuzzing, les tests end-to-end, les simulations et les builds de développement. Elles transforment une dérive d'état silencieuse en échec local et bruyant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces chiffres sont utiles parce qu'ils ne mesurent pas du volume. Le nombre de lignes de code ne prouve pas la fiabilité. Un sweep de 256 seeds et des invariants denses disent autre chose : le code est poussé dans des transitions d'état adversariales, et les structures de données doivent prouver en continu qu'elles restent cohérentes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un proxy, cette distinction est essentielle. Un compteur faux n'est pas seulement un compteur faux. Il peut signifier qu'un flow fuit. Un timer périmé n'est pas seulement un timer. Il peut signifier qu'un backend continue de recevoir du trafic alors que l'état prétend le contraire. Une divergence silencieuse entre une table de routage et un slab n'est pas qu'une incohérence interne. C'est le genre de défaut qui devient un symptôme de production plusieurs couches plus loin que le bug réel.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La simulation déterministe comme direction</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le simulateur UDP indique aussi la direction que nous voulons donner à l'ingénierie de Sōzu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>FoundationDB a rendu célèbre la simulation déterministe dans le logiciel d'infrastructure : exécuter le système dans un monde simulé, injecter des fautes, explorer des milliers d'ordonnancements et rendre chaque panne reproductible depuis une seed. TigerBeetle pousse une discipline complémentaire : énoncer les invariants directement dans le code, affirmer l'espace positif et l'espace négatif, et rendre l'état illégal impossible à ignorer pendant les tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu 2.1.0 applique ces idées au coeur UDP. Le prochain chantier architectural consiste à faire entrer davantage de Sōzu dans cette forme : plus de composants sans-io, plus d'horloges injectées et de frontières déterministes, plus de couches simulables sur les parties pertinentes du modèle OSI avant de les exposer comme comportement de production.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est également pour cela que <a href="https://github.com/PierreZ/moonpool">Moonpool</a> compte pour Clever Cloud. Moonpool, développé par PierreZ, est le moteur de simulation déterministe que nous utilisons chez Clever Cloud pour cette direction en Rust. La version 0.7.0 est désormais disponible publiquement sur crates.io, avec moonpool et moonpool-sim. Le harnais UDP de Sōzu est aujourd'hui un simulateur synchrone in-tree, adapté au coeur UDP pur, mais la direction générale est la même : workloads déterministes, temps virtuel, seeds reproductibles, et systèmes réseau que l'on peut faire échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le premier bénéfice est la fiabilité. Nous voulons moins de bugs de coin dans le code protocolaire et la reconfiguration. Le deuxième bénéfice est la vitesse de développement. Lorsque davantage de proxy est structuré en machines d'état pures avec des frontières d'I/O explicites, les nouveaux comportements protocole et load balancing deviennent plus sûrs à faire évoluer. Le troisième bénéfice est l'exploitabilité. Hot reload, surcharge et panne deviennent plus faciles à raisonner parce que le code a été exercé sous ces formes exactes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la couche située sous l'edge programmable. Les boutons exposés aux utilisateurs ne valent la peine d'exister que si la mécanique qui les porte est suffisamment déterministe pour inspirer confiance.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que cela rend possible</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour Kubernetes managé, le support UDP donne à Sōzu un meilleur socle pour les services de transport direct. Une plateforme peut proposer du trafic web, des services TCP et des services UDP dans un modèle de load balancing plus cohérent, plutôt que de séparer les responsabilités entre composants sans lien.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour le PaaS, cela ouvre la voie à des fonctionnalités produit autour des workloads datagrammes sans repartir d'une pile opérationnelle séparée. Des services proches de DNS, des flux proches de syslog, des sondes proches de NTP et des applications UDP génériques peuvent être pensés avec le vocabulaire du même proxy : listeners, clusters, backends, health, métriques et reconfiguration à chaud.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour les opérateurs Sōzu hors Clever Cloud, cela signifie que le projet couvre davantage de surface d'edge infrastructure. Si vous utilisez déjà Sōzu parce que vous voulez un proxy open source, reconfigurable à chaud, avec des releases signées et un code Rust auditable, la 2.1.0 élargit la classe de trafic que vous pouvez placer sous ce modèle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La conséquence côté observabilité est également importante. Le trafic UDP dispose désormais de métriques natives dans le proxy. Vous pouvez demander combien de flows sont actifs, combien ont été délestés, pourquoi des datagrammes ont été droppés, si les backends sont healthy et combien de temps vivent les flows. C'est ce qui transforme une fonctionnalité protocolaire en capacité exploitable.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La fiabilité vient aussi de ce qui entoure UDP</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le titre de cette release est UDP, mais la 2.1.0 continue aussi le travail opérationnel de la 2.0.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La reconfiguration à chaud est l'une des promesses centrales de Sōzu, donc la correction du replay d'état compte. Cette release corrige un cas où un listener dont la configuration changeait tout en restant actif pouvait être rejoué comme une suppression suivie d'un ajout sans réémettre l'activation. Ce type de bug explique précisément pourquoi le modèle d'état doit être testé comme un cycle de vie, et pas seulement comme une somme de commandes isolées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La release corrige aussi un panic par underflow arithmétique dans le pattern trie pour des hostnames dont le segment le plus à gauche est une regex. Elle corrige enfin la chaîne de release en pinning le binaire cosign sur la ligne 2.x, après un changement d'outillage ayant cassé le flux des artefacts de signature pendant la release 2.0.2.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce ne sont pas les parties de la release que les utilisateurs verront en premier. Elles font pourtant partie du produit. À l'échelle de Clever Cloud, la tranquillité opérationnelle est un bénéfice client. Un proxy qui se reconfigure correctement, signe ses artefacts de manière prévisible et transforme ses cas limites en tests laisse les applications continuer à servir du trafic pendant que la plateforme bouge sous elles.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La suite</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le support UDP va continuer à mûrir avec l'usage réel. Il y aura de la place pour du travail de performance, du batching et du retour d'expérience opérationnel. Mais la direction plus large est architecturale : rendre davantage de Sōzu déterministe, davantage sans-io lorsque cela a du sens, et davantage de modes de panne reproductibles avant qu'ils ne deviennent des incidents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la leçon de Sōzu 2.1.0. L'edge programmable n'est pas seulement un ensemble de toggles exposés aux utilisateurs. C'est aussi une manière de construire du logiciel d'infrastructure : protocole par protocole, machine d'état par machine d'état, avec assez d'observabilité pour l'exploiter et assez de simulation pour lui faire confiance.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu est un projet open source publié sous AGPL-3.0, avec sa command library sous LGPL-3.0. Le code, les notes de release, les issues et les discussions de conception vivent sur <a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>. Merci aux contributeurs et aux opérateurs qui poussent le projet vers un edge plus large, plus sûr et plus programmable.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Sōzu</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Notes de release Sōzu 2.1.0</strong>. Load balancing UDP de première classe, simulation déterministe, densité d'assertions, CI et documentation. <a href="https://github.com/sozu-proxy/sozu/releases/tag/2.1.0">https://github.com/sozu-proxy/sozu/releases/tag/2.1.0</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC et master plan UDP de Sōzu</strong>. Issue publique de conception pour le load balancing UDP de première classe. <a href="https://github.com/sozu-proxy/sozu/issues/1273">https://github.com/sozu-proxy/sozu/issues/1273</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>PR d'implémentation UDP de Sōzu</strong>. Implémentation des listeners UDP de première classe et du load balancing associé. <a href="https://github.com/sozu-proxy/sozu/pull/1274">https://github.com/sozu-proxy/sozu/pull/1274</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Issue historique sur le load balancing UDP</strong>. Issue publique ouverte en 2020. <a href="https://github.com/sozu-proxy/sozu/issues/654">https://github.com/sozu-proxy/sozu/issues/654</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Sōzu 2.0 : du reverse proxy à l'edge programmable</strong>. Article de release jalon. <a href="https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/">https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de configuration Sōzu</strong>. Listeners UDP, clusters UDP, health checks, PROXY protocol et métriques. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/configure.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/configure.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test Sōzu</strong>. Doctrine de test : unit, e2e, fuzz, simulation déterministe et gardes de régression. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/testing.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de simulation UDP Sōzu</strong>. Sweep par défaut de 256 seeds et knobs de replay. <a href="https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/udp_simulation.md">https://github.com/sozu-proxy/sozu/blob/2.1.0/doc/udp_simulation.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Protocoles et algorithmes</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Spécification PROXY protocol v2</strong>. Propagation de l'adresse client à travers les proxies. <a href="https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt">https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Rendezvous hashing / HRW</strong>. Sélection avec affinité et perturbation minimale lorsque l'ensemble des backends change. <a href="https://en.wikipedia.org/wiki/Rendezvous_hashing">https://en.wikipedia.org/wiki/Rendezvous_hashing</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Maglev: A Fast and Reliable Software Network Load Balancer</strong>. Papier Google décrivant le consistent hashing Maglev. <a href="https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/">https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Tests</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie assertion-first. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Moonpool</strong>. Simulation déterministe pour systèmes distribués en Rust. <a href="https://crates.io/crates/moonpool">https://crates.io/crates/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Moteur de simulation du framework Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Développé par PierreZ. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Sōzu 2.0 : du reverse proxy à l&#8217;edge programmable</title>
		<link>https://www.clever.cloud/fr/blog/engineering-fr/2026/05/29/sozu-2-0-reverse-proxy-edge-programmable/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Fri, 29 May 2026 15:15:50 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[reverse proxy]]></category>
		<guid isPermaLink="false">https://www.clever.cloud/?p=24438</guid>

					<description><![CDATA[<p><img width="2499" height="1109" src="https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.05.29 Clever Cloud Bannière Blog Sōzu 2.0 FR" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr.png 2499w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1368x607.png 1368w" sizes="auto, (max-width: 2499px) 100vw, 2499px" /></p><!-- wp:paragraph -->
<p>Cette version marque une étape : la mécanique sous-jacente est désormais prête à accueillir les fonctionnalités produit que nous voulons bâtir au-dessus. Plutôt qu'une liste de correctifs, nous avons regroupé le travail en six thèmes ; pour chacun, nous disons deux choses — ce qui a été livré, et ce que cela rend possible, pour celles et ceux qui font tourner leurs applications sur la plateforme comme pour les opérateurs qui exécutent Sōzu sur leur propre infrastructure.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">1. Un multiplexer HTTP/2 réécrit intégralement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La pile HTTP/1 de Sōzu avait déjà été réécrite autour de <strong>kawa</strong>, notre format pivot : une représentation interne du message HTTP indépendante de sa version, dans le même esprit que le format HTX de HAProxy. Le multiplexer HTTP/2 en est le prolongement naturel — il étend kawa avec la gestion des sessions et le multiplexing des streams.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Il couvre l'intégralité de la matrice des protocoles (H1↔H1, H1↔H2, H2↔H1, H2↔H2), avec un état de stream partagé, la compression HPACK assurée par loona-hpack, le pooling des connexions HTTP/2 vers les backends, la priorisation des streams selon <a href="https://datatracker.ietf.org/doc/html/rfc9218">RFC 9218</a> Extensible Priorities, et la négociation ALPN par listener, afin que chaque connexion TLS aboutisse sur le bon chemin de code. Environ 181 tests end-to-end et deux cibles de fuzzing (cargo-fuzz) maintiennent le parser et le décodeur HPACK dans le droit chemin — dont des garde-fous de régression qui vérifient octet pour octet l'intégrité des réponses volumineuses sur un trajet « backend HTTP/1 → frontend HTTP/2 », précisément la frontière où se cachent les bugs de readiness en mode edge-triggered d'epoll.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour les clients Clever Cloud, l'incidence concrète est simple : <strong>chaque application servie par la plateforme parle désormais HTTP/2 par défaut, côté frontend</strong> — aucun opt-in, aucune modification de code, aucune configuration. L'activation du HTTP/2 jusqu'au backend reste un choix par cluster — un <em>cluster</em>, dans le modèle de Sōzu, étant l'une de vos applications ; activée de bout en bout, elle débloque notamment gRPC sur toute la chaîne. Les pages s'affichent en moins de connexions TCP ; les navigateurs peuvent mutualiser les requêtes entre les hôtes qui partagent un certificat (nous honorons le SAN coalescing décrit dans la <a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC 7540 §9.1.1</a> : lorsque le certificat, l'autorité d'origine et les conditions de connexion s'y prêtent, Firefox et Chrome peuvent réutiliser une seule connexion vers vos cdn.example.com et assets.example.com au lieu d'en ouvrir plusieurs en parallèle). Il s'agit, au meilleur sens du terme, d'une mise à niveau silencieuse de la plateforme.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi le prérequis structurel pour la suite — HTTP/3 sur QUIC et des fondations de streaming plus solides à l'edge. La réécriture du multiplexer est la pièce de la roadmap qui devait advenir en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">2. La sécurité pour socle, non comme option</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La seconde moitié de la réécriture HTTP/2 est celle dont personne ne réclame l'existence tant qu'elle ne fait pas défaut : la résistance aux floods et aux attaques par déni de service. Sōzu 2.0 embarque des mitigations natives pour les vulnérabilités <a href="https://nvd.nist.gov/vuln/detail/CVE-2023-44487"><strong>CVE-2023-44487</strong></a><strong> (Rapid Reset)</strong>, <a href="https://nvd.nist.gov/vuln/detail/CVE-2024-27316"><strong>CVE-2024-27316</strong></a><strong> (CONTINUATION flood)</strong>, <a href="https://nvd.nist.gov/vuln/detail/CVE-2025-8671"><strong>CVE-2025-8671</strong></a><strong> (MadeYouReset)</strong>, ainsi que pour la famille PING / SETTINGS / empty-DATA des <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9512">CVE-2019-9512</a>/<a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9515">CVE-2019-9515</a>/<a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9518">CVE-2019-9518</a>. Chaque mitigation expose un counter dédié — douze métriques sous h2.flood.violation.* — afin qu'un SIEM puisse mesurer en fenêtre glissante le taux de déclenchement, sans avoir à parser les logs. Dix-sept motifs de rejet HPACK sont exposés selon le même principe ; il s'agit du premier signal observable côté opérateur pour les tentatives de request smuggling contre la pile HTTP/2.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le reste du travail de sécurité se déploie à travers le proxy : un plafond de connexions par couple (cluster, IP source) assorti d'une réponse 429 Too Many Requests ; une éviction optionnelle des sessions les plus anciennes lorsque l'accept queue sature ; un durcissement du command channel, du parser HTTP/1, du pattern-trie router (fermeture d'un contournement de routing via regex non ancrées) et du wildcard matcher ; un assainissement du pipeline d'audit contre les séquences <a href="https://nvd.nist.gov/vuln/detail/CVE-2021-42574">Trojan-Source</a> et le SIEM column-smuggling ; et une rotation à chaud des certificats TLS qui <strong>ne laisse jamais tomber le certificat fonctionnel en cas d'échec</strong>, quand bien même le nouveau serait malformé. Quatre security advisories de dépendances purgées au cours de la même fenêtre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chaque mutation privilégiée atterrit désormais dans un journal d'audit structuré : chaque action du plan de contrôle est consignée sous la forme d'une ligne Command(verb=…, actor_uid=…, actor_user=…, result=…) — qui a fait quoi, depuis où, et avec quel résultat. Deux sinks dédiés l'exportent : audit_logs_target pour le flux lisible, et audit_logs_json_target pour un objet JSON à schéma stable par ligne, de sorte que la piste se déverse directement dans un SIEM (Wazuh, Elastic, Loki, Splunk) sans parser sur mesure — dans un format pensé pour PCI-DSS 10.5.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le cadrage produit est limpide : <strong>notre métier, c'est d'opérer la plateforme et de protéger vos applications dès que nous le pouvons</strong>. Lorsque la prochaine vulnérabilité HTTP/2 de cette classe paraît un vendredi à vingt-et-une heures, elle n'a pas à se traduire par un week-end de correctifs et de redéploiements sur des milliers d'applications : les attaques de cette classe sont largement absorbées ou atténuées au niveau du proxy, un counter s'incrémente sur un dashboard, et les applications continuent de servir leur trafic. Le « trust-by-default » n'est pas un slogan : c'est l'effet cumulé de dizaines de petits correctifs défensifs, livrés à la couche où la frontière de sécurité se joue véritablement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">3. De la visibilité à chaque couche</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'ajout le plus visible pour l'utilisateur en 2.0 est <strong>sozu top</strong> — une TUI opérateur (derrière le feature flag Cargo tui) qui offre une vue en temps réel, à la manière de btop ou htop, sur sept panes : Overview, Clusters, Backends, Listeners, H2, Certificates, Events. Palette accessible aux personnes daltoniennes, thèmes personnalisables : l'essentiel tient dans un terminal, sans dashboard externe.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sous la TUI, la surface des métriques elle-même a été refondue. Le multiplexer expose des counters par type de frame et par code d'erreur <a href="https://datatracker.ietf.org/doc/html/rfc9113">RFC 9113</a>, la télémétrie des handshakes TLS, des counters HTTP par status code, et de nouvelles gauges de cycle de vie du worker. L'access log gagne les champs TLS et de forwarding (version, cipher, SNI, ALPN, chaîne XFF), la propagation x_request_id de bout en bout, ainsi que les RTT client et serveur — de quoi corréler une requête d'un hop à l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Une nouvelle commande, SetMetricDetail, permet à un opérateur d'élever à la demande la cardinalité des métriques, via un lease à durée limitée qui expire : la production reste à faible cardinalité par défaut, et l'inspection fine devient une décision ponctuelle plutôt qu'une réécriture de configuration.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour Clever Cloud, c'est le socle du <strong>prochain chapitre de l'observabilité tournée vers le client</strong> — percentiles de latence par application, disponibilité par cluster, décomposition des handshakes TLS, request IDs traçables d'un hop à l'autre. Les métriques existent désormais au niveau du proxy. L'étape suivante consiste à les exposer dans la console Clever Cloud, à leur juste place, aux côtés des vues de build et de déploiement — afin qu'aucun APM externe ne soit nécessaire pour comprendre le trafic que votre application reçoit véritablement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">4. Des policies de trafic enfin actionnables d'un geste</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu 2.0 refond l'intégralité de la surface des policies côté frontend (#1231) : <strong>HSTS typé</strong> (<a href="https://datatracker.ietf.org/doc/html/rfc6797">RFC 6797</a>), configurable par listener et par frontend ; <strong>URL rewrite</strong> (host, path, port) avec propagation des regex captures depuis le routing trie vers les rewrite templates ; <strong>réécriture des headers</strong> de requête et de réponse par frontend — ajouter, modifier ou supprimer n'importe quel header (une valeur vide le supprime, parité avec le del-header de HAProxy), avec en complément l'injection de X-Real-IP au niveau listener et l'élision anti-spoofing des valeurs fournies par le client ; <strong>redirects HTTP 301 / 302 / 308</strong> au travers d'une enum typée RedirectPolicy ; et l'<strong>authentification HTTP Basic</strong> par frontend, avec des credentials hashés en SHA-256 et une comparaison constant-time assurée par la crate subtle (le credential boundary est durci contre les side-channels temporels — la code review l'avait identifié).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la partie de la release où l'opportunité produit est la plus saillante. Aujourd'hui, mener une migration de domaine propre sur une plateforme managée requiert typiquement soit un backend sachant rediriger, soit un service de redirection déployé en parallèle ; placer une URL de preview derrière un mot de passe requiert typiquement un add-on d'authentification. <strong>Avec Sōzu 2.0, ces usages deviennent des boutons sur le proxy.</strong> La plomberie existe ; ce qu'il reste à accomplir, c'est d'exposer ces boutons dans la console Clever Cloud — sous la forme d'une case à cocher sur un domaine, ou d'un toggle à clic unique pour les preview environments. C'est la surface no-code de contrôle du trafic que nous voulons construire ensuite.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">5. L'exploitation comme bénéfice pour le client</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Une réécriture de cette profondeur ne se livre sereinement que si la flotte demeure en mouvement en dessous. L'exploitation au quotidien a reçu une attention particulière en 2.0.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>sozu listener {http,https,tcp} update est un nouveau patch verb field-masked qui ajuste à la volée les paramètres d'un listener modifiables sans recycler les sockets sous-jacents : seuils de flood HTTP/2, SNI binding, préférence ALPN, idle timeouts, HSTS, custom answers. <strong>Les mitigations CVE peuvent désormais être resserrées sous attaque sans recycler les sockets d'écoute.</strong> Les health checks actifs des backends s'exécutent à l'intérieur de la loop d'événements mio existante (aucun scheduler async, aucun thread supplémentaire), avec des sondes HTTP/1.1 et HTTP/2, des intervalles dotés d'un léger jitter, et un fail-open path qui achemine à travers les backends au statut Normal dont la retry policy l'autorise. L'intégration systemd (qui clôt #228) effectue enfin ce qu'il convient : des units Type=notify, un READY=1 envoyé seulement après la création des workers initiaux et le replay de l'état sauvegardé, un STOPPING=1 lors du graceful shutdown, un MAINPID=&lt;nouveau&gt; lors des hot upgrades.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les releases elles-mêmes ont changé de forme. Pousser un tag produit désormais <strong>dix tarballs pré-compilés</strong> (trois cibles Linux croisées avec jusqu'à quatre crypto providers), signés keyless via sigstore (cosign + GitHub OIDC), accompagnés d'une attestation SLSA build provenance et d'un pointeur SOURCE.txt vers le code source correspondant satisfaisant l'AGPL §6 et la LGPL §4 — refermant ainsi l'écart noté dans #1089. Les fichiers fullchain.pem ACME se chargent à présent proprement, y compris lorsque le client a émis le leaf en tête de chaîne (Certbot, lego, acme.sh) ; une race condition vieille de six ans sur l'auto-restart des workers (#515) est corrigée par pinning de l'inode original au moyen de /proc/self/fd. Le verbe IPC LoadState demeure forward-compatible avec les clients sozu-command-lib 1.1.1, de sorte que l'écosystème d'intégrations ne se brise pas lors de l'upgrade.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>À l'échelle de Clever Cloud, le coût d'un incident d'exploitation ne se mesure pas en tickets — il s'agit d'une latence qui s'accumule sur des milliers d'applications, et du temps d'ingénierie que nous devons à la construction de l'étape suivante. <strong>Sōzu 2.0 est le proxy qui se laisse exploiter en silence, et cette tranquillité est ce que les clients vivent comme de l'uptime.</strong> C'est également ce qui rend Sōzu crédible comme outil que l'on peut exécuter sur sa propre infrastructure : binaires signés, hot reloads, particularités ACME absorbées, intégration systemd menée correctement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">6. Une crypto prête pour demain</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La pile TLS a reçu une refonte plus discrète, mais d'égale importance (#1191). Sōzu prend désormais en charge <strong>quatre crypto providers pluggables</strong> pour rustls : crypto-ring (par défaut), crypto-aws-lc-rs, crypto-openssl, et fips (qui implique aws-lc-rs en mode FIPS). Les quatre sont exercés par la CI, et la precedence chain fips &gt; ring &gt; aws-lc-rs &gt; openssl résout le provider actif de manière déterministe lorsque plusieurs features sont activées simultanément.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce dont nous sommes le plus satisfaits, en revanche, est le groups_list par défaut : <strong>X25519MLKEM768</strong><strong> est désormais le groupe d'échange de clés en première préférence</strong> lorsque le provider le prend en charge. Il s'agit de l'hybride post-quantique en cours de normalisation à l'IETF (<a href="https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem">draft-ietf-tls-ecdhe-mlkem</a>), déjà enregistré dans le registre TLS de l'IANA ; en pratique, cela signifie qu'un client uniquement compatible X25519 et un client post-quantum négocient l'un comme l'autre l'échange le plus robuste mutuellement pris en charge, sans aucune action de l'opérateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsque la transition post-quantique deviendra une exigence réglementaire — selon un calendrier dont l'industrie débat encore — <strong>les fondations seront déjà en place sur Clever Cloud</strong> : tout client TLS 1.3 qui propose l'hybride le négocie dès aujourd'hui, sans action de l'opérateur. Nous avons effectué ce choix en silence, et nous l'avons inscrit par défaut.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Du reverse proxy à l'edge programmable</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu a toujours été un <strong>load balancer d'infrastructure</strong> : bien au-delà du HTTP, il équilibre aussi du TCP brut, avec un chemin de forwarding zéro-copie via splice(2) sous Linux pour les listeners TCP. Avec la 2.0, il se rapproche d'une <strong>API gateway</strong> et devient le substrat d'un <strong>edge programmable</strong> — et « programmable » est le mot qui compte. Chaque capacité décrite ci-dessus (HTTP/2 par défaut, contrôles anti-abus, observabilité, policies de trafic, crypto agility, calme opérationnel) est un bouton. L'année qui vient de la roadmap Clever Cloud consiste à exposer ces boutons sous la forme de features produit : à travers la console, à travers l'API, à travers les workflows que vous utilisez déjà pour déployer vos applications.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Voilà ce que nous voulons dire lorsque nous affirmons que Sōzu 2.0 est un premier pas vers quelque chose de plus grand. La 2.0 n'est pas la destination — c'est la plateforme sur laquelle nous bâtissons désormais. Le HTTP/2 managé, partout, en constitue la première brique. La deuxième : une console permettant d'activer HSTS, de protéger par mot de passe un preview environment, ou de rediriger un domaine migré. L'aboutissement — un edge entièrement programmable, doté de policy primitives que vous composez — est ce vers quoi nous bâtissons au fil du prochain release cycle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Deux chantiers sont déjà sur l'établi. D'abord, un volet <strong>load balancing UDP</strong> — dans l'esprit d'IPVS, mais avec le rechargement à chaud propre à Sōzu — assorti de <strong>health checks TCP</strong> pour valider la disponibilité des backends UDP ; de quoi ancrer un peu plus le rôle de load balancer d'infrastructure. Ensuite, des <strong>backends joignables en HTTPS</strong>, qui consolident la connectivité amont et ouvrent la voie à l'API gateway.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu est un projet open source publié sous AGPL-3.0 (la command library est diffusée sous LGPL-3.0). Les binaires de la version 2.0 sont signés via sigstore et embarquent une attestation SLSA ; si vous opérez votre propre edge, cette version vous appartient : à utiliser, à auditer, à étendre. Le code, l'issue tracker, et les conversations vivent à l'adresse <a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Nous remercions les contributeurs qui ont rendu cette release possible — ainsi que toutes celles et ceux qui exécutent Sōzu en production, dont les retours guident la suite.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Standards et spécifications</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>RFC 6797</strong> — HTTP Strict Transport Security (HSTS). <a href="https://datatracker.ietf.org/doc/html/rfc6797">https://datatracker.ietf.org/doc/html/rfc6797</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 7540</strong> — Hypertext Transfer Protocol Version 2 (HTTP/2). Désormais obsolétée par la RFC 9113, mais le §9.1.1 sur le connection coalescing demeure la citation reprise par la RFC 9113. <a href="https://datatracker.ietf.org/doc/html/rfc7540">https://datatracker.ietf.org/doc/html/rfc7540</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 9113</strong> — HTTP/2 (en vigueur). §5 streams, §6 frames, §6.8 GOAWAY, §7 codes d'erreur, §8.1 sémantique HTTP. <a href="https://datatracker.ietf.org/doc/html/rfc9113">https://datatracker.ietf.org/doc/html/rfc9113</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 9218</strong> — Extensible Prioritization Scheme for HTTP. <a href="https://datatracker.ietf.org/doc/html/rfc9218">https://datatracker.ietf.org/doc/html/rfc9218</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>draft-ietf-tls-ecdhe-mlkem</strong> — Hybrid key exchange in TLS 1.3 : X25519MLKEM768 (Internet-Draft IETF, enregistré à l'IANA ; l'hybride post-quantique que Sōzu privilégie par défaut). <a href="https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem">https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">CVE</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>CVE-2019-9512</strong> — HTTP/2 Ping Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9512">https://nvd.nist.gov/vuln/detail/CVE-2019-9512</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2019-9515</strong> — HTTP/2 Settings Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9515">https://nvd.nist.gov/vuln/detail/CVE-2019-9515</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2019-9518</strong> — HTTP/2 Empty Frames Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9518">https://nvd.nist.gov/vuln/detail/CVE-2019-9518</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2021-42574</strong> — Trojan Source (bidirectional override). <a href="https://nvd.nist.gov/vuln/detail/CVE-2021-42574">https://nvd.nist.gov/vuln/detail/CVE-2021-42574</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2023-44487</strong> — HTTP/2 Rapid Reset. <a href="https://nvd.nist.gov/vuln/detail/CVE-2023-44487">https://nvd.nist.gov/vuln/detail/CVE-2023-44487</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2024-27316</strong> — HTTP/2 CONTINUATION Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2024-27316">https://nvd.nist.gov/vuln/detail/CVE-2024-27316</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2025-8671</strong> — MadeYouReset (HTTP/2). <a href="https://nvd.nist.gov/vuln/detail/CVE-2025-8671">https://nvd.nist.gov/vuln/detail/CVE-2025-8671</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Pour aller plus loin</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Cloudflare</strong> — <em>HTTP/2 Rapid Reset: deconstructing the record-breaking attack</em>. Le compte rendu canonique de la divulgation coordonnée d'octobre 2023, incluant la mécanique de l'attaque ainsi que le pic de 398 millions de rps capturé en direct. <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/">https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>HAProxy Technologies</strong> — <em>HAProxy is Not Affected by the HTTP/2 Rapid Reset Attack (CVE-2023-44487)</em>. L'argument structurel de HAProxy quant à la raison pour laquelle son cycle de vie de stream absorbe naturellement le Rapid Reset ; un contraste utile face à l'approche par counters de flood retenue par Sōzu. <a href="https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487">https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Cloudflare blog — série Post-quantum</strong>. Couverture pluriannuelle assurée par Bas Westerbaan et ses collaborateurs sur l'échange de clés post-quantique et les groupes hybrides ; filiation de l'hybride X25519MLKEM768 que Sōzu négocie désormais par défaut. <a href="https://blog.cloudflare.com/tag/post-quantum/">https://blog.cloudflare.com/tag/post-quantum/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Cloudflare Learning Center</strong> — <em>What is HSTS?</em>. Primer accessible sur HSTS, la sémantique max-age / includeSubDomains / preload, et la politique de la HSTS preload list.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></description>
										<content:encoded><![CDATA[<p><img width="2499" height="1109" src="https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.05.29 Clever Cloud Bannière Blog Sōzu 2.0 FR" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr.png 2499w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/05/2026-05-29-clever-cloud-banniere-blog-sozu-2-0-fr-1368x607.png 1368w" sizes="auto, (max-width: 2499px) 100vw, 2499px" /></p><!-- wp:paragraph -->
<p>Cette version marque une étape : la mécanique sous-jacente est désormais prête à accueillir les fonctionnalités produit que nous voulons bâtir au-dessus. Plutôt qu'une liste de correctifs, nous avons regroupé le travail en six thèmes ; pour chacun, nous disons deux choses — ce qui a été livré, et ce que cela rend possible, pour celles et ceux qui font tourner leurs applications sur la plateforme comme pour les opérateurs qui exécutent Sōzu sur leur propre infrastructure.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">1. Un multiplexer HTTP/2 réécrit intégralement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La pile HTTP/1 de Sōzu avait déjà été réécrite autour de <strong>kawa</strong>, notre format pivot : une représentation interne du message HTTP indépendante de sa version, dans le même esprit que le format HTX de HAProxy. Le multiplexer HTTP/2 en est le prolongement naturel — il étend kawa avec la gestion des sessions et le multiplexing des streams.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Il couvre l'intégralité de la matrice des protocoles (H1↔H1, H1↔H2, H2↔H1, H2↔H2), avec un état de stream partagé, la compression HPACK assurée par loona-hpack, le pooling des connexions HTTP/2 vers les backends, la priorisation des streams selon <a href="https://datatracker.ietf.org/doc/html/rfc9218">RFC 9218</a> Extensible Priorities, et la négociation ALPN par listener, afin que chaque connexion TLS aboutisse sur le bon chemin de code. Environ 181 tests end-to-end et deux cibles de fuzzing (cargo-fuzz) maintiennent le parser et le décodeur HPACK dans le droit chemin — dont des garde-fous de régression qui vérifient octet pour octet l'intégrité des réponses volumineuses sur un trajet « backend HTTP/1 → frontend HTTP/2 », précisément la frontière où se cachent les bugs de readiness en mode edge-triggered d'epoll.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour les clients Clever Cloud, l'incidence concrète est simple : <strong>chaque application servie par la plateforme parle désormais HTTP/2 par défaut, côté frontend</strong> — aucun opt-in, aucune modification de code, aucune configuration. L'activation du HTTP/2 jusqu'au backend reste un choix par cluster — un <em>cluster</em>, dans le modèle de Sōzu, étant l'une de vos applications ; activée de bout en bout, elle débloque notamment gRPC sur toute la chaîne. Les pages s'affichent en moins de connexions TCP ; les navigateurs peuvent mutualiser les requêtes entre les hôtes qui partagent un certificat (nous honorons le SAN coalescing décrit dans la <a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC 7540 §9.1.1</a> : lorsque le certificat, l'autorité d'origine et les conditions de connexion s'y prêtent, Firefox et Chrome peuvent réutiliser une seule connexion vers vos cdn.example.com et assets.example.com au lieu d'en ouvrir plusieurs en parallèle). Il s'agit, au meilleur sens du terme, d'une mise à niveau silencieuse de la plateforme.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi le prérequis structurel pour la suite — HTTP/3 sur QUIC et des fondations de streaming plus solides à l'edge. La réécriture du multiplexer est la pièce de la roadmap qui devait advenir en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">2. La sécurité pour socle, non comme option</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La seconde moitié de la réécriture HTTP/2 est celle dont personne ne réclame l'existence tant qu'elle ne fait pas défaut : la résistance aux floods et aux attaques par déni de service. Sōzu 2.0 embarque des mitigations natives pour les vulnérabilités <a href="https://nvd.nist.gov/vuln/detail/CVE-2023-44487"><strong>CVE-2023-44487</strong></a><strong> (Rapid Reset)</strong>, <a href="https://nvd.nist.gov/vuln/detail/CVE-2024-27316"><strong>CVE-2024-27316</strong></a><strong> (CONTINUATION flood)</strong>, <a href="https://nvd.nist.gov/vuln/detail/CVE-2025-8671"><strong>CVE-2025-8671</strong></a><strong> (MadeYouReset)</strong>, ainsi que pour la famille PING / SETTINGS / empty-DATA des <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9512">CVE-2019-9512</a>/<a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9515">CVE-2019-9515</a>/<a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9518">CVE-2019-9518</a>. Chaque mitigation expose un counter dédié — douze métriques sous h2.flood.violation.* — afin qu'un SIEM puisse mesurer en fenêtre glissante le taux de déclenchement, sans avoir à parser les logs. Dix-sept motifs de rejet HPACK sont exposés selon le même principe ; il s'agit du premier signal observable côté opérateur pour les tentatives de request smuggling contre la pile HTTP/2.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le reste du travail de sécurité se déploie à travers le proxy : un plafond de connexions par couple (cluster, IP source) assorti d'une réponse 429 Too Many Requests ; une éviction optionnelle des sessions les plus anciennes lorsque l'accept queue sature ; un durcissement du command channel, du parser HTTP/1, du pattern-trie router (fermeture d'un contournement de routing via regex non ancrées) et du wildcard matcher ; un assainissement du pipeline d'audit contre les séquences <a href="https://nvd.nist.gov/vuln/detail/CVE-2021-42574">Trojan-Source</a> et le SIEM column-smuggling ; et une rotation à chaud des certificats TLS qui <strong>ne laisse jamais tomber le certificat fonctionnel en cas d'échec</strong>, quand bien même le nouveau serait malformé. Quatre security advisories de dépendances purgées au cours de la même fenêtre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chaque mutation privilégiée atterrit désormais dans un journal d'audit structuré : chaque action du plan de contrôle est consignée sous la forme d'une ligne Command(verb=…, actor_uid=…, actor_user=…, result=…) — qui a fait quoi, depuis où, et avec quel résultat. Deux sinks dédiés l'exportent : audit_logs_target pour le flux lisible, et audit_logs_json_target pour un objet JSON à schéma stable par ligne, de sorte que la piste se déverse directement dans un SIEM (Wazuh, Elastic, Loki, Splunk) sans parser sur mesure — dans un format pensé pour PCI-DSS 10.5.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le cadrage produit est limpide : <strong>notre métier, c'est d'opérer la plateforme et de protéger vos applications dès que nous le pouvons</strong>. Lorsque la prochaine vulnérabilité HTTP/2 de cette classe paraît un vendredi à vingt-et-une heures, elle n'a pas à se traduire par un week-end de correctifs et de redéploiements sur des milliers d'applications : les attaques de cette classe sont largement absorbées ou atténuées au niveau du proxy, un counter s'incrémente sur un dashboard, et les applications continuent de servir leur trafic. Le « trust-by-default » n'est pas un slogan : c'est l'effet cumulé de dizaines de petits correctifs défensifs, livrés à la couche où la frontière de sécurité se joue véritablement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">3. De la visibilité à chaque couche</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'ajout le plus visible pour l'utilisateur en 2.0 est <strong>sozu top</strong> — une TUI opérateur (derrière le feature flag Cargo tui) qui offre une vue en temps réel, à la manière de btop ou htop, sur sept panes : Overview, Clusters, Backends, Listeners, H2, Certificates, Events. Palette accessible aux personnes daltoniennes, thèmes personnalisables : l'essentiel tient dans un terminal, sans dashboard externe.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sous la TUI, la surface des métriques elle-même a été refondue. Le multiplexer expose des counters par type de frame et par code d'erreur <a href="https://datatracker.ietf.org/doc/html/rfc9113">RFC 9113</a>, la télémétrie des handshakes TLS, des counters HTTP par status code, et de nouvelles gauges de cycle de vie du worker. L'access log gagne les champs TLS et de forwarding (version, cipher, SNI, ALPN, chaîne XFF), la propagation x_request_id de bout en bout, ainsi que les RTT client et serveur — de quoi corréler une requête d'un hop à l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Une nouvelle commande, SetMetricDetail, permet à un opérateur d'élever à la demande la cardinalité des métriques, via un lease à durée limitée qui expire : la production reste à faible cardinalité par défaut, et l'inspection fine devient une décision ponctuelle plutôt qu'une réécriture de configuration.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour Clever Cloud, c'est le socle du <strong>prochain chapitre de l'observabilité tournée vers le client</strong> — percentiles de latence par application, disponibilité par cluster, décomposition des handshakes TLS, request IDs traçables d'un hop à l'autre. Les métriques existent désormais au niveau du proxy. L'étape suivante consiste à les exposer dans la console Clever Cloud, à leur juste place, aux côtés des vues de build et de déploiement — afin qu'aucun APM externe ne soit nécessaire pour comprendre le trafic que votre application reçoit véritablement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">4. Des policies de trafic enfin actionnables d'un geste</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu 2.0 refond l'intégralité de la surface des policies côté frontend (#1231) : <strong>HSTS typé</strong> (<a href="https://datatracker.ietf.org/doc/html/rfc6797">RFC 6797</a>), configurable par listener et par frontend ; <strong>URL rewrite</strong> (host, path, port) avec propagation des regex captures depuis le routing trie vers les rewrite templates ; <strong>réécriture des headers</strong> de requête et de réponse par frontend — ajouter, modifier ou supprimer n'importe quel header (une valeur vide le supprime, parité avec le del-header de HAProxy), avec en complément l'injection de X-Real-IP au niveau listener et l'élision anti-spoofing des valeurs fournies par le client ; <strong>redirects HTTP 301 / 302 / 308</strong> au travers d'une enum typée RedirectPolicy ; et l'<strong>authentification HTTP Basic</strong> par frontend, avec des credentials hashés en SHA-256 et une comparaison constant-time assurée par la crate subtle (le credential boundary est durci contre les side-channels temporels — la code review l'avait identifié).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la partie de la release où l'opportunité produit est la plus saillante. Aujourd'hui, mener une migration de domaine propre sur une plateforme managée requiert typiquement soit un backend sachant rediriger, soit un service de redirection déployé en parallèle ; placer une URL de preview derrière un mot de passe requiert typiquement un add-on d'authentification. <strong>Avec Sōzu 2.0, ces usages deviennent des boutons sur le proxy.</strong> La plomberie existe ; ce qu'il reste à accomplir, c'est d'exposer ces boutons dans la console Clever Cloud — sous la forme d'une case à cocher sur un domaine, ou d'un toggle à clic unique pour les preview environments. C'est la surface no-code de contrôle du trafic que nous voulons construire ensuite.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">5. L'exploitation comme bénéfice pour le client</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Une réécriture de cette profondeur ne se livre sereinement que si la flotte demeure en mouvement en dessous. L'exploitation au quotidien a reçu une attention particulière en 2.0.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>sozu listener {http,https,tcp} update est un nouveau patch verb field-masked qui ajuste à la volée les paramètres d'un listener modifiables sans recycler les sockets sous-jacents : seuils de flood HTTP/2, SNI binding, préférence ALPN, idle timeouts, HSTS, custom answers. <strong>Les mitigations CVE peuvent désormais être resserrées sous attaque sans recycler les sockets d'écoute.</strong> Les health checks actifs des backends s'exécutent à l'intérieur de la loop d'événements mio existante (aucun scheduler async, aucun thread supplémentaire), avec des sondes HTTP/1.1 et HTTP/2, des intervalles dotés d'un léger jitter, et un fail-open path qui achemine à travers les backends au statut Normal dont la retry policy l'autorise. L'intégration systemd (qui clôt #228) effectue enfin ce qu'il convient : des units Type=notify, un READY=1 envoyé seulement après la création des workers initiaux et le replay de l'état sauvegardé, un STOPPING=1 lors du graceful shutdown, un MAINPID=&lt;nouveau&gt; lors des hot upgrades.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les releases elles-mêmes ont changé de forme. Pousser un tag produit désormais <strong>dix tarballs pré-compilés</strong> (trois cibles Linux croisées avec jusqu'à quatre crypto providers), signés keyless via sigstore (cosign + GitHub OIDC), accompagnés d'une attestation SLSA build provenance et d'un pointeur SOURCE.txt vers le code source correspondant satisfaisant l'AGPL §6 et la LGPL §4 — refermant ainsi l'écart noté dans #1089. Les fichiers fullchain.pem ACME se chargent à présent proprement, y compris lorsque le client a émis le leaf en tête de chaîne (Certbot, lego, acme.sh) ; une race condition vieille de six ans sur l'auto-restart des workers (#515) est corrigée par pinning de l'inode original au moyen de /proc/self/fd. Le verbe IPC LoadState demeure forward-compatible avec les clients sozu-command-lib 1.1.1, de sorte que l'écosystème d'intégrations ne se brise pas lors de l'upgrade.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>À l'échelle de Clever Cloud, le coût d'un incident d'exploitation ne se mesure pas en tickets — il s'agit d'une latence qui s'accumule sur des milliers d'applications, et du temps d'ingénierie que nous devons à la construction de l'étape suivante. <strong>Sōzu 2.0 est le proxy qui se laisse exploiter en silence, et cette tranquillité est ce que les clients vivent comme de l'uptime.</strong> C'est également ce qui rend Sōzu crédible comme outil que l'on peut exécuter sur sa propre infrastructure : binaires signés, hot reloads, particularités ACME absorbées, intégration systemd menée correctement.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">6. Une crypto prête pour demain</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La pile TLS a reçu une refonte plus discrète, mais d'égale importance (#1191). Sōzu prend désormais en charge <strong>quatre crypto providers pluggables</strong> pour rustls : crypto-ring (par défaut), crypto-aws-lc-rs, crypto-openssl, et fips (qui implique aws-lc-rs en mode FIPS). Les quatre sont exercés par la CI, et la precedence chain fips &gt; ring &gt; aws-lc-rs &gt; openssl résout le provider actif de manière déterministe lorsque plusieurs features sont activées simultanément.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce dont nous sommes le plus satisfaits, en revanche, est le groups_list par défaut : <strong>X25519MLKEM768</strong><strong> est désormais le groupe d'échange de clés en première préférence</strong> lorsque le provider le prend en charge. Il s'agit de l'hybride post-quantique en cours de normalisation à l'IETF (<a href="https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem">draft-ietf-tls-ecdhe-mlkem</a>), déjà enregistré dans le registre TLS de l'IANA ; en pratique, cela signifie qu'un client uniquement compatible X25519 et un client post-quantum négocient l'un comme l'autre l'échange le plus robuste mutuellement pris en charge, sans aucune action de l'opérateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsque la transition post-quantique deviendra une exigence réglementaire — selon un calendrier dont l'industrie débat encore — <strong>les fondations seront déjà en place sur Clever Cloud</strong> : tout client TLS 1.3 qui propose l'hybride le négocie dès aujourd'hui, sans action de l'opérateur. Nous avons effectué ce choix en silence, et nous l'avons inscrit par défaut.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Du reverse proxy à l'edge programmable</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sōzu a toujours été un <strong>load balancer d'infrastructure</strong> : bien au-delà du HTTP, il équilibre aussi du TCP brut, avec un chemin de forwarding zéro-copie via splice(2) sous Linux pour les listeners TCP. Avec la 2.0, il se rapproche d'une <strong>API gateway</strong> et devient le substrat d'un <strong>edge programmable</strong> — et « programmable » est le mot qui compte. Chaque capacité décrite ci-dessus (HTTP/2 par défaut, contrôles anti-abus, observabilité, policies de trafic, crypto agility, calme opérationnel) est un bouton. L'année qui vient de la roadmap Clever Cloud consiste à exposer ces boutons sous la forme de features produit : à travers la console, à travers l'API, à travers les workflows que vous utilisez déjà pour déployer vos applications.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Voilà ce que nous voulons dire lorsque nous affirmons que Sōzu 2.0 est un premier pas vers quelque chose de plus grand. La 2.0 n'est pas la destination — c'est la plateforme sur laquelle nous bâtissons désormais. Le HTTP/2 managé, partout, en constitue la première brique. La deuxième : une console permettant d'activer HSTS, de protéger par mot de passe un preview environment, ou de rediriger un domaine migré. L'aboutissement — un edge entièrement programmable, doté de policy primitives que vous composez — est ce vers quoi nous bâtissons au fil du prochain release cycle.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Deux chantiers sont déjà sur l'établi. D'abord, un volet <strong>load balancing UDP</strong> — dans l'esprit d'IPVS, mais avec le rechargement à chaud propre à Sōzu — assorti de <strong>health checks TCP</strong> pour valider la disponibilité des backends UDP ; de quoi ancrer un peu plus le rôle de load balancer d'infrastructure. Ensuite, des <strong>backends joignables en HTTPS</strong>, qui consolident la connectivité amont et ouvrent la voie à l'API gateway.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sōzu est un projet open source publié sous AGPL-3.0 (la command library est diffusée sous LGPL-3.0). Les binaires de la version 2.0 sont signés via sigstore et embarquent une attestation SLSA ; si vous opérez votre propre edge, cette version vous appartient : à utiliser, à auditer, à étendre. Le code, l'issue tracker, et les conversations vivent à l'adresse <a href="https://github.com/sozu-proxy/sozu">github.com/sozu-proxy/sozu</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Nous remercions les contributeurs qui ont rendu cette release possible — ainsi que toutes celles et ceux qui exécutent Sōzu en production, dont les retours guident la suite.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Standards et spécifications</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>RFC 6797</strong> — HTTP Strict Transport Security (HSTS). <a href="https://datatracker.ietf.org/doc/html/rfc6797">https://datatracker.ietf.org/doc/html/rfc6797</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 7540</strong> — Hypertext Transfer Protocol Version 2 (HTTP/2). Désormais obsolétée par la RFC 9113, mais le §9.1.1 sur le connection coalescing demeure la citation reprise par la RFC 9113. <a href="https://datatracker.ietf.org/doc/html/rfc7540">https://datatracker.ietf.org/doc/html/rfc7540</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 9113</strong> — HTTP/2 (en vigueur). §5 streams, §6 frames, §6.8 GOAWAY, §7 codes d'erreur, §8.1 sémantique HTTP. <a href="https://datatracker.ietf.org/doc/html/rfc9113">https://datatracker.ietf.org/doc/html/rfc9113</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>RFC 9218</strong> — Extensible Prioritization Scheme for HTTP. <a href="https://datatracker.ietf.org/doc/html/rfc9218">https://datatracker.ietf.org/doc/html/rfc9218</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>draft-ietf-tls-ecdhe-mlkem</strong> — Hybrid key exchange in TLS 1.3 : X25519MLKEM768 (Internet-Draft IETF, enregistré à l'IANA ; l'hybride post-quantique que Sōzu privilégie par défaut). <a href="https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem">https://datatracker.ietf.org/doc/html/draft-ietf-tls-ecdhe-mlkem</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">CVE</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>CVE-2019-9512</strong> — HTTP/2 Ping Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9512">https://nvd.nist.gov/vuln/detail/CVE-2019-9512</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2019-9515</strong> — HTTP/2 Settings Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9515">https://nvd.nist.gov/vuln/detail/CVE-2019-9515</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2019-9518</strong> — HTTP/2 Empty Frames Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2019-9518">https://nvd.nist.gov/vuln/detail/CVE-2019-9518</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2021-42574</strong> — Trojan Source (bidirectional override). <a href="https://nvd.nist.gov/vuln/detail/CVE-2021-42574">https://nvd.nist.gov/vuln/detail/CVE-2021-42574</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2023-44487</strong> — HTTP/2 Rapid Reset. <a href="https://nvd.nist.gov/vuln/detail/CVE-2023-44487">https://nvd.nist.gov/vuln/detail/CVE-2023-44487</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2024-27316</strong> — HTTP/2 CONTINUATION Flood. <a href="https://nvd.nist.gov/vuln/detail/CVE-2024-27316">https://nvd.nist.gov/vuln/detail/CVE-2024-27316</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>CVE-2025-8671</strong> — MadeYouReset (HTTP/2). <a href="https://nvd.nist.gov/vuln/detail/CVE-2025-8671">https://nvd.nist.gov/vuln/detail/CVE-2025-8671</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Pour aller plus loin</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Cloudflare</strong> — <em>HTTP/2 Rapid Reset: deconstructing the record-breaking attack</em>. Le compte rendu canonique de la divulgation coordonnée d'octobre 2023, incluant la mécanique de l'attaque ainsi que le pic de 398 millions de rps capturé en direct. <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/">https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>HAProxy Technologies</strong> — <em>HAProxy is Not Affected by the HTTP/2 Rapid Reset Attack (CVE-2023-44487)</em>. L'argument structurel de HAProxy quant à la raison pour laquelle son cycle de vie de stream absorbe naturellement le Rapid Reset ; un contraste utile face à l'approche par counters de flood retenue par Sōzu. <a href="https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487">https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Cloudflare blog — série Post-quantum</strong>. Couverture pluriannuelle assurée par Bas Westerbaan et ses collaborateurs sur l'échange de clés post-quantique et les groupes hybrides ; filiation de l'hybride X25519MLKEM768 que Sōzu négocie désormais par défaut. <a href="https://blog.cloudflare.com/tag/post-quantum/">https://blog.cloudflare.com/tag/post-quantum/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Cloudflare Learning Center</strong> — <em>What is HSTS?</em>. Primer accessible sur HSTS, la sémantique max-age / includeSubDomains / preload, et la politique de la HSTS preload list.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Retrait de TLS 1.0 et 1.1 de nos load balancers le 30 juin</title>
		<link>https://www.clever.cloud/fr/blog/entreprise/2022/05/03/retrait-de-tls-1-0-et-1-1-de-nos-load-balancers-le-30-juin/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Tue, 03 May 2022 08:24:47 +0000</pubDate>
				<category><![CDATA[Entreprise]]></category>
		<category><![CDATA[fonctionnalité]]></category>
		<guid isPermaLink="false">https://www.clever-cloud.com/?p=6285</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="banniere tls" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls.png 1400w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><!-- wp:paragraph -->
<p>Lorsque vous accédez à un site ou une application en ligne, vous le faites le plus souvent de manière dite "sécurisée". C'est par exemple le fameux cadenas vert qui symbolise les connexions HTTPS dans votre navigateur, qui est devenu la norme depuis quelques années grâce à des initiatives comme <a href="https://www.clever.cloud/blog/features/2019/01/15/automatic-lets-encrypt-certificates/" target="_blank" rel="noreferrer noopener">Let's Encrypt</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie que les données transférées au serveur sont chiffrées, et que même si elles sont interceptées, elles sont illisibles par un tiers. Une protection assurée par le protocole TLS (<a href="https://fr.wikipedia.org/wiki/Transport_Layer_Security" target="_blank" rel="noreferrer noopener">Transport Layer Security</a>) depuis près de 20 ans, qu'il s'agisse d'un site personnel, de vente en ligne ou même d'accès aux services de votre banque.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>À travers le temps, cette brique technique essentielle sur Internet a évolué pour renforcer le niveau de sécurité qu'elle offre. En août 2018, <a href="https://www.ietf.org/blog/tls13/" target="_blank" rel="noreferrer noopener">sa version 1.3</a> (la dernière en date) était publiée. Les versions 1.0 et 1.1 sont, elles, considérées comme n'offrant plus un niveau de protection suffisant. Elles <a href="https://datatracker.ietf.org/doc/html/rfc8996" target="_blank" rel="noreferrer noopener">sont ainsi dépréciées</a> par l'IETF (Internet Engineering Task Force) depuis mars 2021 et ont été progressivement retirées des navigateurs récents comme Firefox, Chrome et ses dérivés ou Safari.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":6281,"sizeSlug":"full","linkDestination":"none"} -->
<figure class="wp-block-image aligncenter size-full"><img src="https://cdn.clever-cloud.com/uploads/2022/05/sans-titre.webp" alt="Clever Cloud Sōzu TLS Versions" class="wp-image-6281"/><figcaption class="wp-element-caption">TLS 1.3 représente plus de 90 % des requêtes quotidiennes</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous avons vu nos clients suivre ce mouvement et adopter peu à peu TLS 1.2 et 1.3. Sur nos load balancers, basés sur notre reverse proxy maison et open source <a href="https://www.sozu.io/" target="_blank" rel="noreferrer noopener">Sōzu</a>, la version la plus récente représente plus de 90 % des requêtes traitées chaque jour. TLS 1.2 compte pour un peu moins de 9 %. TLS 1.0 et 1.1 seulement quelques dizaines de milliers de requêtes par jour, moins de 0,1 % de notre trafic.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si nous avons continué à gérer ces versions pour des questions de compatibilité, ce ne sera plus le cas à compter du 30 juin prochain. Nous allons bien entendu informer les clients concernés par cette démarche, et les inciter à passer sur des versions plus récentes, ce qui aura pour eux des avantages tant en termes de sécurité que de performance ou même de référencement.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Plusieurs rappels leur seront envoyés d'ici à la coupure définitive de TLS 1.0 et 1.1. En cas de questions à ce sujet, contactez notre support via <a href="https://console.clever-cloud.com/" target="_blank" rel="noreferrer noopener">la Console</a>.</p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="banniere tls" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls.png 1400w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2022/05/banniere-tls-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><!-- wp:paragraph -->
<p>Lorsque vous accédez à un site ou une application en ligne, vous le faites le plus souvent de manière dite "sécurisée". C'est par exemple le fameux cadenas vert qui symbolise les connexions HTTPS dans votre navigateur, qui est devenu la norme depuis quelques années grâce à des initiatives comme <a href="https://www.clever.cloud/blog/features/2019/01/15/automatic-lets-encrypt-certificates/" target="_blank" rel="noreferrer noopener">Let's Encrypt</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie que les données transférées au serveur sont chiffrées, et que même si elles sont interceptées, elles sont illisibles par un tiers. Une protection assurée par le protocole TLS (<a href="https://fr.wikipedia.org/wiki/Transport_Layer_Security" target="_blank" rel="noreferrer noopener">Transport Layer Security</a>) depuis près de 20 ans, qu'il s'agisse d'un site personnel, de vente en ligne ou même d'accès aux services de votre banque.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>À travers le temps, cette brique technique essentielle sur Internet a évolué pour renforcer le niveau de sécurité qu'elle offre. En août 2018, <a href="https://www.ietf.org/blog/tls13/" target="_blank" rel="noreferrer noopener">sa version 1.3</a> (la dernière en date) était publiée. Les versions 1.0 et 1.1 sont, elles, considérées comme n'offrant plus un niveau de protection suffisant. Elles <a href="https://datatracker.ietf.org/doc/html/rfc8996" target="_blank" rel="noreferrer noopener">sont ainsi dépréciées</a> par l'IETF (Internet Engineering Task Force) depuis mars 2021 et ont été progressivement retirées des navigateurs récents comme Firefox, Chrome et ses dérivés ou Safari.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":6281,"sizeSlug":"full","linkDestination":"none"} -->
<figure class="wp-block-image aligncenter size-full"><img src="https://cdn.clever-cloud.com/uploads/2022/05/sans-titre.webp" alt="Clever Cloud Sōzu TLS Versions" class="wp-image-6281"/><figcaption class="wp-element-caption">TLS 1.3 représente plus de 90 % des requêtes quotidiennes</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous avons vu nos clients suivre ce mouvement et adopter peu à peu TLS 1.2 et 1.3. Sur nos load balancers, basés sur notre reverse proxy maison et open source <a href="https://www.sozu.io/" target="_blank" rel="noreferrer noopener">Sōzu</a>, la version la plus récente représente plus de 90 % des requêtes traitées chaque jour. TLS 1.2 compte pour un peu moins de 9 %. TLS 1.0 et 1.1 seulement quelques dizaines de milliers de requêtes par jour, moins de 0,1 % de notre trafic.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si nous avons continué à gérer ces versions pour des questions de compatibilité, ce ne sera plus le cas à compter du 30 juin prochain. Nous allons bien entendu informer les clients concernés par cette démarche, et les inciter à passer sur des versions plus récentes, ce qui aura pour eux des avantages tant en termes de sécurité que de performance ou même de référencement.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Plusieurs rappels leur seront envoyés d'ici à la coupure définitive de TLS 1.0 et 1.1. En cas de questions à ce sujet, contactez notre support via <a href="https://console.clever-cloud.com/" target="_blank" rel="noreferrer noopener">la Console</a>.</p>
<!-- /wp:paragraph -->]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Annonce du Clever Cloud Rust SDK</title>
		<link>https://www.clever.cloud/fr/blog/engineering-fr/2022/04/28/annonce-du-clever-cloud-rust-sdk/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Thu, 28 Apr 2022 08:41:43 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<guid isPermaLink="false">https://www.clever-cloud.com/?p=6199</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="banniere sdk rust" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust.png 1400w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><!-- wp:paragraph {"dropCap":true} -->
<p class="has-drop-cap">Bonjour 🖖, amis humains et robots ! Notre équipe d'ingénieurs est fière d'annoncer un tout nouveau kit de développement logiciel (sdk) Rust, également connu sous le nom de "<a href="https://crates.io/crates/clevercloud-sdk" target="_blank" rel="noreferrer noopener">clevercloud-sdk</a>" sur <a href="https://crates.io/crates/clevercloud-sdk" target="_blank" rel="noreferrer noopener">crates.io</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Certains d'entre vous ont peut-être remarqué qu'il y a de nouveaux dépots sur notre organisation GitHub. Ces dépots sont nommés "<a href="https://github.com/CleverCloud/clevercloud-sdk-rust" target="_blank" rel="noreferrer noopener">clevercloud-sdk-rust</a>" et "<a href="https://github.com/CleverCloud/oauth10a-rust" target="_blank" rel="noreferrer noopener">oauth10a-rust</a>". Leur objectif est de fournir un moyen pratique d'interagir avec l'API de Clever Cloud avec des fonctionnalités intéressantes que nous allons vous faire découvrir dans ce blogpost!</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Conçu pour être asynchrone</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le kit de développement logiciel et le client oauth 1.0a sont principalement construits sur la base de deux crates bien connus de la communauté. Il s'agit de <a href="https://github.com/hyperium/hyper">hyper</a>, et du runtime asynchrone qui le propulse, nommé <a href="https://tokio.rs/" target="_blank" rel="noreferrer noopener">tokio</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'idée principale derrière l'utilisation de la crate hyper et par extension du runtime asynchrone tokio est de tirer parti de l'écosystème actuel qui gravite autour de ces crates et des efforts pour intégrer une nouvelle API du kernel appelée <a href="https://kernel.dk/io_uring.pdf" target="_blank" rel="noreferrer noopener">io_uring</a>. Une fois que cette nouvelle API kernel sera intégrée dans le runtime tokio, cela conduira à une amélioration significative de la performance, selon le <a href="https://tokio.rs/blog/2021-07-tokio-uring" target="_blank" rel="noreferrer noopener">billet de blog de l'annonce de tokio</a>. Nous attendons avec impatience cette amélioration qui nous permettra d'itérer plus rapidement ! 🚀</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'observabilité au cœur de l'outil</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Ces crates sont développées avec l'idée d'être entièrement observables. Cela a été réalisé par d'autres crates bien connus comme <a href="https://crates.io/crates/log" target="_blank" rel="noreferrer noopener">log</a> et <a href="https://crates.io/crates/tracing" target="_blank" rel="noreferrer noopener">tracing</a>, ou en utilisant des initiatives communautaires comme le crate <a href="https://crates.io/crates/prometheus" target="_blank" rel="noreferrer noopener">prometheus</a>. Les intégrations de ces crates font partie du <a href="https://doc.rust-lang.org/cargo/reference/features.html">système de flags de fonctionnalités de compilateur</a> fourni par le <a href="https://doc.rust-lang.org/book/ch01-03-hello-cargo.html" target="_blank" rel="noreferrer noopener">dépot cargo</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Façade de logs standard</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Tout d'abord, vous devez savoir que la façade de logs standard est activée par défaut. Elle fournira des informations utiles sur les comportements internes des crates ci-dessus, en utilisant le logger standard s'il est défini. Elle vous aidera à comprendre comment les appels à l'API de Clever Cloud sont réalisés avec quelques informations de débogage, si vous en avez besoin.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<pre class="wp-block-code"><code class="lang-toml">clevercloud-sdk = { version = "^0.10.0", default-features = false }</code></pre>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Si vous voulez le désactiver, vous devez désactiver les ensembles par défaut de fonctionnalités activées. Cela peut être réalisé en utilisant la syntaxe suivante pour le <code>crate clevercloud-sdk</code> dans votre fichier <code>Cargo.toml</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Orienté métriques</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Nous pensons que les métriques sont importantes. Elles aident à comprendre les systèmes en mettant en corrélation des choses qui ne semblent pas être liées au départ.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi nous avons lancé <a href="https://www.clever.cloud/blog/features/2018/01/16/realtime-metrics/" target="_blank" rel="noreferrer noopener">Clever Cloud Metrics</a> assez rapidement, il y a quelques années. Nous l'avons récemment enrichi de nouvelles fonctionnalités en offrant plus de moyens d'interroger Clever Cloud Metrics, grâce à <a href="https://github.com/ovh/erlenmeyer" target="_blank" rel="noreferrer noopener">Erlenmeyer</a> qui est un proxy de langage d'interrogation de séries temporelles. Vous trouverez plus de détails sur la façon dont vous pouvez l'utiliser dans <a href="https://www.clever.cloud/blog/engineering/2021/10/12/enabling-promql-queries-with-erlenmeyer/" target="_blank" rel="noreferrer noopener">cet article de blog</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Enfin, nous avons annoncé le produit <a href="https://www.clever.cloud/fr/blog/fonctionnalites/2021/11/23/annonce-dune-base-de-donnees-time-series-sur-clever-cloud-avec-tardis/">Tardis</a> qui vous permet de nous envoyer vos métriques et nous nous occupons du reste comme nous le faisons toujours et, plus récemment, nous avons intégré des tableaux de bord Grafana pré-construits pour vous aider à visualiser l'état de vos applications et add-ons, vous pouvez <a href="https://www.clever.cloud/fr/blog/non-classifiee/2021/10/28/grafana-pour-des-metriques-d-applications/" target="_blank" rel="noreferrer noopener">en savoir plus ici</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Revenons à nos crates. Vous pouvez activer la collecte de métriques à l'aide du crate prometheus, en activant les flags de métriques au niveau du crate dans votre fichier <code>Cargo.toml</code>. Cela peut être réalisé en utilisant la syntaxe suivante.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
clevercloud-sdk = { version = "^0.10.0", features = ["metrics"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Une fois cette fonctionnalité activée, il n'y a plus grand-chose à faire. Vous devrez exposer les métriques via un serveur HTTP ou les envoyer en utilisant la passerelle push de prometheus. Cette partie est décrite dans la <a href="https://docs.rs/prometheus" target="_blank" rel="noreferrer noopener">documentation du crate prometheus</a> ou dans ces <a href="https://github.com/tikv/rust-prometheus/tree/master/examples" target="_blank" rel="noreferrer noopener">exemples</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Capacités de traces</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le dernier pilier de l'observabilité, mais non le moindre, sont les traces. Selon l'initiative et la documentation d'OpenTelemetry, les traces sont définies comme suit :</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Les traces suivent la progression d'une demande unique, appelée <strong>trace</strong>, telle qu'elle est traitée par les services qui composent une application. La demande peut être initiée par un utilisateur ou une application. Les traces distribués sont une forme de trace qui traverse les frontières du processus, du réseau et de la sécurité. Chaque unité de travail dans une trace est appelée un <strong>span</strong> ; une trace est un arbre de spans. Les spans sont des objets qui représentent le travail effectué par les services ou les composants individuels impliqués dans une requête au fur et à mesure qu'elle circule dans un système. Un span contient un contexte de span, qui est un ensemble d'identifiants uniques au monde représentant la demande unique dont chaque span fait partie. Un span fournit des mesures de Demande, Erreur et Durée (RED) qui peuvent être utilisées pour déboguer les problèmes de disponibilité et de performance…</p>
<!-- /wp:paragraph --><cite>Documentation sur OpenTelemetry</cite></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Si vous souhaitez vous intéresser de plus près aux traces, même si elles ne sont pas en Rust, vous pouvez consulter l'organisation <a href="https://github.com/open-telemetry/" target="_blank" rel="noreferrer noopener">OpenTelemetry GitHub</a>. Il y a beaucoup de bibliothèques, de SDKs et de documentation pour vous aider à construire votre solution de traces ou à l'intégrer à une solution déjà existante. En outre, si vous utilisez le langage rust et peut-être le runtime tokio, vous pouvez consulter les articles de blog qui expliquent <a href="https://tokio.rs/blog/2019-08-tracing" target="_blank" rel="noreferrer noopener">comment les traces fonctionnent </a>dans le runtime asynchrone ci-dessus et comment les visualiser à l'aide de la <a href="https://tokio.rs/blog/2021-09-console-dev-diary-1" target="_blank" rel="noreferrer noopener">console</a> ou en utilisant le connecteur <a href="https://github.com/tokio-rs/tracing/tree/master/tracing-opentelemetry" target="_blank" rel="noreferrer noopener">OpenTelemetry</a> qui permet d'envoyer des traces à plus de puits, la liste est disponible sur le dépot rust GitHub d'OpenTelemetry.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Alors comment activer concrètement la fonctionnalité de traces à l'aide de clevercloud-sdk ? Comme mentionné ci-dessus, toutes les fonctionnalités sont pilotées par un flag de fonctionnalité, donc pour obtenir des capacités de traces, vous devez activer le flag de trace.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
clevercloud-sdk = { version = "^0.10.0", features = ["trace"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Une fois que l'indicateur de fonctionnalité a été activé, vous devrez collecter et envoyer des traces en utilisant le connecteur et les sinks ci-dessus.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">À quoi ça ressemble ?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Prenons un exemple concret pour illustrer ce à quoi ressemble le clevercloud-sdk. Mais avant de passer en revue l'utilisation de clevercloud-sdk, je vais vous présenter les dépendances et les exigences dont vous aurez besoin. La première chose à faire est de déclarer les crates dans le fichier <code>Cargo.toml</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
[dependencies]
tokio = { version = "^1.17.0", features = ["full"] }
clevercloud-sdk = { version = "^0.10.0", features = ["metrics", "tokio", "trace", "jsonschemas"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Nous sommes maintenant capables d'écrire un logiciel à l'aide de clevercloud-sdk. Voici un exemple de la façon d'utiliser le SDK : </p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<pre class="wp-block-code"><code class="lang-rust">...
use clevercloud_sdk::{
    oauth10a::{
        proxy::{self, ProxyConnectorBuilder},
        Credentials,
    },
    v2::myself,
    Client,
};
...

// See the full code at:
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl/src/cmd/myself.rs
pub async fn get(config: Arc&lt;Configuration&gt;, output: &amp;Output) -&gt; Result&lt;(), Error&gt; {
    let credentials: Credentials = config.credentials.to_owned().into();
    let connector = ProxyConnectorBuilder::try_from_env().map_err(Error::ProxyConnector)?;
    let client = Client::builder()
        .with_credentials(credentials)
        .build(connector);

    let user = myself::get(&amp;client).await.map_err(Error::Get)?;

    println!(
        "{}",
        output
            .format(&amp;user)
            .map_err(|err| Error::FormatOutput(Box::new(err)))?
    );

    Ok(())
}</code></pre>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Un autre exemple du sdk qui interagit avec les add-ons :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
...
use clevercloud_sdk::{
    oauth10a::{
        proxy::{self, ProxyConnectorBuilder},
        Credentials,
    },
    v2::addon,
    Client,
};
...

// See the full code at:
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl/src/cmd/addon/mod.rs 
pub async fn list(
    config: Arc<Configuration>,
    output: &Output,
    organisation_id: &str,
) -> Result<(), Error> {
    let credentials: Credentials = config.credentials.to_owned().into();
    let connector = ProxyConnectorBuilder::try_from_env().map_err(Error::ProxyConnector)?;
    let client = Client::builder()
        .with_credentials(credentials)
        .build(connector);

    let addons = addon::list(&client, organisation_id)
        .await
        .map_err(|err| Error::List(organisation_id.to_owned(), err))?;

    println!(
        "{}",
        output
            .format(&addons)
            .map_err(|err| Error::FormatOutput(Box::new(err)))?
    );
    Ok(())
}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Vous pouvez trouver le code source complet de l'exemple d'interface de ligne de commande dans le dépot clevercloud-sdk dans le dépot d'exemples ou vous pouvez suivre <a href="https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cli" target="_blank" rel="noreferrer noopener">ce lien</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Quelles sont les prochaines étapes ?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Jetons un coup d'œil aux fonctionnalités à venir qui seront intégrées dans ces crates.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Biscuit et token porteur oauth2</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous travaillons sur un nouveau token d'authentification et d'autorisation appelé Biscuit. Plus de détails à ce sujet dans le <a href="https://www.clever.cloud/blog/engineering/2021/04/12/introduction-to-biscuit/">billet de blog d'introduction</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce nouveau token d'authentification et d'autorisation fonctionnera avec la norme OAuth 2.0. L'une des tâches du SDK et du client est de faciliter la transition de OAuth 1.0a à OAuth 2.0 en utilisant Biscuit.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Nouvelles fonctionnalités !</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le kit de développement logiciel va se développer pour prendre en charge l'ensemble de l'API. La prochaine fonctionnalité est l'intégration du bus d'événements afin de s'abonner aux événements qui se produisent sur la plateforme de Clever Cloud. Vous serez par exemple en mesure de recevoir des notifications sur le déploiement d'une application, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>En outre, ces caisses sont utilisées pour construire un autre logiciel que vous avez découvert dans <a href="https://www.clever.cloud/fr/blog/fonctionnalites/2022/03/16/clever-operator/">un autre article du blog</a>. Il présente un opérateur Kubernetes que vous pouvez utiliser sur <a href="https://www.redhat.com/en/technologies/cloud-computing/openshift" target="_blank" rel="noreferrer noopener">OpenShift</a>, qui expose les add-ons de Clever Cloud comme des <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" target="_blank" rel="noreferrer noopener">custom ressources</a>.</p>
<!-- /wp:paragraph -->]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="banniere sdk rust" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust.png 1400w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2022/04/banniere-sdk-rust-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><!-- wp:paragraph {"dropCap":true} -->
<p class="has-drop-cap">Bonjour 🖖, amis humains et robots ! Notre équipe d'ingénieurs est fière d'annoncer un tout nouveau kit de développement logiciel (sdk) Rust, également connu sous le nom de "<a href="https://crates.io/crates/clevercloud-sdk" target="_blank" rel="noreferrer noopener">clevercloud-sdk</a>" sur <a href="https://crates.io/crates/clevercloud-sdk" target="_blank" rel="noreferrer noopener">crates.io</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Certains d'entre vous ont peut-être remarqué qu'il y a de nouveaux dépots sur notre organisation GitHub. Ces dépots sont nommés "<a href="https://github.com/CleverCloud/clevercloud-sdk-rust" target="_blank" rel="noreferrer noopener">clevercloud-sdk-rust</a>" et "<a href="https://github.com/CleverCloud/oauth10a-rust" target="_blank" rel="noreferrer noopener">oauth10a-rust</a>". Leur objectif est de fournir un moyen pratique d'interagir avec l'API de Clever Cloud avec des fonctionnalités intéressantes que nous allons vous faire découvrir dans ce blogpost!</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Conçu pour être asynchrone</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le kit de développement logiciel et le client oauth 1.0a sont principalement construits sur la base de deux crates bien connus de la communauté. Il s'agit de <a href="https://github.com/hyperium/hyper">hyper</a>, et du runtime asynchrone qui le propulse, nommé <a href="https://tokio.rs/" target="_blank" rel="noreferrer noopener">tokio</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'idée principale derrière l'utilisation de la crate hyper et par extension du runtime asynchrone tokio est de tirer parti de l'écosystème actuel qui gravite autour de ces crates et des efforts pour intégrer une nouvelle API du kernel appelée <a href="https://kernel.dk/io_uring.pdf" target="_blank" rel="noreferrer noopener">io_uring</a>. Une fois que cette nouvelle API kernel sera intégrée dans le runtime tokio, cela conduira à une amélioration significative de la performance, selon le <a href="https://tokio.rs/blog/2021-07-tokio-uring" target="_blank" rel="noreferrer noopener">billet de blog de l'annonce de tokio</a>. Nous attendons avec impatience cette amélioration qui nous permettra d'itérer plus rapidement ! 🚀</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'observabilité au cœur de l'outil</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Ces crates sont développées avec l'idée d'être entièrement observables. Cela a été réalisé par d'autres crates bien connus comme <a href="https://crates.io/crates/log" target="_blank" rel="noreferrer noopener">log</a> et <a href="https://crates.io/crates/tracing" target="_blank" rel="noreferrer noopener">tracing</a>, ou en utilisant des initiatives communautaires comme le crate <a href="https://crates.io/crates/prometheus" target="_blank" rel="noreferrer noopener">prometheus</a>. Les intégrations de ces crates font partie du <a href="https://doc.rust-lang.org/cargo/reference/features.html">système de flags de fonctionnalités de compilateur</a> fourni par le <a href="https://doc.rust-lang.org/book/ch01-03-hello-cargo.html" target="_blank" rel="noreferrer noopener">dépot cargo</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Façade de logs standard</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Tout d'abord, vous devez savoir que la façade de logs standard est activée par défaut. Elle fournira des informations utiles sur les comportements internes des crates ci-dessus, en utilisant le logger standard s'il est défini. Elle vous aidera à comprendre comment les appels à l'API de Clever Cloud sont réalisés avec quelques informations de débogage, si vous en avez besoin.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<pre class="wp-block-code"><code class="lang-toml">clevercloud-sdk = { version = "^0.10.0", default-features = false }</code></pre>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Si vous voulez le désactiver, vous devez désactiver les ensembles par défaut de fonctionnalités activées. Cela peut être réalisé en utilisant la syntaxe suivante pour le <code>crate clevercloud-sdk</code> dans votre fichier <code>Cargo.toml</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Orienté métriques</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Nous pensons que les métriques sont importantes. Elles aident à comprendre les systèmes en mettant en corrélation des choses qui ne semblent pas être liées au départ.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi nous avons lancé <a href="https://www.clever.cloud/blog/features/2018/01/16/realtime-metrics/" target="_blank" rel="noreferrer noopener">Clever Cloud Metrics</a> assez rapidement, il y a quelques années. Nous l'avons récemment enrichi de nouvelles fonctionnalités en offrant plus de moyens d'interroger Clever Cloud Metrics, grâce à <a href="https://github.com/ovh/erlenmeyer" target="_blank" rel="noreferrer noopener">Erlenmeyer</a> qui est un proxy de langage d'interrogation de séries temporelles. Vous trouverez plus de détails sur la façon dont vous pouvez l'utiliser dans <a href="https://www.clever.cloud/blog/engineering/2021/10/12/enabling-promql-queries-with-erlenmeyer/" target="_blank" rel="noreferrer noopener">cet article de blog</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Enfin, nous avons annoncé le produit <a href="https://www.clever.cloud/fr/blog/fonctionnalites/2021/11/23/annonce-dune-base-de-donnees-time-series-sur-clever-cloud-avec-tardis/">Tardis</a> qui vous permet de nous envoyer vos métriques et nous nous occupons du reste comme nous le faisons toujours et, plus récemment, nous avons intégré des tableaux de bord Grafana pré-construits pour vous aider à visualiser l'état de vos applications et add-ons, vous pouvez <a href="https://www.clever.cloud/fr/blog/non-classifiee/2021/10/28/grafana-pour-des-metriques-d-applications/" target="_blank" rel="noreferrer noopener">en savoir plus ici</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Revenons à nos crates. Vous pouvez activer la collecte de métriques à l'aide du crate prometheus, en activant les flags de métriques au niveau du crate dans votre fichier <code>Cargo.toml</code>. Cela peut être réalisé en utilisant la syntaxe suivante.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
clevercloud-sdk = { version = "^0.10.0", features = ["metrics"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Une fois cette fonctionnalité activée, il n'y a plus grand-chose à faire. Vous devrez exposer les métriques via un serveur HTTP ou les envoyer en utilisant la passerelle push de prometheus. Cette partie est décrite dans la <a href="https://docs.rs/prometheus" target="_blank" rel="noreferrer noopener">documentation du crate prometheus</a> ou dans ces <a href="https://github.com/tikv/rust-prometheus/tree/master/examples" target="_blank" rel="noreferrer noopener">exemples</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Capacités de traces</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le dernier pilier de l'observabilité, mais non le moindre, sont les traces. Selon l'initiative et la documentation d'OpenTelemetry, les traces sont définies comme suit :</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Les traces suivent la progression d'une demande unique, appelée <strong>trace</strong>, telle qu'elle est traitée par les services qui composent une application. La demande peut être initiée par un utilisateur ou une application. Les traces distribués sont une forme de trace qui traverse les frontières du processus, du réseau et de la sécurité. Chaque unité de travail dans une trace est appelée un <strong>span</strong> ; une trace est un arbre de spans. Les spans sont des objets qui représentent le travail effectué par les services ou les composants individuels impliqués dans une requête au fur et à mesure qu'elle circule dans un système. Un span contient un contexte de span, qui est un ensemble d'identifiants uniques au monde représentant la demande unique dont chaque span fait partie. Un span fournit des mesures de Demande, Erreur et Durée (RED) qui peuvent être utilisées pour déboguer les problèmes de disponibilité et de performance…</p>
<!-- /wp:paragraph --><cite>Documentation sur OpenTelemetry</cite></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Si vous souhaitez vous intéresser de plus près aux traces, même si elles ne sont pas en Rust, vous pouvez consulter l'organisation <a href="https://github.com/open-telemetry/" target="_blank" rel="noreferrer noopener">OpenTelemetry GitHub</a>. Il y a beaucoup de bibliothèques, de SDKs et de documentation pour vous aider à construire votre solution de traces ou à l'intégrer à une solution déjà existante. En outre, si vous utilisez le langage rust et peut-être le runtime tokio, vous pouvez consulter les articles de blog qui expliquent <a href="https://tokio.rs/blog/2019-08-tracing" target="_blank" rel="noreferrer noopener">comment les traces fonctionnent </a>dans le runtime asynchrone ci-dessus et comment les visualiser à l'aide de la <a href="https://tokio.rs/blog/2021-09-console-dev-diary-1" target="_blank" rel="noreferrer noopener">console</a> ou en utilisant le connecteur <a href="https://github.com/tokio-rs/tracing/tree/master/tracing-opentelemetry" target="_blank" rel="noreferrer noopener">OpenTelemetry</a> qui permet d'envoyer des traces à plus de puits, la liste est disponible sur le dépot rust GitHub d'OpenTelemetry.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Alors comment activer concrètement la fonctionnalité de traces à l'aide de clevercloud-sdk ? Comme mentionné ci-dessus, toutes les fonctionnalités sont pilotées par un flag de fonctionnalité, donc pour obtenir des capacités de traces, vous devez activer le flag de trace.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
clevercloud-sdk = { version = "^0.10.0", features = ["trace"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Une fois que l'indicateur de fonctionnalité a été activé, vous devrez collecter et envoyer des traces en utilisant le connecteur et les sinks ci-dessus.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">À quoi ça ressemble ?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Prenons un exemple concret pour illustrer ce à quoi ressemble le clevercloud-sdk. Mais avant de passer en revue l'utilisation de clevercloud-sdk, je vais vous présenter les dépendances et les exigences dont vous aurez besoin. La première chose à faire est de déclarer les crates dans le fichier <code>Cargo.toml</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
[dependencies]
tokio = { version = "^1.17.0", features = ["full"] }
clevercloud-sdk = { version = "^0.10.0", features = ["metrics", "tokio", "trace", "jsonschemas"] }
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Nous sommes maintenant capables d'écrire un logiciel à l'aide de clevercloud-sdk. Voici un exemple de la façon d'utiliser le SDK : </p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<pre class="wp-block-code"><code class="lang-rust">...
use clevercloud_sdk::{
    oauth10a::{
        proxy::{self, ProxyConnectorBuilder},
        Credentials,
    },
    v2::myself,
    Client,
};
...

// See the full code at:
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl/src/cmd/myself.rs
pub async fn get(config: Arc&lt;Configuration&gt;, output: &amp;Output) -&gt; Result&lt;(), Error&gt; {
    let credentials: Credentials = config.credentials.to_owned().into();
    let connector = ProxyConnectorBuilder::try_from_env().map_err(Error::ProxyConnector)?;
    let client = Client::builder()
        .with_credentials(credentials)
        .build(connector);

    let user = myself::get(&amp;client).await.map_err(Error::Get)?;

    println!(
        "{}",
        output
            .format(&amp;user)
            .map_err(|err| Error::FormatOutput(Box::new(err)))?
    );

    Ok(())
}</code></pre>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Un autre exemple du sdk qui interagit avec les add-ons :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
...
use clevercloud_sdk::{
    oauth10a::{
        proxy::{self, ProxyConnectorBuilder},
        Credentials,
    },
    v2::addon,
    Client,
};
...

// See the full code at:
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl
// - https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cleverctl/src/cmd/addon/mod.rs 
pub async fn list(
    config: Arc<Configuration>,
    output: &Output,
    organisation_id: &str,
) -> Result<(), Error> {
    let credentials: Credentials = config.credentials.to_owned().into();
    let connector = ProxyConnectorBuilder::try_from_env().map_err(Error::ProxyConnector)?;
    let client = Client::builder()
        .with_credentials(credentials)
        .build(connector);

    let addons = addon::list(&client, organisation_id)
        .await
        .map_err(|err| Error::List(organisation_id.to_owned(), err))?;

    println!(
        "{}",
        output
            .format(&addons)
            .map_err(|err| Error::FormatOutput(Box::new(err)))?
    );
    Ok(())
}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Vous pouvez trouver le code source complet de l'exemple d'interface de ligne de commande dans le dépot clevercloud-sdk dans le dépot d'exemples ou vous pouvez suivre <a href="https://github.com/CleverCloud/clevercloud-sdk-rust/blob/main/examples/cli" target="_blank" rel="noreferrer noopener">ce lien</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Quelles sont les prochaines étapes ?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Jetons un coup d'œil aux fonctionnalités à venir qui seront intégrées dans ces crates.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Biscuit et token porteur oauth2</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous travaillons sur un nouveau token d'authentification et d'autorisation appelé Biscuit. Plus de détails à ce sujet dans le <a href="https://www.clever.cloud/blog/engineering/2021/04/12/introduction-to-biscuit/">billet de blog d'introduction</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce nouveau token d'authentification et d'autorisation fonctionnera avec la norme OAuth 2.0. L'une des tâches du SDK et du client est de faciliter la transition de OAuth 1.0a à OAuth 2.0 en utilisant Biscuit.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Nouvelles fonctionnalités !</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le kit de développement logiciel va se développer pour prendre en charge l'ensemble de l'API. La prochaine fonctionnalité est l'intégration du bus d'événements afin de s'abonner aux événements qui se produisent sur la plateforme de Clever Cloud. Vous serez par exemple en mesure de recevoir des notifications sur le déploiement d'une application, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>En outre, ces caisses sont utilisées pour construire un autre logiciel que vous avez découvert dans <a href="https://www.clever.cloud/fr/blog/fonctionnalites/2022/03/16/clever-operator/">un autre article du blog</a>. Il présente un opérateur Kubernetes que vous pouvez utiliser sur <a href="https://www.redhat.com/en/technologies/cloud-computing/openshift" target="_blank" rel="noreferrer noopener">OpenShift</a>, qui expose les add-ons de Clever Cloud comme des <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" target="_blank" rel="noreferrer noopener">custom ressources</a>.</p>
<!-- /wp:paragraph -->]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
