Fjord

Dans les coulisses de Fjord

Ce qui fait fonctionner Fjord.

Un bot en Rust. Notre propre moteur graphique. Et les frameworks, bibliothèques et bases de données sur lesquels repose Fjord.

Découvrez ce que nous développons et les technologies qui composent Fjord.

01 Le botFjord préserve l’ordre des événements par serveur tout en traitant les tâches indépendantes en parallèle.

Fjord

Traiter les événements dans l’ordre.

Fjord traite les événements Discord dans l’ordre et exécute les tâches indépendantes en parallèle. Twilight relie le bot à Discord et garde les données des serveurs disponibles localement. Dragonfly stocke les événements en attente et participe à la coordination des connexions à la passerelle.

01

READY délimite l’état.

Un nouveau READY attend la fin des tâches antérieures avant que Fjord remplace l’état des serveurs. Les événements suivants démarrent ensuite, ce qui empêche les anciennes tâches d’écraser le nouvel état.

02

FIFO par serveur.

Les événements d’un même serveur démarrent dans leur ordre d’arrivée. Chacun attend la fin du précédent afin que les modifications de ce serveur ne se dépassent pas.

03

Serveurs en parallèle.

Le répartiteur distingue les tâches par clé. Plusieurs serveurs peuvent avancer simultanément ; seules les tâches de même clé s’attendent mutuellement.

04

Un événement, les bonnes tâches.

Le même message parvient à AutoMod et au journal d’activité en même temps. Chacun le traite séparément pour sa propre tâche.

05

Données temporaires dans Dragonfly.

Les événements Discord en attente et leurs données sont stockés dans Dragonfly. AutoMod et les journaux d’activité utilisent aussi ce stockage commun pour les états temporaires. Le bot continue de piloter l’exécution des tâches.

06

Une détection, une réaction.

Dès qu’un filtre AutoMod actif se déclenche, la vérification de ce message s’arrête. Les autres filtres ne produisent pas une seconde mesure pour le même événement.

07

Données des serveurs avec Twilight.

Twilight maintient en mémoire les serveurs, membres, rôles, salons, émojis, présences et états vocaux à jour. Les messages ne font pas partie de ce cache.

08

Interactions distinctes.

Les interactions sont planifiées indépendamment des événements de serveur. READY marque une frontière d’état au sein de chaque connexion à la passerelle.

09

Responsabilité des shards.

Dragonfly coordonne la responsabilité de chaque shard, c’est-à-dire de chaque connexion à la passerelle. Après un transfert, l’ancien responsable ne peut plus prendre en charge ni terminer d’autres événements.

02 Moteur graphique FjellTraitement des images en Rust, SIMD et performances mesurées.

01 / Notre propre développement

Nos images portent notre signature.

Fjell est notre moteur graphique développé en Rust. Il associe fonds, avatars et textes pour créer des cartes de bienvenue personnelles.

Nous voulions maîtriser la création de ces images. Nous avons donc développé une solution adaptée à Fjord qui nous offre une liberté créative.

La maîtrise des coûts compte tout autant. Fjell offre des performances maximales sans perte de qualité, tout en optimisant l’utilisation du processeur et de la mémoire pendant la génération. Nous réduisons ainsi considérablement nos coûts de serveur.

Notre travail va jusqu’au traitement des pixels. Nos propres boucles SIMD utilisent AVX2, FMA et BMI1/BMI2 pour calculer plusieurs pixels en parallèle.

Aperçu de l’éditeur de Fjord avec une carte de bienvenue personnalisée
Conçu dans Fjord. Rendu avec Fjell.

Mesure des performances

Benchmark contrôlé*

Quatre niveaux de charge avec des variations de cartes contrôlées et le même protocole de test.

ParallèleCartes/sCartes/minRendu moy.Rendu P50Rendu P95Rendu P99Total moy.Total P50Total P95Total P99CPU moy.RAM moy.
1797,4847.8491,062 ms1,061 ms1,226 ms1,242 ms1,253 ms1,251 ms1,428 ms1,473 ms88,3 %381,2 MiB
21.577,9594.6771,038 ms1,004 ms1,225 ms1,421 ms1,266 ms1,236 ms1,470 ms1,715 ms173,5 %360,1 MiB
43.173,00190.3801,023 ms1,011 ms1,188 ms1,230 ms1,259 ms1,243 ms1,448 ms1,557 ms344,9 %375,3 MiB
85.850,25351.0151,050 ms1,026 ms1,194 ms1,290 ms1,366 ms1,349 ms1,578 ms1,803 ms647,0 %385,8 MiB

Mise à l’échelle du débit

Débit mesuré comparé à une mise à l’échelle linéaire parfaite.

MesuréLinéaire idéal
1248Workers parallèlesCartes/s
WorkersMesuréLinéaire idéalMise à l’échelleEfficacité
1797,48797,481,00×100,0 %
21.577,951.594,961,98×98,9 %
43.173,003.189,923,98×99,5 %
85.850,256.379,847,34×91,7 %

Les quatre tests locaux ont duré 60 secondes chacun sur un AMD Ryzen 9 9950X. Ils utilisaient 100 arrière-plans légers avec des couleurs ordinaires ou des illustrations et des fichiers d’environ 100 à 300 Ko, généralement proches de 200 Ko. La couche liquide restait désactivée et la police constante ; les couleurs et positions des shaders du texte et du cercle variaient entre les cartes.

Le temps de rendu comprend la création de l’image ainsi que l’encodage et la compression PNG jusqu’au fichier PNG final. Le transfert réseau et le temps de téléchargement ne sont pas inclus.

Le générateur de charge utilisait 1, 2, 4 ou 8 requêtes parallèles selon le test. Une nouvelle requête ne commençait qu’après la réception complète et la validation du PNG précédent. L’utilisation CPU indiquée a été mesurée sous cette charge précise. Le moteur graphique pouvait répartir son travail sur plusieurs cœurs.

* Mesures internes non vérifiées indépendamment, réalisées dans les conditions décrites. Elles ne constituent ni une caractéristique garantie, ni une garantie, ni un engagement de performance. Les performances réelles peuvent varier selon le système, la charge et l’environnement.

Test aléatoire intensif

Test de performance avec des cartes aléatoires*

Un protocole beaucoup plus variable avec 1 000 arrière-plans, 237 polices et des effets aléatoires à chaque requête.

ParallèleCartes/sCartes/minRendu moy.Rendu P50Rendu P95Rendu P99Total moy.Total P50Total P95Total P99CPU moy.RAM moy.
192,655.5599,775 ms10,478 ms12,781 ms13,401 ms10,788 ms11,553 ms14,006 ms14,784 ms93,6 %1.205,6 MiB
2184,5311.0729,944 ms10,621 ms12,858 ms13,550 ms10,832 ms11,576 ms13,938 ms14,698 ms189,1 %1.278,8 MiB
4358,8221.52910,209 ms10,855 ms13,240 ms13,997 ms11,138 ms11,857 ms14,363 ms15,212 ms377,7 %1.300,9 MiB
8660,5239.63110,897 ms11,610 ms14,343 ms15,336 ms12,101 ms12,889 ms15,838 ms16,880 ms744,8 %1.308,6 MiB

Mise à l’échelle du débit

Débit mesuré comparé à une mise à l’échelle linéaire parfaite.

MesuréLinéaire idéal
1248Workers parallèlesCartes/s
WorkersMesuréLinéaire idéalMise à l’échelleEfficacité
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

Ces quatre tests locaux ont duré 60 secondes chacun sur le même AMD Ryzen 9 9950X. Chaque requête choisissait parmi 1 000 arrière-plans plus exigeants de 800 Ko à 2,4 Mo et 237 polices. Les textes, la transparence, la taille de la police et de l’avatar, le contour, les couleurs du texte et du cercle ainsi que l’angle, la force et l’intensité des shaders variaient. Environ la moitié des cartes activait aussi la couche liquide avec une couleur, une opacité et un flou aléatoires.

Le générateur de charge utilisait 1, 2, 4 ou 8 workers parallèles en boucle fermée. Chaque worker ne lançait la requête suivante qu’après réception complète et validation du PNG précédent. Tous les tests de 60 secondes se sont achevés sans erreur, expiration de délai ni PNG invalide.

Le temps de rendu comprend la création de l’image ainsi que l’encodage et la compression PNG jusqu’au fichier PNG final. Le transfert réseau et le temps de téléchargement ne sont pas inclus.

* Mesures internes non vérifiées indépendamment, réalisées dans les conditions décrites. Elles ne constituent ni une caractéristique garantie, ni une garantie, ni un engagement de performance. Les performances réelles peuvent varier selon le système, la charge et l’environnement.

03 TechnologiesLangages, frameworks, bibliothèques, bases de données et stockage objet.

02 / Nos fondations techniques

Nos outils de développement.

En plus de notre propre moteur, nous utilisons Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB et RustFS. Chaque technologie a un rôle précis dans le système.

Langage de programmation

Rust

Rust

Rust est à la base de notre bot Discord, du backend, de l’éditeur de cartes et du moteur graphique Fjell.

Logo © Rust Foundation. CC BY 4.0 · sans modification

Framework web

Leptos

Leptos

Nous utilisons Leptos pour certaines parties de notre interface web. Le framework amène Rust dans le navigateur et s’intègre naturellement au reste de notre stack.

Logo des mainteneurs de Leptos. MIT · sans modification

Framework web

Vue

Vue

Vue structure les composants du site public, de la navigation et de la documentation aux autres zones interactives. Ces interfaces restent ainsi cohérentes et faciles à faire évoluer.

Logo © Evan You. CC BY-NC-SA 4.0 · sans modification

Bibliothèque pour Discord

Twilight

Twilight

Nous utilisons Twilight pour nous connecter à Discord. Cette bibliothèque relie notre bot écrit en Rust à Discord.

Logo de Fezhoof. CC BY-SA 4.0 · sans modification

Base de données

Dragonfly est notre stockage temporaire commun pour les événements Discord, la coordination des shards et des connexions multiples à la passerelle, AutoMod et les journaux d’activité.

Logiciel sous BSL 1.1 avec un droit d’utilisation supplémentaire.

Base de données relationnelle

PostgreSQL complète notre couche de données pour les données et structures relationnelles. Il fonctionne aux côtés de ScyllaDB comme un composant distinct de notre infrastructure.

Base de données

ScyllaDB

ScyllaDB

ScyllaDB fait partie de notre couche de données aux côtés de PostgreSQL. Nous utilisons les deux systèmes pour des tâches différentes au sein de Fjord.

Logo utilisé selon le Media Kit ScyllaDB

Stockage d’objets

Nous utilisons RustFS pour le stockage d’objets compatible S3. Il ajoute une couche de stockage distincte aux côtés de PostgreSQL et ScyllaDB.

Logiciel sous Apache 2.0. RustFS est une marque de RustFS, Inc.