Fjord

走进 Fjord 幕后

Fjord 背后的技术。

一个用 Rust 编写的机器人,一套自研图形引擎,以及 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 渲染。

性能测量

受控基准测试*

四种负载级别、受控的卡片变化和相同的测试设置。

并行数卡片/秒卡片/分钟渲染平均渲染 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 %

四个本地测试均在 AMD Ryzen 9 9950X 上运行 60 秒,使用了 100 个采用普通颜色或插图的轻量背景,文件大小约为 100 至 300 KB,通常约 200 KB。液态图层保持关闭,字体保持不变;各卡片之间仅改变文字和圆形的颜色及其着色器位置。

渲染时间包括图像生成以及 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 %

这四个本地测试均在同一台 AMD Ryzen 9 9950X 上运行 60 秒。每次请求从 1,000 个大小为 800 KB 至 2.4 MB 的高复杂度背景和 237 种字体中选择,并随机改变文本、透明度、字体和头像大小、描边、文字和圆形颜色,以及着色器的角度、强度和色彩强度。约一半卡片还会启用液态图层,并随机设置颜色、不透明度和模糊程度。

负载生成器在闭环中使用 1、2、4 或 8 个并行 worker。每个 worker 只有在完整接收并验证前一个 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

我们使用 Twilight 连接 Discord。这个库将我们用 Rust 编写的机器人与 Discord 相连。

标志由 Fezhoof 创作。CC BY-SA 4.0 · 未经修改

数据库

Dragonfly 是我们的共享临时数据存储,用于 Discord 事件、分片和多条网关连接的协调,以及 AutoMod 和活动日志。

软件采用 BSL 1.1 许可,并提供额外使用授权。

关系型数据库

PostgreSQL 用于补充关系型数据和结构的数据层,并与 ScyllaDB 一同作为基础设施中的独立组成部分运行。

对象存储

我们使用 RustFS 提供兼容 S3 的对象存储,并在 PostgreSQL 与 ScyllaDB 之外增加独立的存储层。

软件许可 Apache 2.0. RustFS 是 RustFS, Inc. 的商标。