Fjord

Ein Blick hinter Fjord

Was hinter Fjord steckt.

Ein Bot in Rust. Eine hauseigene Grafikengine. Dazu Frameworks, Bibliotheken und Datenbanken, auf denen Fjord aufbaut.

Hier zeigen wir, was wir selbst entwickeln und welche Technologien bei Fjord zusammenkommen.

01 Der BotFjord wahrt die Reihenfolge pro Server und verarbeitet unabhängige Aufgaben parallel.

Fjord

Ereignisse geordnet verarbeiten.

Fjord verarbeitet Discord-Ereignisse geordnet und führt unabhängige Aufgaben parallel aus. Twilight verbindet den Bot mit Discord und hält Serverdaten lokal verfügbar. Dragonfly speichert wartende Ereignisse und unterstützt die Koordination der Gateway-Verbindungen.

01

READY als Zustandsgrenze.

Ein neues READY wartet auf frühere Ereignisaufgaben, bevor Fjord den Serverbestand erneuert. Spätere Ereignisse starten erst danach. So bleibt der neue Zustand vor alter Arbeit geschützt.

02

FIFO je Server.

Ereignisse desselben Servers starten in Empfangsreihenfolge. Das nächste beginnt erst nach dem Abschluss des vorherigen, damit Änderungen am selben Server einander nicht überholen.

03

Parallel zwischen Servern.

Der Dispatcher unterscheidet Aufgaben anhand ihrer Schlüssel. Verschiedene Server können gleichzeitig arbeiten; nur Aufgaben mit demselben Schlüssel warten aufeinander.

04

Ein Ereignis, passende Aufgaben.

Dieselbe Nachricht erreicht AutoMod und Aktivitätsprotokoll zugleich. Beide bearbeiten sie getrennt für ihre jeweilige Aufgabe.

05

Temporäre Daten in Dragonfly.

Wartende Discord-Ereignisse und ihre Daten liegen in Dragonfly. Auch AutoMod und Aktivitätsprotokolle nutzen den gemeinsamen Speicher für temporäre Zustände. Die Ausführung der Aufgaben steuert weiterhin der Bot.

06

Ein Treffer, eine Reaktion.

Sobald ein aktivierter AutoMod-Filter anschlägt, endet die Prüfung dieser Nachricht. Weitere Filter lösen für dasselbe Ereignis keine zweite Moderationsreaktion aus.

07

Serverdaten mit Twilight.

Twilight hält Server, Mitglieder, Rollen, Kanäle, Emojis, Präsenzen und Sprachkanalzustände im Arbeitsspeicher aktuell. Nachrichten gehören nicht zu diesem Cache.

08

Interaktionen separat.

Interaktionen werden unabhängig von Serverereignissen eingeplant. READY bildet eine Zustandsgrenze innerhalb der jeweiligen Gateway-Verbindung.

09

Zuständigkeiten beim Sharding.

Dragonfly koordiniert die Zuständigkeit für die einzelnen Shards, also Gateway-Verbindungen. Bei einer Übernahme darf der frühere Besitzer keine weiteren Ereignisse übernehmen oder abschließen.

02 Fjell GrafikengineEigene Bildverarbeitung in Rust, SIMD und gemessene Leistung.

01 / Unsere Eigenentwicklung

Die Bilder tragen unsere Handschrift.

Fjell ist unsere hauseigene Grafikengine in Rust. Sie verbindet Hintergründe, Avatare und Texte zu persönlichen Willkommenskarten.

Wir wollten die Kontrolle darüber, wie diese Bilder entstehen. Deshalb haben wir eine Lösung entwickelt, die auf Fjord zugeschnitten ist und uns gestalterische Freiheit gibt.

Dabei geht es ebenso um Kosteneffizienz. Fjell erzielt maximale Leistung ohne Qualitätsverlust und hält die Generierung bei CPU und Arbeitsspeicher so effizient wie möglich. Das senkt unsere Serverkosten drastisch.

Die Umsetzung reicht bis zur Pixelverarbeitung. Selbst geschriebene SIMD Schleifen nutzen AVX2, FMA und BMI1/BMI2 für die parallele Berechnung mehrerer Bildpunkte.

Vorschau des Karteneditors von Fjord mit einer gestalteten Willkommenskarte
Gestaltung in Fjord. Gerendert mit Fjell.

Leistungsmessung

Kontrollierter Benchmark*

Vier Laststufen mit kontrollierten Kartenvariationen und demselben Testaufbau.

ParallelKarten/sKarten/minRenderzeit ØRenderzeit P50Renderzeit P95Renderzeit P99Gesamt ØGesamt P50Gesamt P95Gesamt P99CPU ØRAM Ø
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

Durchsatz-Skalierung

Gemessener Durchsatz im Vergleich zur perfekten linearen Skalierung.

GemessenIdeal linear
1248Parallele WorkerKarten/s
WorkerGemessenIdeal linearSkalierungEffizienz
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 %

Alle vier lokalen Tests liefen jeweils 60 Sekunden auf einem AMD Ryzen 9 9950X. Verwendet wurden 100 leichte Hintergründe mit normalen Farben oder Illustrationen und einer Dateigröße von etwa 100 bis 300 KB, typischerweise rund 200 KB. Der Liquid Layer blieb deaktiviert und die Schriftart konstant; zwischen den Karten variierten die Farben und Shaderpositionen von Text und Kreis.

Die Renderzeit umfasst die Bilderzeugung sowie die PNG Kodierung und Komprimierung bis zum fertigen PNG. Netzwerkübertragung und Downloadzeit sind nicht enthalten.

Der Lastgenerator arbeitete je nach Messlauf mit 1, 2, 4 oder 8 parallelen Anfragen. Eine neue Anfrage begann jeweils erst nach dem vollständigen Empfang und der Prüfung des vorherigen PNG. Die ausgewiesene Server CPU Auslastung entstand unter genau dieser Last. Die Grafikengine konnte ihre Arbeit serverseitig auf mehrere Kerne verteilen.

* Interne, nicht unabhängig verifizierte Messwerte unter den beschriebenen Bedingungen. Sie sind keine zugesicherte Eigenschaft, Garantie oder Leistungszusage. Die tatsächliche Leistung kann je nach System, Auslastung und Umgebung abweichen.

Aggressiver Zufallstest

Benchmark mit zufälligen Karten*

Ein deutlich variablerer Testaufbau mit 1.000 Hintergründen, 237 Schriftarten und zufälligen Effekten pro Anfrage.

ParallelKarten/sKarten/minRenderzeit ØRenderzeit P50Renderzeit P95Renderzeit P99Gesamt ØGesamt P50Gesamt P95Gesamt P99CPU ØRAM Ø
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

Durchsatz-Skalierung

Gemessener Durchsatz im Vergleich zur perfekten linearen Skalierung.

GemessenIdeal linear
1248Parallele WorkerKarten/s
WorkerGemessenIdeal linearSkalierungEffizienz
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

Diese vier lokalen Tests liefen jeweils 60 Sekunden auf demselben AMD Ryzen 9 9950X. Jede Anfrage wählte aus 1.000 aufwendigeren Hintergründen mit Dateigrößen von 800 KB bis 2,4 MB und aus 237 Schriftarten. Variiert wurden Texte, Transparenz, Schrift- und Avatargröße, Outline, Text- und Kreisfarben sowie Winkel, Stärke und Intensität der Shader. Bei etwa der Hälfte der Karten war zusätzlich der Liquid Layer mit zufälliger Farbe, Deckkraft und Unschärfe aktiv.

Der Lastgenerator verwendete 1, 2, 4 oder 8 parallele Worker in einem geschlossenen Kreislauf. Jeder Worker startete die nächste Anfrage erst, nachdem das vorherige PNG vollständig empfangen und validiert worden war. Alle 60-Sekunden-Läufe endeten ohne Fehler, Timeouts oder ungültige PNGs.

Die Renderzeit umfasst die Bilderzeugung sowie die PNG Kodierung und Komprimierung bis zum fertigen PNG. Netzwerkübertragung und Downloadzeit sind nicht enthalten.

* Interne, nicht unabhängig verifizierte Messwerte unter den beschriebenen Bedingungen. Sie sind keine zugesicherte Eigenschaft, Garantie oder Leistungszusage. Die tatsächliche Leistung kann je nach System, Auslastung und Umgebung abweichen.

03 TechnologiestackSprachen, Frameworks, Bibliotheken, Datenbanken und Objektspeicher.

02 / Unser technisches Fundament

Womit wir entwickeln.

Neben unserer eigenen Engine setzen wir auf Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB und RustFS. Jede Technologie übernimmt einen klaren Teil im System.

Programmiersprache

Rust

Rust

Rust bildet die Grundlage für unseren Discord-Bot, das Backend, den Karteneditor und die Grafikengine Fjell.

Logo © Rust Foundation. CC BY 4.0 · unverändert

Webframework

Leptos

Leptos

Für Teile unserer Weboberfläche setzen wir Leptos ein. Das Framework bringt Rust in den Browser und passt damit zu unserem übrigen Stack.

Logo der Leptos-Maintainer. MIT · unverändert

Webframework

Vue

Vue

Vue bildet die Komponenten für die öffentliche Website. Dazu gehören die Navigation, die Dokumentation und weitere interaktive Bereiche. So bleiben diese Oberflächen zusammenhängend und erweiterbar.

Logo © Evan You. CC BY-NC-SA 4.0 · unverändert

Bibliothek für Discord

Twilight

Twilight

Für die Anbindung an Discord nutzen wir Twilight. Die Bibliothek ist die Verbindung zwischen unserem in Rust programmierten Bot und Discord.

Logo von Fezhoof. CC BY-SA 4.0 · unverändert

Datenbank

Dragonfly ist unser gemeinsamer temporärer Datenspeicher für Discord-Ereignisse, die Koordination von Shards und mehreren Gateway-Verbindungen sowie AutoMod und Aktivitätsprotokolle.

Software unter BSL 1.1 mit zusätzlichem Nutzungsrecht.

Relationale Datenbank

PostgreSQL ergänzt unsere Datenhaltung für relationale Daten und Strukturen. Es läuft neben ScyllaDB als eigener Bestandteil unserer Infrastruktur.

Datenbank

ScyllaDB

ScyllaDB

ScyllaDB ist neben PostgreSQL ein Teil unserer Datenhaltung. Wir nutzen beide Systeme für unterschiedliche Aufgaben innerhalb von Fjord.

Logo gemäß dem ScyllaDB Media Kit

Objektspeicher

RustFS ist unser S3-kompatibler Objektspeicher. Damit ergänzen wir PostgreSQL und ScyllaDB um eine separate Storage-Schicht.

Software unter Apache 2.0. RustFS ist eine Marke von RustFS, Inc.