随着 GPU 硬件能力的快速提升和软件生态的成熟,GPU 正在成为数据分析领域的新计算范式。Sirius 作为一款开源的 GPU 原生 SQL 引擎,通过创新的架构设计实现了对现有数据库系统的无缝加速。本文将从存储引擎架构、查询优化策略、高并发性能表现和扩展性设计四个维度,深入分析 Sirius 的技术实现与工程价值。
GPU 时代的数据分析新范式
传统 CPU 数据库在应对大规模数据分析时面临计算吞吐量和内存带宽的双重瓶颈。现代 GPU 在核心数量和内存带宽上已显著超越 CPU,例如最新的 NVIDIA Blackwell GPU 拥有 288GB 设备内存和超过 3TB/s 的读写带宽。然而,GPU 数据库的广泛应用一直受到内存容量限制、数据移动瓶颈、硬件成本高昂和工程复杂度四大挑战的制约。
Sirius 的设计哲学基于两个核心原则:GPU 原生执行和无缝集成加速。与在传统 CPU 引擎上添加 GPU 加速的混合系统不同,Sirius 将 GPU 作为主要执行设备,整个查询计划从扫描到结果都在 GPU 上运行。这种设计减少了 CPU-GPU 协同执行的复杂性,同时通过 Substrait 标准查询格式实现了与现有数据库系统的无缝集成。
存储引擎架构:缓冲区管理的创新设计
Sirius 的存储引擎架构围绕 GPU 内存特性进行了深度优化,其核心是缓冲区管理器(Buffer Manager)。该管理器将内存划分为两个独立区域:
数据缓存区
数据缓存区用于存储缓存数据,可位于设备内存或固定主机内存中。为了最小化动态内存分配的开销,缓存区在查询执行前预先分配。当前版本中,Sirius 依赖主机数据库(如 DuckDB)从磁盘读取数据,读取后自动缓存到预分配的缓存区域供后续重用。
数据处理区
数据处理区位于设备内存中,存储查询执行期间的中间结果,如哈希表、中间结果等。Sirius 使用RMM(RAPIDS Memory Manager)池分配器高效管理这一区域。RMM 提供了高性能的 GPU 内存分配机制,特别适合频繁分配和释放内存的查询执行场景。
缓冲区管理器还负责不同列式格式之间的转换:Sirius 内部列式格式、libcudf 列式格式以及主机数据库使用的列式格式。Sirius 和 libcudf 都基于 Apache Arrow 派生其列式格式,这允许通过指针传递实现零拷贝转换。唯一的例外是行索引转换,因为 Sirius 使用 uint64_t 而 libcudf 使用 int32_t。
查询优化策略:GPU 原生执行模型
Sirius 的查询执行引擎采用了创新的流水线执行模型和基于推送的执行模型,这两个设计选择共同构成了其高效的 GPU 原生执行基础。
流水线执行模型
查询计划被划分为多个流水线,每个任务(以流水线为粒度)被排入全局任务队列。空闲的 CPU 线程从队列中拉取任务,通过调用每个操作符来执行流水线。这种模型在现代数据系统中被广泛采用,如 DuckDB、Hyper 和 Velox。
基于推送的执行模型
在每个流水线内部,Sirius 采用基于推送的执行模型。查询执行器充当协调器,维护查询执行状态(如操作符的输入和输出)。执行器将数据推送到操作符中,而不是让操作符从其前驱拉取数据(如 Velox 系统所做)。这种设计使操作符保持无状态,简化了实现。
大多数物理操作符使用 libcudf 库实现,少数特殊功能如谓词下推和物化使用自定义 CUDA 内核。得益于模块化设计,开发者可以轻松在 libcudf 和自定义 CUDA 内核之间切换操作符实现。
高并发场景下的性能表现
Sirius 的性能评估基于 TPC-H 和 ClickBench 基准测试,结果显示在相同硬件租赁成本下,Sirius 相比 DuckDB 实现了 8.3 倍的加速,相比 ClickHouse 实现了 38 倍的加速。
单节点性能分析
在单节点设置中,Sirius 作为 DuckDB 的加速器运行 TPC-H 查询(scale factor 100)。性能分解显示,连接操作在大多数情况下主导查询执行时间,特别是在连接密集型查询(Q2-Q5、Q7-Q8、Q20-Q22)中。
分组操作在多个查询中占相当大比例,特别是在涉及字符串键分组(Q10、Q18)或组数较少(Q1)的查询中。对于字符串键,libcudf 默认使用基于排序的分组策略,这比基于哈希的分组性能较差。对于组数较少的分组操作,GPU 会遭受内存争用。
过滤操作在过滤密集型查询如 Q6 和 Q19 中占主导地位,在 Q13 中也占显著比例,该查询使用具有极低选择性的复杂字符串匹配表达式。
分布式性能表现
在分布式设置中(4×NVIDIA A100 集群),Sirius 相比 Apache Doris 在 Q1、Q3 和 Q6 查询上分别实现了 12.5 倍、2.5 倍和 2.4 倍的加速。性能分解显示,在当前的分布式 Sirius 实现中,GPU 执行不是主要的性能瓶颈,表明有充足的优化机会。
例如,在 Q1 和 Q6 中,查询执行时间的很大一部分花费在 Doris 的查询优化器和协调器上,这些组件在 CPU 上运行。这种开销不随数据大小扩展,对于更大的数据集预计会变得不那么显著。在 Q3 中,数据交换是主要瓶颈,因为 Doris 的分布式查询计划对 orders 和 lineitem 表都进行了洗牌。
扩展性设计与技术挑战
交换服务层
Sirius 的交换服务层协调多个节点间的分布式查询执行。在单节点部署中,这一层可以完全绕过。但在多节点设置中,它在协调节点间数据交换方面扮演关键角色。
在 Sirius 中,交换被建模为专用的物理操作符。Sirius 支持常见的交换模式 —— 广播、洗牌、合并和多播 —— 所有这些都使用 NCCL 原语实现。
在分布式执行中,查询计划被划分为多个片段,每个片段在参与节点上本地执行。数据交换发生在片段之间 —— 一个片段完成后,其输出在计算节点间传输,并被后续片段作为输入消耗。Sirius 内部维护一个运行时注册表,将交换的中间数据作为临时表。这些临时表在相应片段完成执行后自动注销。
当前限制与未来扩展
尽管 Sirius 在性能上表现出色,但仍面临一些技术挑战:
-
超出内存执行支持:当前原型主要针对内存设置,需要扩展缓冲区管理器以支持溢出到固定内存和磁盘,增强执行引擎以支持批处理执行。
-
分布式 SQL 覆盖范围:分布式模式相比单节点模式 SQL 覆盖范围有限,例如不支持 avg 等函数。未来计划扩展分布式执行的 SQL 覆盖范围。
-
直接磁盘访问:目前依赖主机数据库从磁盘读取数据,未来计划通过 GPUDirect 技术优化从磁盘和网络读取数据的 I/O 路径。
-
多 GPU 支持:计划扩展 Sirius 以支持每个节点多个 GPU,使其能够处理更大的工作负载。
工程实践建议
对于考虑采用 Sirius 的工程团队,以下实践建议值得关注:
内存配置策略
- 为数据缓存区分配 50% 的 GPU 内存,为数据处理区分配另外 50%
- 使用 RMM 池分配器管理数据处理区,减少内存分配开销
- 考虑使用固定主机内存作为缓存扩展,特别是当数据集超过 GPU 内存容量时
查询优化要点
- 关注连接密集型查询的性能优化,这是 GPU 执行的主要瓶颈
- 对于字符串键分组操作,考虑自定义实现以替代 libcudf 的默认排序策略
- 在分布式设置中,优化数据交换模式,减少洗牌数据量
监控与调优
- 监控 GPU 内存使用情况,特别是数据处理区的分配模式
- 跟踪查询执行时间分解,识别性能瓶颈操作符
- 在分布式环境中,监控网络带宽使用和数据交换延迟
结论
Sirius 代表了 GPU 原生数据库系统的一个重要里程碑。通过创新的存储架构设计、高效的查询执行模型和灵活的扩展性机制,Sirius 在保持与现有数据库系统兼容性的同时,实现了显著的性能提升。随着 GPU 硬件能力的持续提升和软件生态的进一步完善,GPU 原生数据库有望成为数据分析领域的主流选择。
Sirius 的开源许可(Apache-2.0)和模块化设计为数据库社区提供了宝贵的参考实现和扩展基础。未来的发展方向包括超出内存执行支持、完整的分布式功能覆盖、多 GPU 支持和更广泛的 SQL 操作符支持。对于面临大规模数据分析挑战的组织,Sirius 提供了一个有前景的技术路径,值得深入研究和实践探索。
资料来源:
- Sirius 官方论文:Rethinking Analytical Processing in the GPU Era (arXiv:2508.04701)
- Sirius 官方网站:https://sirius-db.com/
- 相关性能评估基于 TPC-H 和 ClickBench 基准测试数据