【Rust基础】Rust后端开发常用库
使用Rust有一段时间了,期间尝试过使用Rust做后端开发、命令行工具开发,以及做端侧模型部署,也尝试过交叉编译、FFI调用等,也算是基本入门了。在用Rust做后端接口开发时,常常会找不到一些合适库,而这些库在Java中却很常见,于是在此汇总一下后Rust后端开发中常用的一些库。
-
基础框架
首先是基础web开发框架,在Java中,最常用的就是Spring了,而Spring其实不单单是一个开发框架,而是一整个完整的生态。其中的SpringBoot更是做了很好的封装,屏蔽了非常多的细节,这也导致了从Java系的web开发转到Rust时会遇到很多问题。而在Rust中,显然没有向Spring一样完整的生态支持,所以需要我们自己把各个模块组装在一起。
可选项:axum、actix-web、warp、rocket
从使用方式和使用难度上来说大同小异,axum和rocket可能会更容易上手一点,个人目前使用rocket稍微多一点,它也支持通过类似于Spring注解的方式来定义接口,支持参数映射。但是,它似乎没有和SpringBoot类似的参数校验工具,比如校验最大最小值、参数长度等,目前只能自己实现相关trait来校验了,还没有发现一个很好用的校验库来实现自定义返回错误码的功能。
-
数据库
基本上主流的数据库Rust都是支持的,都有Rust客户端,而我们开发时更多关注的是ORM框架,在Java中最常用的非MyBatis莫属了,其实Rust中有一个类似于MyBatis的库,叫做rbatis,目前还没有尝试过,看起来还不错,也支持动态SQL,只是从xml格式变为html感觉怪怪的。另一个比较常用的就是diesel,性能确实不错,支持流式处理,也支持联表,类型安全,但是,不怎么支持动态SQL,所以针对一些复杂查询可能会写的比较费力。可选项:diesel、rbatis、sqlx
其实sqlx不能算作ORM框架,但是它比较简单且灵活,适合一些小项目使用吧。
-
缓存
缓存算是中间件了,基本上就是看其是否有支持Rust的驱动或者SDK了。常用的Redis,有Rust版本的驱动,也叫redis。另一个是moka,一个内存缓存库,也很好用。可选项:redis、moka
除了以上两个常用的外,其他缓存大部分也都有Rust版的驱动,可以在crates.io上找到
-
池化
数据库连接、Redis连接以及其他涉及到网络连接的,基本都会用到连接池,Java里有Hikari、C3P0、DBCP等,这些池化工具常常被用来做连接复用,连接复用的好处一是能减少频繁创建连接带来的消耗,二是可以限制连接数量,在有限的系统资源下维持系统的稳定。而在Rust中,最常用的一个池化工具就是r2d2,它本身支持了许多连接的池化,如redis、diesel、sqlx以及postgres和oracle等。我们也可以实现它的trait来管理自定义的需要池化的对象,还是很方便的可选项:r2d2、deadpool
除了r2d2外,还有一个就是deadpool,它是支持异步的,而r2d2目前看是同步的,所以在并发性能上会有所提升。
-
多线程和异步
Rust支持async/await关键字来实现异步,但这只是一个语法,它需要一个异步的runtime来支持异步操作,最常用的莫过于tokio了,这个名字初次看到感觉也是有点怪怪的。大部分的需要异步的库都集成了tokio。要实现异步,只需要为函数加上asnyc即可,需要注意的是,要对async函数使用.await才会触发执行,否则是不会执行的,而.await又需要在async中才可以使用,所以层层嵌套到最外层到main函数,它就需要是async的了,我们可以使用#[tokio::main]来开启异步runtime。具体的tokio异步相关的一些问题,后面会再总结一下。
可选项:tokio
对于tokio中的spwan,它和Java线程池中的submit提交一个任务类似,spwan提交一个任务后,由tokio去调度执行,spwan会返回一个JoinHandle,有多个任务时,使用join!(task1,task2,…)来并发执行即可。使用上还是蛮简单的。
说到多线程,那免不了线程间的通信,有一个库叫crossbeam,提供了一些原子包装类型,以及线程安全的channel,可以很方便的在多线程中交互,比标准库中的channel好用一些。
-
错误处理
在Java中,错误处理一般是自定义的Exception,结合业务状态码,封装一个统一的响应格式。在Rust中,没有异常的概念,虽然有panic,但是,正常来讲,在后端服务中,应该确保不会发生panic,也就是必须要手动处理错误。Rust的每一个库都会有一个它自己的自定义的异常,这些异常(即Error)会暴露给调用方来处理,我们可以通过match来匹配指定的Error,或者if let来处理对应的Error,如果函数使用Result作为返回值,还可将Error返回给外层,或者用问号?来返回给外层。但是我们通常会使用多个库,一个函数里会有多个不同类型的错误,这就需要自定义个错误枚举,来实现std下的Error,给不同的Error类型包装成统一的自定义Error,或者结合Box+dyn实现动态包裹Error。而这些操作,也可以通过第三方的库来实现,常用的就是anyhow。
可选项:anyhow、eyre
anyhow其实依赖于thiserror,而thiserror提供了一些宏来包裹不同类型的错误,用法也很简单。我们可以将std::result::Result替换为anyhow的Result,返回anyhow!()或者bail!(“”),这样就可以将错误向外传递。
-
单元测试
Rust中的单元测试使用上比较简单,#[test]即可开启测试,对于异步的测试,使用#[tokio::test]即可开启。需要注意的是,如果使用IDE点击运行开始测试的话,依赖的feature不会自动检测到,可能会报错,需要配置一下。其他测试库还没有常见用到,后续有用到了再补充。
-
序列化/反序列化
主要是指Json的序列化和反序列化,Java中有FastJson和Jackson,Rust中有serde_json。serde是一个通用的序列化和反序列化库,支持常见的Json、Yaml,但是好像不支持XML。使用上很简单,在struct上加上#[derive(Serialize, Deserialize)]即可支持序列化和反序列化,需要注意的是,struct里边的字段也需要支持序列化和反序列化,常用的基础数据类型是已经都实现了了的。
可选项:serde、serde_json、serde_yaml
除了Json外,还有protobuf,Rust也支持,叫做prost,可以很方便的进行encode和decode,它也支持从proto文件生成rs文件,构建工具叫做prost-build,我们可以在build.rs中配置需要生成的内容。
还有arrow格式,这个是一种跨平台的数据格式,Rust也是支持的,如果需要跨进程传输数据,可以使用这个。
-
消息队列
消息队列也算是中间件,常用的kafka、rabbitmq、rocketmq等都有rust版的客户端实现。说到消息队列,除了这几个外,还有个库叫做zmq,用来做网络通信,也很不错,简单易用,支持多种TCP连接模式,也支持IPC,对于跨进程或者不同机器之间高效通信很适合。
可选项:kafka、rabbitmq、rocketmq、zmq
-
日志
最后,就是日志库了,无论是Java还是Rust中,日志库都很多,Java中的Log4j可以对于Rust中的log库,都定义了统一的接口,有着不同的实现。常用的有env_logger、tracing、log4rs,tracing还未曾使用过,不过看介绍,似乎比较复杂一些,而env_logger则相对简单很多。env_logger支持不同级别的日志输出,支持按model过滤日志级别,支持彩色日志,但是,不支持输出到文件。所以log4rs可能更适合,它也支持通过yaml配置日志格式,支持不同的输出,支持滚动日志,看起来是比较适合web后端日志的。
可选项:tracing、env_logger、log4rs
-
其他
除了以上了解到库外,还有其他一些使用到的库,也记录一下。
- rand:随机数生成库
- image: 图像处理
- imageproc:实现了一些图像处理相关的算法
- base64:base64编码解码
- chrono:日期时间库,这个很常用,提供了大量的日期和时间操作API
- once_cell:全局静态变量初始化。Rust中static类型不能像Java一样很方便的定义全局静态变量,这个库提供了简单的静态变量初始化方式,并且线程安全,确保只被初始化一次。
- strum:枚举遍历以及枚举值映射
- reqwest:用于简单的http请求
- tokio-cron-scheduler:定时任务
- dashmap:简化并发编程中的hashmap带来的问题
Rust做Web开发,有好处也有坏处,先说好处。首先确实能够节约机器成本,一个Rust包通常来说会比Jar包小很多,而运行时占用的内存就比Java小的更多了,能够减小5倍左右;其次,Rust写的程序,确实会比Java稳定,能够规避一些潜在的问题,例如NPE等,当然前提是不要到处unwrap,否则一样会崩。另外,对于客户端来说,Tauri使用Rust构架,如果做客户端开发,前端使用Vue,后端使用Rust还是很方便的。还有就是在部署层面,Rust可以跨平台编译,使用musl工具链编译后,基本上可以部署到任何linux系统上,对于需要支持不同平台的应用来说,非常方便,而对于Java来说还需要JVM的环境,虽然Java21已经支持原生应用编译了,但是依赖于泛型的框架来说,编译可能还是有些坑的。
再说不好的地方,一是学习成本,Rust的确没有Java容易学,尤其是对Java越熟悉的,转Rust可能反而会比较麻烦,因为很多概念两者并不相通,这是学习成本,并非开发成本,因为如果熟悉了Rust的话,开发速度其实并不慢,我们更多需要的是在开发初期做好设计,不论架构还是API,否则后续修改起来还是比较痛苦的。所以这也就是Rust做Web开发的另一个不好的地方,不能快速适应业务上的变化,由于本身的语法限制,你不能向Java一样运用各种设计模式来应对业务变化,而需要花费更多的时间去衡量是否需要重构或者其他方案,换句话说,可能对于我们做开发的要求会变高,考虑的东西也会变多,比如改用String还是&str?不过,从另一种角度看,这也提高了我们的编程的严谨性和系统的稳定性吧。
最近也在尝试使用Rust在嵌入式设备上部署例如Yolo等模型,以及一些大模型,想尝试使用ONNX简化部署流程,期间也遇到了很多问题,比如OpenCV交叉编译、Rust的交叉编译、FFI调用、跨进程通信等问题。看起来有点混乱,这些后续有时间再总结一下。本身是从5年的Java转Rust,目前看Rust国内只有量化和区块链这两个方向稍微多一点,其他的几乎没有岗位,也是一脸迷茫,期待后续Rust能够在不同领域发展起来,多一些工作机会吧。
相关文章:
【Rust基础】Rust后端开发常用库
使用Rust有一段时间了,期间尝试过使用Rust做后端开发、命令行工具开发,以及做端侧模型部署,也尝试过交叉编译、FFI调用等,也算是基本入门了。在用Rust做后端接口开发时,常常会找不到一些合适库,而这些库在J…...
如何使用Cursor的claude-3.7模型来开发高保真的原型设计图,学会写好的提示词人人都是设计师
1、想要开发出高保真的设计图原型,需要给出cursor具体的提示词:比如我想开发一款IT面试题小程序,给出的提示词是这样的 我想开发一个 {IT面试题库小程序},现在需要输出高保真的原型图,请通过以下方式帮我完成所有界面…...
AGI大模型(5):提示词工程
1 什么是提示词工程(Prompt) 所谓的提示词其实指的就是提供给模型的⼀个⽂本⽚段,⽤于指导模型⽣成特定的输出或回答。提示词的⽬的是为模型提供⼀个任务的上下⽂,以便模型能够更准确地理解⽤户的意图,并⽣成相关的回…...
Redis Sentinel (哨兵模式)深度解析:构建高可用分布式缓存系统的核心机制
一、传统主从复制的痛点 在分布式系统架构中,Redis 作为高性能缓存和数据存储解决方案,其可用性直接关系到整个系统的稳定性。传统的主从复制架构虽然实现了数据冗余,但在面临节点故障时仍存在明显缺陷: 手动故障转移…...
微信小程序-实现锚点跳转,页面加载后自动跳转、点击跳转到指定位置
一、页面加载后滚动到指定位置,onLoad或onReady里执行。 scrollAfterLoading() {const query wx.createSelectorQuery()query.select(#cont1).boundingClientRect()query.selectViewport().scrollOffset()query.exec(function (res) {wx.pageScrollTo({scrollTop:…...
[LeetCode热门100题]|137,260,268,面试17.19
1、137 只出现一次数字|| 1、题目描述 137 只出现一次数字||https://leetcode.cn/problems/single-number-ii/description/ 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你…...
Android子线程更新View的方法原理
对于所有的Android开发者来说,“View的更新必须在UI线程中进行”是一项最基本常识。 如果不在UI线程中更新View,系统会抛出CalledFromWrongThreadException异常。那么有没有什么办法可以不在UI线程中更新View?答案当然是有的! 一…...
Kafka常用指令(详细)
Kafka常用指令(详细) 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon,窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...
Golang Channel 使用详解、注意事项与死锁分析
#作者:西门吹雪 文章目录 一、引言:Channel 在 Go 并发编程中的关键地位二、Channel 基础概念深度剖析2.1 独特特性2.2 类型与分类细解 三、Channel 基本使用实操指南3.1 声明与初始化3.3 单向 Channel 的运用 四、Channel 典型使用场景实战案例4.1 协程…...
使用LiteFlow实现阻塞审批工作流
在 LiteFlow 中实现阻塞的审批工作流,你可以使用异步处理与同步逻辑结合,实现节点的等待 使用 LiteFlow 实现阻塞审批工作流 下面是如何实现一个带有阻塞审批功能的 LiteFlow 工作流示例。 1. 引入依赖 确保您的 pom.xml 文件中已引入 LiteFlow 和 S…...
2025移动端软件供应链安全开源治理方案最佳实践
2025年3月13日,由中国软件评测中心、CAPPVD漏洞库联合主办的“第六期移动互联网APP产品安全漏洞技术沙龙”在海口成功召开。悬镜安全基于移动端数字供应链安全开源治理方案荣获中国软件评测中心“2024移动互联网APP产品安全漏洞治理”优秀案例,并获颁证书…...
Git Fast-forward 合并详解:原理、场景与最佳实践
在使用 Git 进行团队协作时,我们经常需要合并分支。合并方式有很多种,其中 Fast-forward(快速合并) 是一种最简单且无冲突的合并方式。本文将详细介绍 Fast-forward 的原理、适用场景、常见问题及最佳实践。 一、Fast-forward 合并…...
《C#上位机开发从门外到门内》2-3:SPI总线协议详解及应用实践
文章目录 一、引言二、SPI总线协议的基本原理三、SPI通信模式详解 —— CPOL与CPHA3.1 时钟极性(CPOL)3.2 时钟相位(CPHA)3.3 四种SPI模式 四、主从设备通信机制4.1 通信流程概述4.2 数据帧结构与传输细节4.3 主设备与从设备的协同…...
vscode出现:No module named ‘requests‘ 问题的解决方法
问题: ① No module named requests ② pip install requests:显示已经安装成功 运行失败原因: 我的失败原因是因为:我的python环境有两个,电脑C盘默认一个、pycharm下载后在它的路径下有一个。而vscode所运行的环境…...
【openwebui 搭建本地知识库(RAG搭建本地知识库)】
安装准备 openwebui 这个本地安装之前写过使用python安装。也可以直接用docker 命令 docker run --rm -d \-p 3080:8080 \-p 3081:8081 \-e WEBUI_AUTHtrue \-e DEFAULT_LOCALEcn \-e GLOBAL_LOG_LEVEL"INFO" \-e AIOHTTP_CLIENT_TIMEOUT100 \--privilegedtrue \-…...
Docker Compose 使用笔记
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具; docker-compose.yml 文件则是 Docker Compose 用来配置应用服务的核心文件,它以 YAML 格式编写。 YAML 文件用途: 服务定义:在 docker-compose.yml 文件中&…...
雷池WAF 处理 HTTP 请求的流程
项目介绍 SafeLine,中文名 "雷池",是一款简单好用, 效果突出的 Web 应用防火墙(WAF),可以保护 Web 服务不受黑客攻击。 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、…...
JAVA-Thread类实现多线程
引言: 本章博客涉及进程线程内容,如果不了解的可以看:什么是进程线程-CSDN博客 线程是操作系统的概念,操作系统提供的API供程序员使用操作。但是不同的操作系统(Winodws、Linux、Unix……差别很大),但是做为JAVA程序员就不需要担心…...
【算法】DFS、BFS、拓扑排序
⭐️个人主页:小羊 ⭐️所属专栏:算法 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 持续更新中...1、DFS2、BFSN 叉树的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度 3、多源BFS腐烂的苹果 4、拓扑排序 持续更新中…...
MySQL中 IN 到底走不走索引?
文章目录 前言数据库表结构查询sqlEXPLAIN介绍EXPLAIN 的输出每列解释 强制走索引查询时添加条件(复合索引字段)查询小时查询分钟 总结 前言 在 MySQL 中,IN 语句是否能够利用索引取决于多个因素,包括但不限于查询的具体形式、表的统计信息、索引的选择…...
centos没有ll
vi /etc/bashrc alias ll‘ls -l’ source /etc/bashrc...
腾讯云低代码开发应用
创建客户端应用 如上所示,登录腾讯云微搭低代码业务控制台,开始搭建企业官网应用 如上所示,在腾讯云微搭低代码业务控制台中,开始创建企业官网应用 如上所示,在腾讯云微搭低代码业务控制台中,开始编辑企业官…...
医疗APP开发如何实现跨机构数据互通
医疗APP开发如何实现跨机构数据互通 在数字化医疗时代,医疗APP开发已成为连接医疗机构、患者和医疗资源的重要桥梁。然而,如何实现跨机构的数据互通,成为医疗APP开发中的一大挑战。本文将探讨如何通过医疗APP开发实现跨机构数据互通,提升医疗服务效率和患者体验。我们将涵…...
深度学习项目--基于DenseNet网络的“乳腺癌图像识别”,准确率90%+,pytorch复现
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 前言 如果说最经典的神经网络,ResNet肯定是一个,从ResNet发布后,很多人做了修改,denseNet网络无疑是最成功的…...
级联树SELECTTREE格式调整
步骤: 1、将全部列表设置成Map<Long, List<Obejct>> map的格式,方便查看每个父级对应的子列表,减少循环次数 2、对这个map进行递归,重新进行级联树的集合调整,将子集放置在对应的childs里面。 public Dyna…...
编译RTTR 0.9.6 (CMake + vs2019)解决std::iterator对rapidjson编译事项
RTTR编译 使用CMake和VS2019 x64编译RTTR 0.9.6指南一、下载RTTR 0.9.6并配置CMake二、在VS2019上编译RTTR 0.9.6解决rapidjson与C17兼容性问题 三、安装RTTR四、最简单的还是用vcpkg 使用CMake和VS2019 x64编译RTTR 0.9.6指南 本文将指导您完成从下载RTTR 0.9.6到使用CMake生…...
深入理解JavaScript构造函数与原型链:从原理到最佳实践
一、开篇:为什么需要理解原型链? 在JavaScript开发中,90%以上的"诡异"bug都与原型链机制相关。理解构造函数与原型链的运行原理,不仅能帮助我们写出更优雅的代码,还能在框架源码阅读、性能优化等场景中游刃…...
【Linux 指北】常用 Linux 指令汇总
第一章、常用基本指令 # 注意: # #表示管理员 # $表示普通用户 [rootlocalhost Practice]# 说明此处表示管理员01. ls 指令 语法: ls [选项][目录或文件] 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件…...
第27周JavaSpringboot 前后端联调
电商前后端联调课程笔记 一、项目启动与环境搭建 1.1 项目启动 在学习电商项目的前后端联调之前,需要先掌握如何启动项目。项目启动是整个开发流程的基础,只有成功启动项目,才能进行后续的开发与调试工作。 1.1.1 环境安装 环境安装是项…...
QT中的布局管理
在 Qt 中,布局管理器(如 QHBoxLayout 和 QVBoxLayout)的构造函数可以接受一个 QWidget* 参数,用于指定该布局的父控件。如果指定了父控件,布局会自动将其管理的控件添加到父控件中。 在你的代码中,QHBoxLa…...
