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.
Ein Blick hinter Fjord
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.
Fjord
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
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
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
Der Dispatcher unterscheidet Aufgaben anhand ihrer Schlüssel. Verschiedene Server können gleichzeitig arbeiten; nur Aufgaben mit demselben Schlüssel warten aufeinander.
04
Dieselbe Nachricht erreicht AutoMod und Aktivitätsprotokoll zugleich. Beide bearbeiten sie getrennt für ihre jeweilige Aufgabe.
05
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
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
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 werden unabhängig von Serverereignissen eingeplant. READY bildet eine Zustandsgrenze innerhalb der jeweiligen Gateway-Verbindung.
09
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.
01 / Unsere Eigenentwicklung
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.
Leistungsmessung
Vier Laststufen mit kontrollierten Kartenvariationen und demselben Testaufbau.
| Parallel | Karten/s | Karten/min | Renderzeit Ø | Renderzeit P50 | Renderzeit P95 | Renderzeit P99 | Gesamt Ø | Gesamt P50 | Gesamt P95 | Gesamt P99 | CPU Ø | RAM Ø |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 797,48 | 47.849 | 1,062 ms | 1,061 ms | 1,226 ms | 1,242 ms | 1,253 ms | 1,251 ms | 1,428 ms | 1,473 ms | 88,3 % | 381,2 MiB |
| 2 | 1.577,95 | 94.677 | 1,038 ms | 1,004 ms | 1,225 ms | 1,421 ms | 1,266 ms | 1,236 ms | 1,470 ms | 1,715 ms | 173,5 % | 360,1 MiB |
| 4 | 3.173,00 | 190.380 | 1,023 ms | 1,011 ms | 1,188 ms | 1,230 ms | 1,259 ms | 1,243 ms | 1,448 ms | 1,557 ms | 344,9 % | 375,3 MiB |
| 8 | 5.850,25 | 351.015 | 1,050 ms | 1,026 ms | 1,194 ms | 1,290 ms | 1,366 ms | 1,349 ms | 1,578 ms | 1,803 ms | 647,0 % | 385,8 MiB |
Gemessener Durchsatz im Vergleich zur perfekten linearen Skalierung.
| Worker | Gemessen | Ideal linear | Skalierung | Effizienz |
|---|---|---|---|---|
| 1 | 797,48 | 797,48 | 1,00× | 100,0 % |
| 2 | 1.577,95 | 1.594,96 | 1,98× | 98,9 % |
| 4 | 3.173,00 | 3.189,92 | 3,98× | 99,5 % |
| 8 | 5.850,25 | 6.379,84 | 7,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
Ein deutlich variablerer Testaufbau mit 1.000 Hintergründen, 237 Schriftarten und zufälligen Effekten pro Anfrage.
| Parallel | Karten/s | Karten/min | Renderzeit Ø | Renderzeit P50 | Renderzeit P95 | Renderzeit P99 | Gesamt Ø | Gesamt P50 | Gesamt P95 | Gesamt P99 | CPU Ø | RAM Ø |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 92,65 | 5.559 | 9,775 ms | 10,478 ms | 12,781 ms | 13,401 ms | 10,788 ms | 11,553 ms | 14,006 ms | 14,784 ms | 93,6 % | 1.205,6 MiB |
| 2 | 184,53 | 11.072 | 9,944 ms | 10,621 ms | 12,858 ms | 13,550 ms | 10,832 ms | 11,576 ms | 13,938 ms | 14,698 ms | 189,1 % | 1.278,8 MiB |
| 4 | 358,82 | 21.529 | 10,209 ms | 10,855 ms | 13,240 ms | 13,997 ms | 11,138 ms | 11,857 ms | 14,363 ms | 15,212 ms | 377,7 % | 1.300,9 MiB |
| 8 | 660,52 | 39.631 | 10,897 ms | 11,610 ms | 14,343 ms | 15,336 ms | 12,101 ms | 12,889 ms | 15,838 ms | 16,880 ms | 744,8 % | 1.308,6 MiB |
Gemessener Durchsatz im Vergleich zur perfekten linearen Skalierung.
| Worker | Gemessen | Ideal linear | Skalierung | Effizienz |
|---|---|---|---|---|
| 1 | 92,65 | 92,65 | 1,00× | 100,0 % |
| 2 | 184,53 | 185,30 | 1,99× | 99,6 % |
| 4 | 358,82 | 370,60 | 3,87× | 96,8 % |
| 8 | 660,52 | 741,20 | 7,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.
02 / Unser technisches Fundament
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 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
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
Programmiersprache
Für die interaktiven öffentlichen Seiten schreiben wir TypeScript. Die Typprüfung hilft uns, Komponenten und Zustände konsistent zu halten.
Offizielles Logo von TypeScript. Nutzung gemäß den Markenrichtlinien.
Webframework
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
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 ist neben PostgreSQL ein Teil unserer Datenhaltung. Wir nutzen beide Systeme für unterschiedliche Aufgaben innerhalb von Fjord.
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.