Rust一直以难度大、学习成本高著称,最明显的可能就是所有权以及生命周期的问题。
然而,如果大家真正使用过一段时间的Rust后,会发Rust其实非常好用,尤其是对于业务代码,Rust的无Null设计以及Result模式,能够在开发阶段避免不少问题,并且使得代码更清晰可读。而在大部分场景下,都不会涉及到生命周期问题,编译器能够隐式的推断出生命周期。而所有权系统使得我们不得不思考代码是否合理,如果因为所有权问题导致编译不过,那可能是设计问题,想一想是否需要重构当前代码。
今天以一个知识库的后端开发为例,来看一下Rust到底是否适合后端业务开发。
背景
今年上半年使用Rust写了一个知识库,主要功能是导入一些文档,经过编码后保存到本地向量库,并接入AI模型和MCP,实现智能问答的效果,也就是所谓的RAG。
目前暂未开源,详情可了解:https://fskb.coderbox.cn
这个项目除UI部分外,完全使用Rust开发,以下是Rust的代码行数统计(不含依赖库)。
| Language | Files | Lines | Code | Comments | Blanks |
|---|---|---|---|---|---|
| Rust | 194 | 20695 | 17672 | 1044 | 1979 |
| - Markdown | 119 | 1701 | 39 | 1582 | |
| (Total) | 22396 | 17711 | 2626 | 2059 | |
| Total | 194 | 20695 | 17672 | 1044 | 1979 |
从开始开发到初版完成,耗时1个月左右,而在此过程中,实际上遇到的比较麻烦的问题不是Rust语言本身的问题,而是如何在本地提取各种文档里的内容的问题。
为什么选择Rust
作为一个需要支持多种系统部署的本地化应用,跨平台是必须的,而知识库获取内容的主要来源是通过解析文件并提起其中的内容,而这部分内容很可能需要调用第三方库实现,并且要保证解析性能。综合下来,Rust是适合的。
另外,我们希望这是一个本地化应用,需要能够快速部署在用户的电脑或者服务器上,并能够稳定运行,这也与Rust的特性相符,能够做到跨平台编译,并且编译后的可执行文件的体积较小(除过资源文件,大约40M左右)。
框架选型
虽然Rust生态确实不如Java生态丰富,但是基本上常见的功能在Rust中都有对应的实现。
以下大致列出了Java中的常用库在Rust中对应的替代选项。
| Java库 | Rust替代品 |
|---|---|
| Spring Web | Actix Web, Rocket, Axum |
| MyBatis(Plus) | Diesel, Sea ORM, RBatis |
| Apache Commons | itertools, regex, chrono |
| Log4j | log, env_logger, tracing |
| Jackson、Fastjson | serde, serde_json |
| HttpClient | reqwest |
| Redis | redis-rs |
| Kafka、RabbitMQ | rdkafka, lapin、JetStream |
| Reactor | tokio |
Rust中暂时还没有类似Spring Boot这样的集成框架,也没有像Spring Cloud这样的微服务框架。但这并不是说Rust开发的应用不能使用微服务模式,因为微服务本身核心是服务发现,而不少老牌的服务注册中心也都提供了Rust版的客户端,用于服务的注册和发现,使用起来也和其他语言类似。
我们也开源了一个服务配置和注册中心的应用,参考了Nacos的设计,开源地址为:https://github.com/xgpxg/conreg
在知识库项目中,我们最终选用的主要框架有以下几个:
• 基础Web框架: Rocket
• ORM框架:RBatis
• 缓存:Redis和Sled+Moka。Redis在集群模式下使用,Sled+Moka在单机模式下使用
• 数据库:Sqlite和MySQL
• 序列化/反序列化:serde、serde_json
这些都是在业务开发中非常常用的库,使用起来都非常容易上手。
其中,增删改查主要会用到RBatis,这是一个和MyBatis类似的库,提供了基本的ORM功能。它也支持动态SQL和分页查询,支持自定义SQL。
Rust写业务代码效率如何
后端开发,一般以业务为主,会涉及不少复杂的数据结构以及调用关系,如果没有亲自使用Rust写过业务代码的同学,可能都会觉得Rust的限制太多,一写一个错。但实际上并不会存在这些问题,相反,大部分时候是写的很顺畅的,包括生命周期和所有权机制,使用多了后,你会发现它就是合理的,这些规则就是能避免大部分内存问题,并且你也会思考,一个变量应该什么时候不需要再使用,避免过长时间占用内存,不知不觉的就会写出高性能代码。而在以往的Java项目中,一个对象,可能会经过十几个甚至几十个方法,很难知道哪个方法会修改这个对象,而Rust的可变性与不可变性规则就能简化这类问题,通过参数定义是否为mut的,就知道是否会修改里边的值(内部可变性除外)。
Java中的Spring Web提供了Web开发的基本框架,通过一个注解就能开启一个HTTP端点,例如:
java
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "World";
}
}
而Rust中的Web框架则使用宏实现类似注解的功能。
以Rocket为例:
rust
#[get("/hello")]
pub fn hello() -> String {
"World".to_string()
}
它们非常相似,并且Rust的代码看起来更简洁一点点。
其实在很多场景下,Rust的代码和Java有相似之处,这也是因为Rust是融合了其他语言的一些优势,逐渐发展起来的,虽然它本身不算是一个面向对象的编程语言,但是具有面向对象的部分特性。
至于令人头疼的生命周期,在项目的1.7万行代码中,也仅需要手动标记了38处,其它都无需显示标注。
使用Rust写业务代码时,只要稍微细心一点,能够编译通过,运行起来,基本上不会有太大问题,减少了不少调试时间。
在这个知识库项目之后,我们又做了一些其他的Rust实现的项目,例如:使用Tauri实现的个人知识库客户端、服务配置和注册中心、AI网关以及其他的一些小工具,累计代码量也达到了10万行。就开发效率而言,其实是和Java是差不多的。而编译后程序本身大小以及占用内存比Java程序小很多,实测知识库应用在未加载本地模型情况下,占用内存稳定在70M左右。
Rust用于实现高性能的后端服务
我们以一个空接口为例,分别测试了Java(17)和Rust的QPS。Web框架分别为Spring Web和Rocket,均使用默认配置,未做任何优化,测试环境相同。
Java测试代码:
java
@RestController
class TestController {
@GetMapping("/hello")
public String hello() {
return "World";
}
}
Rust测试代码
rust
#[get("/hello")]
fn hello() -> &'static str {
"World"
}
Java测试结果:

Rust测试结果:

Rust版的比Java版的快了3倍左右。
以上这个简单的测试虽然不能直接定义Rust比Java快,但是在我们网关项目中,在经过一些列处理(鉴权、安全验证、过滤器、接口调用等)后,未做优化的情况下,仍然能达到2w+的QPS,可见使用Rust作为后端服务,能够提升不少的性能。
这些性能的提升一方面得益于语言本身,因为Rust编译器在编译时做了一系列优化,使得能够以接近C语言的效率执行,另一方面也是因为框架的原因,Rocket当前默认使用Tokio异步执行,能够提升并发度,而Java中也可以使用WebFlux来异步运行,从而提升性能。
使用Rust重构以节约成本
之前提到了,Rust有很好的性能,而这些性能提升带来的直接价值就是能够节省机器资源,如果使用Rust实现后,能够提升3倍性能,那就可以减少2/3的服务器成本,当服务数量众多时,这也是一笔不小的费用。
当然,对现有系统使用Rust重构本身也是一个不小的成本,对于存量系统,可以对性能要求较高的部分使用Rust重写,对于新系统则可以完全使用Rust实现。
总结
Rust虽然作为一门系统级的语言,但是在后端业务开发中,它也是非常适合的,只是看起来比较难而已,当开发新系统时,可以考虑使用Rust,能够带来不小的收益。
Rust的生态也正在逐步完善,并且大家常说的编译慢的问题目前版本也有所改善,未来也会有更多的应用使用Rust重写。