Fjord

Una mirada al interior de Fjord

La tecnología detrás de Fjord.

Un bot en Rust. Un motor gráfico propio. Y los frameworks, bibliotecas y bases de datos sobre los que se apoya Fjord.

Aquí mostramos qué desarrollamos nosotros y qué tecnologías se unen en Fjord.

01 El botFjord conserva el orden de cada servidor y procesa las tareas independientes en paralelo.

Fjord

Procesar eventos en orden.

Fjord procesa los eventos de Discord en orden y ejecuta tareas independientes en paralelo. Twilight conecta el bot con Discord y mantiene los datos del servidor disponibles localmente. Dragonfly almacena eventos pendientes y ayuda a coordinar las conexiones del gateway.

01

READY delimita el estado.

Un nuevo READY espera las tareas anteriores antes de renovar el estado de los servidores. Los eventos posteriores comienzan después, de modo que el trabajo antiguo no puede sobrescribir el estado nuevo.

02

FIFO por servidor.

Los eventos de un mismo servidor empiezan en orden de llegada. Cada uno espera a que termine el anterior para que los cambios del servidor no se adelanten entre sí.

03

Servidores en paralelo.

El dispatcher distingue las tareas por clave. Los servidores distintos pueden avanzar a la vez; solo esperan entre sí las tareas que comparten clave.

04

Un evento, tareas adecuadas.

El mismo mensaje llega a AutoMod y al registro de actividad a la vez. Cada uno lo trata por separado para su propia tarea.

05

Datos temporales en Dragonfly.

Los eventos pendientes de Discord y sus datos se almacenan en Dragonfly. AutoMod y los registros de actividad también utilizan este almacén compartido para estados temporales. El bot sigue controlando la ejecución de las tareas.

06

Una coincidencia, una reacción.

Cuando se activa un filtro de AutoMod, termina la comprobación de ese mensaje. Los demás filtros no provocan una segunda medida para el mismo evento.

07

Datos del servidor con Twilight.

Twilight mantiene actualizados en memoria servidores, miembros, roles, canales, emojis, presencias y estados de voz. Los mensajes no forman parte de esta caché.

08

Interacciones independientes.

Las interacciones se planifican independientemente de los eventos del servidor. READY establece un límite de estado dentro de cada conexión del gateway.

09

Responsabilidad de los shards.

Dragonfly coordina la responsabilidad de cada shard, es decir, de cada conexión del gateway. Tras un traspaso, el responsable anterior no puede asumir ni completar más eventos.

02 Motor gráfico FjellProcesamiento de imágenes en Rust, SIMD y rendimiento medido.

01 / Desarrollo propio

Nuestras imágenes llevan nuestra firma.

Fjell es nuestro motor gráfico propio, escrito en Rust. Combina fondos, avatares y textos para crear tarjetas de bienvenida personales.

Queríamos controlar cómo se crean estas imágenes. Por eso desarrollamos una solución adaptada a Fjord que nos da libertad creativa.

La eficiencia de costes es igual de importante. Fjell ofrece el máximo rendimiento sin perder calidad y mantiene el uso de CPU y memoria durante la generación lo más eficiente posible. Así reducimos drásticamente los costes de servidor.

Nuestra implementación llega hasta el procesamiento de píxeles. Los bucles SIMD propios utilizan AVX2, FMA y BMI1/BMI2 para calcular varios píxeles en paralelo.

Vista previa del editor de Fjord con una tarjeta de bienvenida diseñada
Diseñado en Fjord. Renderizado con Fjell.

Medición de rendimiento

Prueba controlada*

Cuatro niveles de carga con variaciones controladas de las tarjetas y la misma configuración de prueba.

ParaleloTarjetas/sTarjetas/minRenderizado prom.Renderizado P50Renderizado P95Renderizado P99Total prom.Total P50Total P95Total P99CPU prom.RAM prom.
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

Escalado del rendimiento

Rendimiento medido frente a un escalado lineal perfecto.

MedidoLineal ideal
1248Workers paralelosTarjetas/s
WorkersMedidoLineal idealEscaladoEficiencia
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 %

Las cuatro pruebas locales duraron 60 segundos cada una en un AMD Ryzen 9 9950X. Se utilizaron 100 fondos ligeros con colores normales o ilustraciones y archivos de unos 100 a 300 KB, normalmente alrededor de 200 KB. La capa líquida permaneció desactivada y la fuente fue constante; entre tarjetas variaron los colores y las posiciones de los shaders del texto y del círculo.

El tiempo de renderizado incluye la generación de la imagen y la codificación y compresión PNG hasta obtener el PNG final. No incluye la transferencia por red ni el tiempo de descarga.

El generador de carga utilizó 1, 2, 4 u 8 solicitudes paralelas según la prueba. Cada nueva solicitud comenzaba después de recibir y validar por completo el PNG anterior. El uso de CPU indicado se produjo exactamente bajo esta carga. El motor gráfico podía repartir el trabajo entre varios núcleos.

* Mediciones internas no verificadas de forma independiente y realizadas bajo las condiciones descritas. No constituyen una característica garantizada, garantía ni compromiso de rendimiento. El rendimiento real puede variar según el sistema, la carga y el entorno.

Prueba aleatoria agresiva

Prueba de rendimiento con tarjetas aleatorias*

Una configuración mucho más variable con 1.000 fondos, 237 fuentes y efectos aleatorios en cada solicitud.

ParaleloTarjetas/sTarjetas/minRenderizado prom.Renderizado P50Renderizado P95Renderizado P99Total prom.Total P50Total P95Total P99CPU prom.RAM prom.
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

Escalado del rendimiento

Rendimiento medido frente a un escalado lineal perfecto.

MedidoLineal ideal
1248Workers paralelosTarjetas/s
WorkersMedidoLineal idealEscaladoEficiencia
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

Estas cuatro pruebas locales duraron 60 segundos cada una en el mismo AMD Ryzen 9 9950X. Cada solicitud eligió entre 1.000 fondos más exigentes de entre 800 KB y 2,4 MB y entre 237 fuentes. Se variaron textos, transparencia, tamaños de fuente y avatar, contorno, colores de texto y círculo, y ángulo, fuerza e intensidad de los shaders. Aproximadamente la mitad de las tarjetas activó además la capa líquida con color, opacidad y desenfoque aleatorios.

El generador de carga utilizó 1, 2, 4 u 8 workers paralelos en un bucle cerrado. Cada worker inició la siguiente solicitud solo después de recibir y validar por completo el PNG anterior. Todas las pruebas de 60 segundos finalizaron sin errores, tiempos de espera agotados ni PNG no válidos.

El tiempo de renderizado incluye la generación de la imagen y la codificación y compresión PNG hasta obtener el PNG final. No incluye la transferencia por red ni el tiempo de descarga.

* Mediciones internas no verificadas de forma independiente y realizadas bajo las condiciones descritas. No constituyen una característica garantizada, garantía ni compromiso de rendimiento. El rendimiento real puede variar según el sistema, la carga y el entorno.

03 TecnologíasLenguajes, frameworks, bibliotecas, bases de datos y almacenamiento de objetos.

02 / Nuestra base técnica

Con qué desarrollamos.

Además de nuestro propio motor, usamos Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB y RustFS. Cada tecnología cumple una función concreta en el sistema.

Lenguaje de programación

Rust

Rust

Rust es la base de nuestro bot de Discord, el backend, el editor de tarjetas y el motor gráfico Fjell.

Logotipo © Rust Foundation. CC BY 4.0 · sin modificaciones

Framework web

Leptos

Leptos

Usamos Leptos en partes de nuestra interfaz web. El framework lleva Rust al navegador y encaja con el resto de nuestro stack.

Logo de los mantenedores de Leptos. MIT · sin modificaciones

Framework web

Vue

Vue

Vue organiza los componentes del sitio público, desde la navegación y la documentación hasta otras áreas interactivas. Así podemos ampliar la interfaz de forma coherente.

Logotipo © Evan You. CC BY-NC-SA 4.0 · sin modificaciones

Biblioteca para Discord

Twilight

Twilight

Utilizamos Twilight para conectarnos a Discord. Esta biblioteca enlaza nuestro bot escrito en Rust con Discord.

Logotipo de Fezhoof. CC BY-SA 4.0 · sin modificaciones

Base de datos

Dragonfly es nuestro almacén temporal compartido para eventos de Discord, coordinación de shards y múltiples conexiones del gateway, AutoMod y registros de actividad.

Software bajo BSL 1.1 con una autorización de uso adicional.

Base de datos relacional

PostgreSQL complementa nuestra capa de datos para información y estructuras relacionales. Funciona junto a ScyllaDB como una parte independiente de nuestra infraestructura.

Almacenamiento de objetos

Usamos RustFS para almacenamiento de objetos compatible con S3. Añade una capa de almacenamiento separada junto a PostgreSQL y ScyllaDB.

Software bajo Apache 2.0. RustFS es una marca de RustFS, Inc.