Fjord

Fjord の舞台裏

Fjord を支える技術。

Rust 製の Bot、自社開発のグラフィックスエンジン。そして Fjord を支えるフレームワーク、ライブラリ、データベース。

私たちが独自に開発しているものと、Fjord を構成する技術をご紹介します。

01 ボットFjord はサーバーごとのイベント順序を守り、独立した処理を並列に進めます。

Fjord

イベントを順序どおりに処理。

Fjord は Discord イベントを順序どおりに処理し、独立したタスクを並行実行します。Twilight はボットを Discord に接続し、サーバーデータをローカルで保持します。Dragonfly は処理待ちのイベントを保存し、ゲートウェイ接続の調整を支えます。

01

READY は状態の境界。

新しい READY は以前の処理が終わるまで待ってからサーバー状態を更新します。後続イベントはその後に開始され、古い処理による上書きを防ぎます。

02

サーバーごとの FIFO。

同じサーバーのイベントは到着順に開始されます。前の処理が終わるまで次を待たせ、状態変更が追い越し合うのを防ぎます。

03

サーバー間は並列。

ディスパッチャーはキーで処理を区別します。異なるサーバーは同時に進み、同じキーの処理だけが順番を待ちます。

04

一つのイベントを適切な担当へ。

同じメッセージが AutoMod とアクティビティログの両方に届きます。それぞれが自分の役割として別々に処理します。

05

Dragonfly に一時データを保存。

処理待ちの Discord イベントとそのデータは Dragonfly に保存されます。AutoMod とアクティビティログも、一時的な状態にこの共有ストアを使用します。タスクの実行は引き続きボットが制御します。

06

一度の検出に一度の対応。

有効な AutoMod フィルターが一致すると、そのメッセージの検査を終了します。他のフィルターが同じイベントに二度目の措置を行うことはありません。

07

Twilight のサーバーデータ。

Twilight はサーバー、メンバー、ロール、チャンネル、絵文字、プレゼンス、ボイス状態をメモリ内で最新に保ちます。メッセージはこのキャッシュに含まれません。

08

インタラクションは個別に処理。

インタラクションはサーバーイベントとは独立してスケジュールされます。READY は各ゲートウェイ接続内で状態の境界を定めます。

09

シャードの担当管理。

Dragonfly は各シャード、つまりゲートウェイ接続の担当を調整します。引き継ぎ後、以前の担当は以降のイベントを取得したり完了したりできません。

02 Fjell 画像エンジンRust による画像処理、SIMD、実測した性能。

01 / 独自開発

画像にも、私たちらしさを。

Fjell は Rust で独自開発したグラフィックエンジンです。背景、アバター、テキストを組み合わせて、個別のウェルカムカードを生成します。

画像の生成方法を自分たちで制御したい。そのため、Fjord の用途に合わせた仕組みを開発し、自由な表現を可能にしました。

コスト効率も同じく重要です。Fjell は品質を損なわずに最大限の性能を発揮し、生成時の CPU とメモリ使用量を可能な限り効率化します。これにより、サーバーコストを大幅に削減できます。

独自の実装はピクセル処理にまで及びます。自作の SIMD ループが AVX2、FMA、BMI1/BMI2 を使用し、複数のピクセルを並列に計算します。

デザインしたウェルカムカードを表示する Fjord カードエディターのプレビュー
Fjord でデザイン。Fjell でレンダリング。

性能測定

制御されたベンチマーク*

4 段階の負荷、制御されたカードの変化、同一のテスト構成です。

並列数カード/秒カード/分レンダー平均レンダー P50レンダー P95レンダー P99合計平均合計 P50合計 P95合計 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

スループットのスケーリング

実測スループットと理想的な線形スケーリングの比較。

実測理想線形
1248並列ワーカーカード/秒
ワーカー実測理想線形スケーリング効率
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 %

4 回のローカルテストはいずれも AMD Ryzen 9 9950X 上で 60 秒間実行し、通常の色またはイラストを使った 100 種類の軽量な背景を使用しました。ファイルサイズは約 100~300 KB、標準的には約 200 KB です。Liquid Layer は無効、フォントは固定とし、カードごとにテキストと円の色およびシェーダー位置だけを変化させました。

レンダリング時間には画像生成に加えて PNG のエンコードと圧縮が含まれ、完成した PNG が得られるまでを計測しています。ネットワーク転送とダウンロード時間は含みません。

負荷生成側はテストに応じて 1、2、4、8 件の並列要求を使用しました。新しい要求は前の PNG を完全に受信して検証した後に開始しました。表示した CPU 使用率はこの負荷条件で発生した値です。グラフィックエンジンは処理を複数コアへ分散できました。

* 記載条件での社内測定であり、独立した検証は行われていません。保証された特性、保証、または性能上の確約を構成するものではありません。実際の性能はシステム、負荷、環境によって異なります。

高負荷ランダムテスト

ランダムカードのベンチマーク*

1,000 種類の背景、237 種類のフォント、リクエストごとのランダム効果を使う、より変化の大きいテスト構成です。

並列数カード/秒カード/分レンダー平均レンダー P50レンダー P95レンダー P99合計平均合計 P50合計 P95合計 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

スループットのスケーリング

実測スループットと理想的な線形スケーリングの比較。

実測理想線形
1248並列ワーカーカード/秒
ワーカー実測理想線形スケーリング効率
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

4 回のローカルテストはいずれも同じ AMD Ryzen 9 9950X 上で 60 秒間実行しました。各リクエストは 800 KB~2.4 MB の高負荷な背景 1,000 種類と 237 種類のフォントから選択し、テキスト、透明度、フォントとアバターのサイズ、アウトライン、テキストと円の色、シェーダーの角度・強さ・色強度を変化させました。約半数のカードでは Liquid Layer も有効にし、色、不透明度、ぼかしをランダム化しました。

負荷生成側は閉ループで 1、2、4、8 個の並列ワーカーを使用しました。各ワーカーは前の PNG を完全に受信して検証した後に次のリクエストを開始しました。すべての 60 秒テストはエラー、タイムアウト、無効な PNG なしで完了しました。

レンダリング時間には画像生成に加えて PNG のエンコードと圧縮が含まれ、完成した PNG が得られるまでを計測しています。ネットワーク転送とダウンロード時間は含みません。

* 記載条件での社内測定であり、独立した検証は行われていません。保証された特性、保証、または性能上の確約を構成するものではありません。実際の性能はシステム、負荷、環境によって異なります。

03 技術スタック言語、フレームワーク、ライブラリ、データベース、オブジェクトストレージ。

02 / 技術の基盤

開発を支えるもの。

独自エンジンに加えて、Rust、Leptos、TypeScript、Vue、Twilight、Dragonfly、PostgreSQL、ScyllaDB、RustFS を使用しています。それぞれがシステム内で明確な役割を担います。

プログラミング言語

Rust

Rust

Rust は、Discord ボット、バックエンド、カードエディター、Fjell グラフィックエンジンの基盤です。

ロゴ © Rust Foundation。CC BY 4.0 · 変更なし

Web フレームワーク

Leptos

Leptos

Web インターフェースの一部には Leptos を使用しています。Rust をブラウザ側でも使えるため、ほかの技術スタックとも自然につながります。

ロゴ制作:Leptos メンテナー。MIT · 変更なし

Web フレームワーク

Vue

Vue

Vue は公開サイトのナビゲーション、ドキュメント、その他の操作部分をコンポーネントとして構成します。

ロゴ © Evan You. CC BY-NC-SA 4.0 · 変更なし

Discord 用ライブラリ

Twilight

Twilight

Discord との接続には Twilight を使用しています。このライブラリが、Rust で書かれたボットと Discord をつなぎます。

Fezhoof によるロゴ。CC BY-SA 4.0 · 変更なし

データベース

Dragonfly は Discord イベント、シャードと複数のゲートウェイ接続の調整、AutoMod、アクティビティログに使用する共有の一時データストアです。

ソフトウェアは追加の使用許諾付き BSL 1.1。

リレーショナルデータベース

PostgreSQL は、リレーショナルなデータや構造を扱うためのデータ層を補完します。ScyllaDB と並ぶ独立したインフラ構成要素です。

オブジェクトストレージ

S3 互換のオブジェクトストレージとして RustFS を使用しています。PostgreSQL と ScyllaDB に加えて、独立したストレージ層を構成します。

ソフトウェア Apache 2.0. RustFS は RustFS, Inc. の商標です。