Fjord

Nos bastidores do Fjord

A tecnologia por trás do Fjord.

Um bot em Rust. Um motor gráfico próprio. E os frameworks, bibliotecas e bases de dados em que o Fjord se apoia.

Aqui mostramos o que desenvolvemos e as tecnologias que se juntam no Fjord.

01 O botO Fjord preserva a ordem dos eventos por servidor e processa tarefas independentes em paralelo.

Fjord

Processar eventos por ordem.

O Fjord processa os eventos do Discord por ordem e executa tarefas independentes em paralelo. O Twilight liga o bot ao Discord e mantém os dados dos servidores disponíveis localmente. O Dragonfly guarda eventos pendentes e ajuda a coordenar as ligações ao gateway.

01

READY delimita o estado.

Um novo READY espera pelas tarefas anteriores antes de o Fjord renovar o estado dos servidores. Os eventos seguintes começam depois, impedindo que o trabalho antigo substitua o novo estado.

02

FIFO por servidor.

Os eventos do mesmo servidor começam pela ordem de chegada. Cada um espera pelo fim do anterior para que as alterações desse servidor não se ultrapassem.

03

Servidores em paralelo.

O dispatcher distingue as tarefas por chave. Servidores diferentes podem avançar ao mesmo tempo; só as tarefas com a mesma chave esperam umas pelas outras.

04

Um evento, as tarefas certas.

A mesma mensagem chega ao AutoMod e ao registo de atividade ao mesmo tempo. Cada um trata-a separadamente para a sua tarefa.

05

Dados temporários no Dragonfly.

Os eventos pendentes do Discord e os seus dados ficam no Dragonfly. O AutoMod e os registos de atividade também usam este armazenamento comum para estados temporários. O bot continua a controlar a execução das tarefas.

06

Uma deteção, uma reação.

Quando um filtro ativo do AutoMod é acionado, termina a verificação dessa mensagem. Os outros filtros não provocam uma segunda ação para o mesmo evento.

07

Dados dos servidores com Twilight.

O Twilight mantém servidores, membros, cargos, canais, emojis, presenças e estados de voz atualizados em memória. As mensagens não fazem parte deste cache.

08

Interações separadas.

As interações são agendadas independentemente dos eventos dos servidores. READY define uma fronteira de estado dentro de cada ligação ao gateway.

09

Responsabilidade dos shards.

O Dragonfly coordena a responsabilidade por cada shard, ou ligação ao gateway. Após uma transferência, o responsável anterior deixa de poder assumir ou concluir novos eventos.

02 Motor gráfico FjellProcessamento de imagens em Rust, SIMD e desempenho medido.

01 / Desenvolvimento próprio

As imagens têm a nossa assinatura.

Fjell é o nosso motor gráfico desenvolvido em Rust. Combina fundos, avatares e textos para criar cartões de boas vindas pessoais.

Queríamos controlar a criação destas imagens. Por isso, desenvolvemos uma solução adaptada ao Fjord que nos dá liberdade criativa.

A eficiência de custos é igualmente importante. O Fjell oferece desempenho máximo sem perda de qualidade e mantém o uso de CPU e memória durante a geração o mais eficiente possível. Isso reduz drasticamente os nossos custos de servidor.

A nossa implementação chega ao processamento dos píxeis. Ciclos SIMD próprios utilizam AVX2, FMA e BMI1/BMI2 para calcular vários píxeis em paralelo.

Prévia do editor do Fjord com um cartão de boas vindas personalizado
Criado no Fjord. Renderizado com Fjell.

Medição de desempenho

Benchmark controlado*

Quatro níveis de carga com variações controladas dos cartões e a mesma configuração de teste.

ParaleloCartões/sCartões/minRenderização méd.Renderização P50Renderização P95Renderização P99Total méd.Total P50Total P95Total P99CPU méd.RAM méd.
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

Escalonamento do débito

Débito medido comparado com um escalonamento linear perfeito.

MedidoLinear ideal
1248Workers paralelosCartões/s
WorkersMedidoLinear idealEscalonamentoEficiência
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 %

Os quatro testes locais duraram 60 segundos cada num AMD Ryzen 9 9950X. Foram usados 100 fundos leves com cores normais ou ilustrações e ficheiros de cerca de 100 a 300 KB, normalmente próximos de 200 KB. A camada líquida permaneceu desativada e a fonte constante; as cores e posições dos shaders do texto e do círculo variaram entre os cartões.

O tempo de renderização inclui a geração da imagem e a codificação e compressão PNG até ao PNG final. A transferência de rede e o tempo de download não estão incluídos.

O gerador de carga utilizou 1, 2, 4 ou 8 pedidos paralelos consoante o teste. Um novo pedido só começava depois de o PNG anterior ter sido totalmente recebido e validado. A utilização da CPU indicada ocorreu exatamente sob esta carga. O motor gráfico podia distribuir o trabalho por vários núcleos.

* Medições internas não verificadas de forma independente, realizadas nas condições descritas. Não constituem característica assegurada, garantia ou compromisso de desempenho. O desempenho real pode variar consoante o sistema, a carga e o ambiente.

Teste aleatório agressivo

Teste de desempenho com cartões aleatórios*

Uma configuração muito mais variável com 1.000 fundos, 237 fontes e efeitos aleatórios em cada pedido.

ParaleloCartões/sCartões/minRenderização méd.Renderização P50Renderização P95Renderização P99Total méd.Total P50Total P95Total P99CPU méd.RAM méd.
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

Escalonamento do débito

Débito medido comparado com um escalonamento linear perfeito.

MedidoLinear ideal
1248Workers paralelosCartões/s
WorkersMedidoLinear idealEscalonamentoEficiência
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

Estes quatro testes locais duraram 60 segundos cada no mesmo AMD Ryzen 9 9950X. Cada pedido escolheu entre 1.000 fundos mais exigentes de 800 KB a 2,4 MB e 237 fontes. Variaram-se textos, transparência, tamanhos da fonte e do avatar, contorno, cores do texto e do círculo, além do ângulo, força e intensidade dos shaders. Cerca de metade dos cartões também ativou a camada líquida com cor, opacidade e desfocagem aleatórias.

O gerador de carga utilizou 1, 2, 4 ou 8 workers paralelos num ciclo fechado. Cada worker iniciou o pedido seguinte apenas depois de o PNG anterior ter sido totalmente recebido e validado. Todos os testes de 60 segundos terminaram sem erros, timeouts ou PNG inválidos.

O tempo de renderização inclui a geração da imagem e a codificação e compressão PNG até ao PNG final. A transferência de rede e o tempo de download não estão incluídos.

* Medições internas não verificadas de forma independente, realizadas nas condições descritas. Não constituem característica assegurada, garantia ou compromisso de desempenho. O desempenho real pode variar consoante o sistema, a carga e o ambiente.

03 TecnologiasLinguagens, frameworks, bibliotecas, bases de dados e armazenamento de objetos.

02 / A nossa base técnica

Com o que desenvolvemos.

Além do nosso próprio motor, usamos Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB e RustFS. Cada tecnologia tem uma função clara no sistema.

Linguagem de programação

Rust

Rust

Rust é a base do nosso bot para Discord, do backend, do editor de cartões e do motor gráfico Fjell.

Logótipo © Rust Foundation. CC BY 4.0 · sem alterações

Framework web

Leptos

Leptos

Usamos Leptos em partes da nossa interface web. O framework leva Rust para o navegador e encaixa naturalmente no restante da nossa stack.

Logótipo dos mantenedores do Leptos. MIT · sem alterações

Framework web

Vue

Vue

Vue organiza os componentes do site público, da navegação e documentação a outras áreas interativas. Assim, as interfaces mantêm-se coerentes e fáceis de expandir.

Logótipo © Evan You. CC BY-NC-SA 4.0 · sem alterações

Biblioteca para Discord

Twilight

Twilight

Utilizamos Twilight para a ligação ao Discord. A biblioteca liga o nosso bot escrito em Rust ao Discord.

Logótipo de Fezhoof. CC BY-SA 4.0 · sem alterações

Base de dados

O Dragonfly é o nosso armazenamento temporário comum para eventos do Discord, coordenação de shards e várias ligações ao gateway, AutoMod e registos de atividade.

Software sob BSL 1.1 com uma autorização de utilização adicional.

Base de dados relacional

O PostgreSQL complementa a nossa camada de dados para dados e estruturas relacionais. Funciona ao lado do ScyllaDB como uma parte separada da nossa infraestrutura.

Armazenamento de objetos

Usamos RustFS para armazenamento de objetos compatível com S3. Ele adiciona uma camada de armazenamento separada ao lado de PostgreSQL e ScyllaDB.

Software sob Apache 2.0. RustFS é uma marca da RustFS, Inc.