介绍DoomBench - 您的数据栈能运行DOOM吗?

Lobsters Hottest 工具

摘要

CedarDB推出了DoomBench,这是一个基准测试,通过纯SQL运行一个多玩家类DOOM游戏,以压力测试数据栈在分析和事务工作负载下的性能,并提供直观的性能比较。

<p><a href="https://lobste.rs/s/nkafrw/introducing_doombench_can_your_data">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/26 17:22

# 介绍 DoomBench——你的数据栈能运行 DOOM 吗? 来源:https://cedardb.com/blog/doombench/ dev2026年4月22日·12分钟 ## 你的数据栈能运行 DOOM 吗? ## TL;DR 我们在不同的数据栈架构上,用纯 SQL 运行了一个多人 DOOM 服务器,录制了精彩的视频,并测量了哪些部分最先崩溃。 - 点击这里 (https://cedardb.com/doombench) 直接进入基准测试页面(含视频)。 - 下面是一个 CedarDB 经受“DOOMbench”考验的视频:Your browser does not support the video tag. ## 为什么是 DOOM? > 严谨说明:最初的 DOOMQL 使用的是光线投射算法,而非 BSP 树 (https://en.wikipedia.org/wiki/Binary_space_partitioning),因此有部分人指出 (https://news.ycombinator.com/item?id=45196767) 它在技术上更像是《德军总部》而不是《DOOM》。 去年,我们发布了 DOOMQL (https://cedardb.com/blog/doomql):一款完全运行在 SQL 内部的类 DOOM 多人游戏,使用递归 CTE 进行光线投射,并采用真正的客户端-服务器架构,玩家直接连接到数据库。当它登上 Hacker News 首页 (https://news.ycombinator.com/item?id=45183050) 时,我们非常激动。DOOMBench 建立在 DOOMQL 之上,并将其转变为对不同数据栈的压力测试。延迟数字和吞吐量图表很容易报告,但很难*感受*到。而数据库在努力渲染游戏画面时的视频,却能让人立刻感同身受! 让我们看看 DOOMQL 所涵盖的三个维度: - **原始分析性能**:DOOMQL 使用递归 CTE (https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL) 通过光线投射在 ASCII 艺术中渲染游戏世界。这是 SQL 中最需要数值计算的操作了!有人可能会反驳说,这并非真实世界中的代表性工作负载,对此我的回应是:可能确实如此,但这种事有先例 (https://canitrundoom.org/)。 - **事务处理**:DOOMQL 采用客户端-服务器架构。客户端直接连接到数据库,并将其输入插入到 `inputs` 表中:WASD 移动,X 射击。这不会产生大量事务(假设 10 个玩家每 200 毫秒发送一个输入 → 每秒 50 个事务),但延迟是一个大问题。如果你玩过高延迟 ping 的多人射击游戏,你就能理解。此外,服务器还必须每秒多次运行一个*游戏循环*。其频率可以低至每分钟 100 次 tick(《Runescape》),高至每秒 128 次 tick(《Valorant》)。 - **原子性**:没有什么比被一个在你屏幕上已经死亡的玩家击中更糟糕的了。优秀的数据库系统能够以*原子*方式执行事务。要么全部生效,要么全部不生效:不可能存在一个生命值小于等于 0 却还没有被杀死并重生的玩家。这实际上不是一个可以*测量*的指标:要么成立,要么不成立。幸运的是,如今几乎所有严肃的数据库都提供了这样的 ACID 保证。 有趣的是,要让你的数据栈在分析处理和事务处理两方面都表现出色非常困难。分析工作负载想要处理大量数据,通常受限于带宽(内存、磁盘、缓存)。事务处理则希望写入操作响应迅速,通常受限于延迟。这两种方法传统上采用不同的数据布局、数据结构和系统架构。让我们在 DOOM 的背景下探讨它们! ## 一个运行着 DOOM 的数据库看起来什么样? 我们以 Postgres 为例。下面是它运行 DOOMbench 的视频: Your browser does not support the video tag.让我们看看我们看到了什么: - 左侧的主视图显示玩家的视角:光线投射的游戏视图本身、一个带有玩家视野锥的小地图,以及一个包含玩家生命值、弹药和击杀数的得分面板。 - 其右侧是一个*世界状态*的小地图。这是 Postgres 当前所处的状态,即不是渲染给客户端的视图,而是当前 tick 时数据库的状态。 - 在下面,我们看到玩家的输入,以及一些性能数字:服务器的 tick 率和 FPS(帧率),既有当前值也有历史图表。 那么,数据在整个系统中是如何流动的呢?让我们看看要渲染一个新视图必须完成哪些步骤: ### 1. 输入 玩家按下 'W',这会在 `inputs` 表中追加一行:`insert into inputs(player_id, action, timestamp) values (47, 'W', now())`。 ### 2. 游戏 tick 下一个游戏 tick 会读取该行,更新玩家位置(只要玩家没有死亡,移动没有被墙壁阻挡等等)。我们将服务器 tick 率限制为每秒 35 次 tick(与原始 DOOM 相同)。tick 和输入是同步处理的。 ### 3. 渲染 客户端可以通过查询一个视图来请求帧,该视图会在后台按需执行所有光线投射:`select full_row from frames_by_row where player_id = 47 order by f.row asc`(见这里 (https://github.com/cedardb/DOOMQL/blob/8d6c2fc7e9548df1800a6618b205aad37fe5db20/pyclient.py#L65)) 渲染循环与游戏 tick 循环解耦(游戏设计基础 101),从而产生了真正的混合工作负载:每个客户端都想最大化自己的 FPS(这里没有垂直同步,分析型工作负载),而服务器同时仍然必须能够以每秒 35 次 tick 处理所有输入(事务型工作负载),同时玩家们继续愉快地随时发送他们的输入(事务型工作负载 #2)。 由于渲染非常(!)昂贵,并且游戏 tick 循环与渲染循环解耦,玩家的视图可能会与游戏状态严重不同步。 你可以在上面的 Postgres 中看到这一点:虽然它大约能每秒处理 10 次 tick,但渲染视图需要好几秒钟。玩家进行了一次平滑的 360 度转身,这在游戏状态中可见,但输出却永远跟不上。虽然服务器已经*知道*发生在你身上的事,但你却不知道!我想我们都同意,一位《反恐精英》职业选手不会认为这是*可玩的*。 ## OLAP:让我们在数据湖里完成所有事情! 好吧,虽然 Postgres 是一个久经考验的数据库系统,但它似乎不适合我们的工作负载,因为它的速度不够快,无法每秒推送足够的帧。让我们改用纯 OLAP 系统吧!它们专为回答复杂分析查询而构建,所以它们应该能推送大量 FPS,对吧? 没错,但不幸的是,它们在事务处理方面非常糟糕,而且通常根本没有办法进行实时事务处理。如果您的输入没有被处理,那么渲染大量帧有什么价值呢? 有两种方法可以绕过这个限制:中间带有一个 ETL 管道的两个系统(提取-转换-加载),或者我亲切地称之为套娃方法。让我们看看这两种方法! ### ETL 这个概念非常简单:让我们使用一个非常擅长事务处理的系统和一个非常擅长分析处理的系统,并在中间插入一个复制数据的管道(所谓的 ETL 管道)。事务系统可以专注于处理所有玩家输入并运行游戏循环,而分析系统则可以推送 FPS。 以下是这样一个设置。它使用 Postgres 作为事务系统,DuckDB 作为分析系统。一个简单的 CDC(变更数据捕获)循环每秒运行一次,并将所有表从 Postgres 复制到 DuckDB。结果如下: Your browser does not support the video tag.看起来好不了多少,对吧? 但实际上,*确实*好多了!如果你看图表,你会发现 DuckDB 能够推送出可观的 10 FPS(相比 Postgres 的 0.3 FPS)。但由于 DuckDB 可见的游戏状态每秒只更新一次,所以十分之九的帧只是渲染了相同的视图! 这种系统拆分对于原始分析性能来说很棒,但如果你需要紧密的反馈循环,它几乎毫无用处。 ### 套娃方法 拥有第二个系统和 ETL 管道很糟糕:除了我们刚刚遇到的复制延迟之外,你还必须维护多个系统以及它们之间的管道。不过,还有另一种方法:如果每个人都真的喜欢使用 Postgres,但 Postgres 在处理分析型工作负载时速度不够快,为什么不直接将一个快速的分析引擎与 Postgres 放在一起呢? 其中一种方法是 pg_clickhouse (https://github.com/ClickHouse/pg_clickhouse),我们在本博客的上一篇帖子 (https://cedardb.com/blog/unnest_dbs/) 中已经讨论过。它从 Postgres 内部提供对 ClickHouse 数据库引擎的访问,并可以将表扫描推送到能力更强的 ClickHouse 分析引擎。这是 pg_clickhouse 上的 DOOMQL: Your browser does not support the video tag.如您所见,它显示的性能与 Postgres 大致相同。用现代引擎改进表扫描性能很好,但最终瓶颈仍然是 Postgres 的查询优化器和执行引擎。对于 DOOMQL 尤其如此,因为表相当小(因此不需要快速表扫描),但查询本身非常复杂。 ## HTAP 是圣杯吗? 到目前为止,我们看到:Postgres 处理事务,但无法推送帧。带有 ETL 管道的 DuckDB 推送帧,但渲染的是陈旧状态。将快速的分析引擎硬塞到 Postgres 上也无济于事,因为瓶颈是查询执行器(及其执行模型),而不是单纯的表扫描。 那么,如果你的数据库*同时擅长这两者*呢?这就是 HTAP(混合事务/分析处理)的前提。一个以这种方式构建的数据库,既能以低延迟处理写入,又能同时对相同数据运行复杂的分析查询,而无需 ETL 管道。因此没有复制延迟、陈旧读取,尤其是不需要维护第二个系统和数据管道。 但是,如果这如此令人向往,为什么不是所有系统都这样呢?在数据库发展的大部分历史中,硬件迫使你做出“二选一”的决定。OLTP 系统是围绕旋转磁盘灾难性的随机 I/O 设计的。为了确保新插入的记录尽可能少地触及磁盘上的不同位置,OLTP 系统通常是行导向的,并且新行只是追加写入。 OLAP 系统显然必须处理相同的磁盘限制,但希望以尽可能少的读取次数扫描大量数据。由于它们通常受限于 HDD 可怜的吞吐量,它们试图尽可能少地读取数据,广泛使用压缩方案并将其数据布局结构化为列。一个查询通常不会触及一条记录的所有字段(如果我只想找出玩家在地图上的位置,我对他们的密码不感兴趣),这极大地减少了需要扫描的数据量。不幸的是,这对于 OLTP 来说很糟糕:添加新行意味着我必须更新其所有列,而这些列分散在整个磁盘上。 如今,有整个公司的存在就是为了在 OLTP 和 OLAP 系统之间移动数据。但是这些系统的基础假设已经不再成立:一台服务器可以有几十个核心和数百 GiB 的 RAM,这通常足以将你的整个热数据集保存在主内存中。现代 NVMe SSD 可以处理数十万次随机 IOPS。因此,迫使专业化的硬件限制基本上已经消失,但大多数数据库架构还没有跟上。它们仍然围绕着 90 年代和 00 年代的权衡进行组织。CedarDB 是为新现实从头构建的:存储层、查询优化器和执行引擎都设计为原生处理两种工作负载。CedarDB 没有将分析引擎硬塞到事务引擎上或反之亦然,而是遵循一种统一的架构,该架构假设快速存储、充足的 DRAM 和许多核心。 但理论说得够多了,让我们看看 CedarDB 的实际表现: Your browser does not support the video tag.差异立即可见。CedarDB 可以在每秒 30 次 tick 的情况下推送约 30 FPS,并且没有复制延迟:每一帧都显示当前系统状态。DOOMbench 记录的中位延迟为 44 毫秒,这意味着只需 44 毫秒就能让一个按键产生可观察的结果。对于《反恐精英》职业选手来说仍然不够,但已经足够实际玩游戏了! 这是一个刻意设计的工作负载吗?绝对是的!但底层模式(基于新鲜数据做出观察)无处不在。例如,仪表板、交互式分析,或者根据自身决策采取行动的 AI 代理。 ## DOOMbench 网页 关于视频就到此为止。请前往 cedardb.com/doombench (https://cedardb.com/doombench) 查看完整结果表格,或者继续阅读以获得总结。 DOOMbench 测量四项指标: - **Tickrate**:这是一个纯 OLTP 测量,不渲染任何帧。四名玩家移动和射击,同时服务器以尽可能快的速度处理游戏 tick。你的数据库能多快运行游戏循环? - **Static FPS**:这是一个纯 OLAP 测量,没有任何移动或 tick。四名玩家尽可能快地查询他们渲染的视图。这是原始的分析查询吞吐量。我们汇总并报告所有四个客户端的 FPS。 - **Median Lag**:每个电竞玩家都关心的指标。从按下按钮到渲染视图反映该输入所用的时间。这在单个数字中捕获了 OLTP 性能、OLAP 性能*以及*复制延迟。 - **DOOMscore**:HTAP 基准测试。四名玩家在游戏循环以 35 Hz(原始 DOOM tick 率) tick 的情况下实际玩游戏。数据库在跟上游戏循环的同时,每秒能渲染多少总帧数?无法维持每秒 35 次 tick 的系统会受到按比例的惩罚:如果你只能达到一半的 tick 率,那么你的 DOOMscore 也会减半。 每个系统都在相同的硬件上运行相同的 DOOMQL 代码库。由于某些系统(CockroachDB、DuckDB)在语法上有轻微差异,DOOMbench 允许你声明特定于数据库的 SQL 覆盖。除了上述四个数字外,DOOMbench 还为每个数据库录制了相同场景的视频回放,你可以观看。 DOOMbench 是开源的。如果你想添加其他系统,请随时提交 PR!DOOMbench 目前仅适用于兼容 Postgres 的系统,但我们希望将来也添加其他系统。 ## 我应该关心吗? ### 关于基准测试? 可能不需要。每个供应商都推动他们自己 (https://rtabench.com/) 的基准测试,在其中他们表现得最优秀 (https://questdb.com/dashboards/fx-orderbook/),这完全不会让任何人感到惊讶 (https://exasol.github.io/benchkit/public/performance/#tab=TPC-H)。这个基准测试也不例外:它使用了非常晦涩和奇特的 SQL 特性,比如递归和非常复杂的字符串操作。但它生成的视频能让你的数据栈中的权衡一目了然。这总该有点价值吧,不是吗? ### 关于 HTAP? 取决于你的工作负载。许多工作负载对旧数据可以接受。如果你反正是在喝完一杯咖啡后才阅读报告,你大概不会关心它是否已经过时了五分钟。如果你想在没有人工参与的情况下做出决策,或者将你的数据库用于交互式工作负载(你、你的客户或你的 AI 代理更改某些参数并期望立即得到结果),HTAP 将是一个颠覆性的改变!或者如果你想玩 DOOM,我想也是…… ## 接下来是什么? 我们正在将 DOOMbench 开源。缺少某个系统?对我们的方法论不满意?请发起拉取请求!我也正在研究用递归 SQL 实现 BSP 树,这样我们很快就能在 SQL 内部拥有一个真正的 DOOM。 如果你想自己运行 DOOMbench,可以在这里 (https://github.com/cedardb/doombench) 查看代码。所有数据库系统都已 Docker 化,开箱即用。想在你自己的栈中试用 CedarDB?从这里开始 (https://cedardb.com/get-started) 或联系我们 (https://calendly.com/d/ct73-6mf-7vw/30-minutes-with-cedardb) 继续阅读 ## 在 CedarDB 博客上阅读更多内容 查看全部 (https://cedardb.com/blog/)

相似文章

DuckDB: it's not quack science

Lobsters Hottest

DuckDB是一个开源嵌入式分析型数据库,支持直接查询文件、嵌入应用,并提供友好的SQL扩展,在数据分析场景下比传统Unix管道更高效。

为什么fastDoom这么快

Fabien Sanglard

关于fastDOOM移植版相比原始Doom可执行文件实现显著性能提升的详细技术分析,涵盖了Doom源代码传承历史及具体优化技巧。