在 2025 收官前,看清 Data + AI 的真实走向,点击查看 BUILD 大会精华版 了解详情
写点什么

我们为什么要选择小众语言 Rust 来实现 TiKV?

  • 2017-09-21
  • 本文字数:2753 字

    阅读完需:约 9 分钟

本文是 InfoQ 策划的语言专题其中的 Rust 篇。其他更多内容将在月底结集推出,敬请期待。Rust 是什么?

Rust 是由 Mozilla 研究室主导开发的一门现代系统编程语言,自 2015 年 5 月发布 1.0 之后,一直以每 6 周一个小版本的开发进度稳定向前推进。语言设计上跟 C++ 一样强调零开销抽象和 RAII。拥有极小的运行时和高效的 C 绑定,使其运行效率与 C/C++ 一个级别,非常适合对性能要求较高的系统编程领域。利用强大的类型系统和独特的生命周期管理实现了编译期内存管理,保证内存安全和线程安全的同时使编译后的程序运行速度极快,Rust 还提供函数式编程语言的模式匹配和类型推导,让程序写起来更简洁优雅。宏和基于 trait 的泛型机制让 Rust 的拥有非常强大的抽象能力,在实际工程中尤其是库的编写过程中可以少写很多 boilerplate 代码。

Rust 的生态

Rust 由于有 Cargo 这样一个非常出色的包管理工具,周边的第三方库发展非常迅速,各个领域都有比较成熟的库,比如 HTTP 库有 Hyper,异步 IO 库有 Tokio, mio 等,基本上构建后端应用必须的库 Rust 都已经比较齐备。 总体来说,现阶段 Rust 定位的方向还是高性能服务器端程序开发,另外类型系统和语法层面上的创新也使得其可以作为开发 DSL 的利器。

Rust 的使用情况

Rust 作为一种新锐的语言,具备其独有的优越性,目前在全球落地的项目中比较知名的比如,Dropbox 的后端分布式存储系统(闭源),Firefox 的新的内核 Servo,操作系统 Redox,当让包括 PingCAP 的分布式数据库 TiDB 的存储层 TiKV,TiKV 作为其中的一员,自上线以来非常引人注目,在 GitHub Rust 语言的全球排名项目中,基本上一直徘徊在前几名的状态。

TiKV 是一个事务型分布式 Key-Value 数据库,是作为 TiDB 项目的核心存储组件,也是 Google 著名的分布式数据库 Spanner 的开源实现。对于这样一个大型的分布式存储项目,在 TiKV 的开发语言选择上,我们选择了 Rust 语言从零构建。在今天这个文章里,我想详细聊聊什么驱动我们选择了 Rust。

对于数据库这类基础软件来说,在过去很长的一段时间,我们能选择的编程语言基本只有 C/C++。Java 和 Go 这类编程语言的主要问题还是由于 GC 引起抖动,尤其在读写压力比较大的情况下。另外一方面,对于 Go 来说,一个非常吸引人的特性是轻量级线程 Goroutine,对于开发者来说极大的降低的开发并发程序的复杂度,但是相应的代价是 Goroutine 的 Runtime 会带来额外的上下文切换开销。 对于数据库这样的基础软件,性能显然是很重要的,另一方面,系统需要尽可能的保持 ”确定性”,在性能优化和调试阶段能够更加方便,但是引入 GC 和另一个 Runtime 的问题是会增加这种不确定性,所以在很长的时间内,C/C++ 是唯一的选择。

TiKV 这个项目起始于 2015 年底,当时也是在 Pure Go / Go + Cgo / C++11 / Rust 几个语言之间纠结,虽然我们的核心团队有大量的 Go 语言开发经验,另外 TiDB 的 SQL 层是完全采用 Go 语言开发,Go 带来的开发效率的极大提升也让我们受益良多,但是在存储层的选型上,我们首先排除的就是 Pure Go 的选项,理由也很简单,在底层,我们已经决定接入 RocksDB,RocksDB 本身就是个 C++ 的项目,而 Go 的 LSM-Tree 的实现大多成熟度不太够没有能和 RocksDB 相提并论的项目,如果选 Go 的话,只能选择用 Cgo 来 bridge, 但是当时 Cgo 的问题同样明显,在 2015 年底,在 Go code 里调用 Cgo 的性能损失比较大,并不是在 Goroutine 所在的线程直接 Call cgo 的代码,而且对于数据库来说,调用底层的存储引擎库是很频繁的,如果每次调用 RocksDB 的函数都需要这些额外的开销的话,非常不划算,当然也可以通过一些技巧增大 Cgo 这边的调用的吞吐,比如一段时间内的调用打包成一个 cgo batch call,通过增加单个请求的延迟来增大的整体的吞吐,抹平 cgo 调用本身的开销,但是这样一来,实现就会变得非常复杂,另一方面,GC 的问题仍然没有办法彻底的解决, 在存储层我们希望尽可能高效的利用内存,大量使用 syscall.Mmap 或者对象复用这些有些 hacky 的技巧,会让整体的代码可读性降低,我的判断仍然是得不偿失。

所以后来认真在考虑的只剩下 Rust / C++11,先说 C++11 的问题,其实 C++11 也没啥问题,性能上肯定没问题,RocksDB 是 C++11 写的,在纠结了一小段时间后,我们认真评估了一下我们的团队背景和要做的东西,最后还是没有选择 C++,原因主要是:

  1. 我们核心团队过去都是 C++ 的重度开发者,也基本都有维护过大型 C++ 项目的经历,每个人都有点心里阴影… 悬挂指针、内存泄漏、Data race 在项目越来越大的过程中几乎很难避免,当然你可以说靠老司机带路,严格 Code Review 和编码规范可以将问题发生的概率降低,但是一旦出现问题,Debug 的成本很高,心智负担很重,而且第三方库不满足规范怎么办。
  2. C++ 的编程范式太多,而且差异很大,又有很多奇技淫巧,统一风格同样也需要额外的学习成本,特别是团队的成员在不断的增加,不一定所有人都是 C++ 老司机,特别是大家这么多年了都已经习惯了 GC 的帮助,已经很难回到手动管理内存的时代。
  3. 缺乏包管理,集成构建等现代化的周边工具,虽然这点看上去没那么重要,但是对于一个大型项目这些自动化工具是极其重要的,直接关系到大家的开发效率和项目的迭代的速度。而且 C++ 的第三方库参差不齐,很多轮子得自己造。

Rust 在 2015 年底已经发布了 1.0,Rust 有几点特性非常吸引我们:

  1. 内存安全性
  2. 高性能 (得益于 llvm 的优秀能力,运行时实际上和 C++ 几乎没区别),与 C/C++ 的包的亲缘性
  3. 强大的包管理和构建工具 Cargo
  4. 更现代的语法
  5. 和 C++ 几乎一致的调试调优体验,之前熟悉的工具比如 perf 之类的都可以直接复用
  6. FFI,可以无损失的链接和调用 RocksDB 的 C API

其中放在第一位的是安全性,之前在 C++ 中提到的内存管理和避免 Data race 的问题,我相信虽然靠老司机是可以解决,但是仍然没有在编译器层面上强约束,把问题扼杀在摇篮之中解决的彻底,Rust 这点非常符合我的口味, 对于大型项目来说,永远不要把软件的质量押宝在人身上,人永远会犯错,人是不稳定的。Rust 的做法虽然增加了上手的门槛,但是我认为是值得的。另一方面,Rust 又是一个非常现代化的编程语言,现代的类型系统,模式匹配,功能强大的宏,trait 等在熟悉以后会很大的提升开发效率,其实如果选择 C++ 的话,算上 Debug 的时间,Rust 的开发效率不算低,在我们的实践经验中,我们的工程师从零开始接触 Rust,到能够高效进行开发的时间大概是 1 个月,而且熟练的工程师的 Rust 开发效率几乎是和写 Go 差不多的。

小结

总体来说,Rust 这门新兴的语言对于国内大多数开发者来说会显得比较陌生,但是并不妨碍 Rust 已经在世界范围内作为公认的 C/C++ 的有希望的挑战者。我认为,从长远来看,在对内存安全性和性能有严苛要求的场景,Rust 将会有广阔空间。

2017-09-21 19:0010342
用户头像

发布了 22 篇内容, 共 17.0 次阅读, 收获喜欢 92 次。

关注

评论

发布
暂无评论
发现更多内容

从小样本学习出发,奔向星辰大海

百度大脑

Linux修改drop_caches内核参数来清理缓存的一些笔记

山河已无恙

Linux 2月月更

元宇宙里办年会,听演讲、看产品、抽大奖一件不落

Meta 小元

数字孪生 元宇宙

浅谈OKR(12/100)

hackstoic

OKR

总结 XSS 与 CSRF 两种跨站攻击

喀拉峻

网络安全

netty系列之:Bootstrap,ServerBootstrap和netty中的实现

程序那些事

Java Netty 程序那些事 2月月更

springcloud五大核心组件

编程江湖

虚拟空间引领 数字化转型拉开银行差距

CECBC

PingCode Wiki 权限设计之ACL

PingCode研发中心

项目管理 开发 acl PingCode 页面权限

【安全漏洞】浅谈Bypass Waf (基础-实战)

H

网络安全 渗透测试 漏洞

Web Components系列(四) —— 认识 Shadow DOM

编程三昧

前端 组件化 HTML5, CSS3 2月月更

征文投稿丨使用云服务器ECS快速搭建halo博客

阿里云弹性计算

征文投稿 玩转ECS halo博客

阿里云服务器搭建halo博客从0到1

乌龟哥哥

阿里云 2月月更 halo博客

亚信科技AISWare AntDB数据库在运营商核心业务系统的联合实践分享

亚信AntDB数据库

5G AntDB intel 亚信科技

声网AI降噪测评系统初探

RTE开发者社区

音视频 RTE 技术详解

redis 面试总结

yuexin_tech

redis 面试

一文让你彻底搞懂Python中__str__和__repr__

宇宙之一粟

Python 2月月更

2 月亚马逊云科技培训与认证课程,精彩不容错过!

亚马逊云科技 (Amazon Web Services)

架构师 培训 认证

我与Android的故事|社区征文

Changing Lin

android 移动开发 新春征文

欧拉的奇异之旅·风暴来临与欧拉初诞

白洞计划

2022-02微软漏洞通告

火绒安全

微软 网络安全 终端安全 漏洞修复

2022年1月云主机性能评测报告,移动云升至第三

博睿数据

5种阿里常用代码检测推荐 | 阿里巴巴DevOps实践指南

阿里云云效

阿里云 云原生 软件开发 研发 DevOps实践指南

Java自定义DNS解析器负载均衡实现

FunTester

负载均衡 性能测试 接口测试 DNS FunTester

[JAVA冷知识]什么是逆变(contravariant)与协变(covariant)?数组支持协变&逆变吗?泛型呢?

山河已无恙

Java 2月月更

Flutter 重构 QTalk

Qunar技术沙龙

元宇宙的本质特征是五大融合

CECBC

2022年的元宇宙,你该知晓些什么?

CECBC

基于RestTemplate的在线武器库

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

我们为什么要选择小众语言Rust来实现TiKV?_语言 & 开发_黄东旭_InfoQ精选文章