本文字数:2544;估计阅读时间:7 分钟
审校:庄晓东(魏庄)
本文在公众号【ClickHouseInc】首发
Meetup活动
ClickHouse 上海首届 Meetup 讲师招募中,欢迎讲师在文末扫码报名!
介绍
目前,ClickHouse DBMS 的代码库包含多种编程语言,但其主要语言是 C++。因此,集成其他编译语言的库的可能性非常有限。Rust 是其中一种语言。它的性能与 C 和 C++ 相似,并且 Rust 丰富的类型系统和所有权模型可以保证内存安全和线程安全。由于有许多有用的库是用 Rust 编写的,所以我们考虑在 ClickHouse 中使用这些库。
将 Rust 集成到 ClickHouse
构建 Rust
Rust 有一个名为 Cargo 的包管理器,用于下载依赖项、编译和分发包。另一方面,ClickHouse 使用 CMake 和 Ninja 构建系统。这两种构建方法默认情况下不兼容,因此我们需要实现某种集成 Rust 构建系统的方法。我们首先尝试实现了一个自定义的 CMake 函数,该函数可以启动 Cargo 并检测其输出。虽然这种方法成功地让我们能够将 Rust 库作为依赖项构建到 ClickHouse 中,但每次引入新的 Rust 库时,都需要更改和重新实现部分函数。后来,我们找到了一个名为 Corrosion-rs 的工具,它专为将 Rust 库集成到 CMake 项目中设计。通过它,我们可以更轻松地集成 Rust 项目,仅需一个简单的三行 CMake 文件。
BLAKE3
我们选择 BLAKE3 作为示例 Rust 库进行集成。BLAKE3 是一种高性能的安全加密哈希函数。
我们将其添加为子模块并连接到 ClickHouse 构建系统,但仍然无法在 C++ 代码中直接使用其方法。为了解决 Rust 数据类型与 C++ 数据类型之间的兼容性问题,我们在 Rust 中编写了一个中间函数。该函数接收 C 数据类型的变量作为输入,在将数据转换为相应的 Rust 类型后调用 BLAKE3 哈希函数,然后以 C 格式返回哈希结果。我们之所以使用 C 是因为 Rust 外部函数接口仅提供与 C 兼容的类型。
由于其输入和返回类型都为 C 类型,我们创建了一个 .h 头文件,声明了该函数,从而使我们最终能够在 ClickHouse 代码中使用它。
关于性能
我们在三种不同的输入上测量了 BLAKE3 的性能。以下是比较 BLAKE3 与 ClickHouse 中类似哈希函数的图表:
如图所示,BLAKE3 的性能比 SHA224 或 SHA256 提升超过两倍,并且比 MD5 更快。此外,BLAKE3 是安全的,不像 MD5 和 SHA-1,并且能够防止长度扩展攻击,不像 SHA-2。
这些结果符合我们的预期,并且与 BLAKE3 作者对 1KB 输入长度的测试结果一致:
中间函数的方法如何?我们在调用 BLAKE3 之前和之后使用中间函数转换 Rust 和 C 数据类型,这些转换需要一些时间。为了衡量类型转换带来的开销,我们使用了 perf top 工具,并将其数据呈现为火焰图:
由图可见,中间函数最消耗时间的部分是将 Rust 哈希数据转换为 C 格式,这大约占整个查询时间的 1.15%。此外,在开始时将 C 输入的 char 指针转换为 Rust 字节数组类型几乎不需要时间,因为指针到字符串的转换是零成本的,而转换为字节数组在 Rust 中具有恒定成本。
遇到的问题
在 BLAKE3 集成过程中,我们遇到了一些问题。第一个问题是 C++ 内存检测器无法理解 Rust 中的内存操作,并将其标记为误报。我们通过在输入数据上使用 _msanunpoison 内存检测器函数,并添加一个更明确的字节数组转换版本的中间方法解决了这个问题。所有修复完成后,误报消失,内存检测器正常工作。
另一个问题是多平台构建和链接。虽然大多数 ClickHouse 支持的平台都可以通过 Cargo 轻松配置,但有些需要通过 CMake 或特定的包/框架进行额外配置。目前,只有一个平台 (aarch64-darwin) 由于链接问题仍不支持。
结论
我们实现了将 Rust 语言库集成到 ClickHouse 的可能性,并将 BLAKE3 哈希函数作为示例库添加。这使我们能够:
1. 将来在 ClickHouse 中添加和使用其他 Rust 库。
2. 在 ClickHouse 中与其他哈希函数一起使用 BLAKE3,并利用其速度和安全特性。
Alexey Milovidov 的评论
我们希望在构建中添加对 Rust 的支持,作为一种实验。Rust 有一个活跃的社区,并且有许多优秀的高质量库,我们可以在 ClickHouse 中使用。同时,我们希望尽可能不引人注目地进行集成。我们使用“你不使用就不付费”的原则:Rust 集成不应妨碍您的使用,并且不要强调它有多好。
我们对集成提出的要求如下:
-
它应该是可选的 - 代码不应要求构建时需要 Rust:
如果未安装 cargo,则应在没有 Rust 库的情况下进行简单构建;
-
静态链接(没有新的动态库);
它不应引入来自 glibc 的新符号版本依赖;
二进制文件应在古老的 Linux 系统上运行;
二进制文件应是单片的;
-
支持与 C++ 代码的交叉编译,因为我们总是使用交叉编译我们的代码(即使目标平台与主机平台相同,我们也使用带有自定义 sysroot 的密封构建);
-
支持使用检测器和模糊测试的构建:
它们主要用于 C++ 代码,但二进制文件应能与 Rust 代码链接并与检测器一起正常工作。
满足这些要求比我们想象的要难得多,但结果比我预期的要好。没有人抱怨 Rust - 当它未安装时,项目照常构建;当它已安装时,构建就能正常工作。
我们选择了一个小型库作为概念验证。如果实验顺利进行,我们可以将其使用扩展到更多的库。同时,我们的期望值不高 - 如果没有足够的热情,我们可以简单地放弃它。
我对 Denis Bolonin 的工作印象深刻,他使这一切成为可能!
Meetup 活动讲师招募
我们正为上海活动招募讲师,如果你有独特的技术见解、实践经验或 ClickHouse 使用故事,非常欢迎你加入我们,成为这次活动的讲师,与大家分享你的经验。
点击此处或扫描下方二维码,立刻报名成为讲师!
征稿启示
面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com
联系我们
手机号:13910395701
邮箱:Tracy.Wang@clickhouse.com
满足您所有的在线分析列式数据库管理需求