Motore 与 Volo 的关系
理解它们之间的关系对深入使用 Volo(进行框架扩展、开发自定义中间件 等等)至关重要。
简单来说:Motore 定义了 Service 和 Layer 这两个通用的、核心的异步中间件抽象接口,而 Volo 是这些抽象接口的使用者和特定场景(RPC)下的实现者。
Motore 更通用,理论上可用于任何需要异步服务抽象的地方。Volo 则更具体地专注于 RPC 领域,利用 Motore 的抽象来实现 RPC 特有的功能。
可以将 Motore 视为 Volo 中间件系统的 “骨架”,Volo 本身为 “骨架” 注入了 “血肉”(实现 RPC 所需的框架层面的组件和逻辑),用户最终在 Volo 上去填充具体的业务逻辑。
Motore: 核心抽象层
Motore 是一个独立的 Rust crate (cloudwego/motore),其设计目标是提供一套简洁、高效且符合人体工程学的异步中间件抽象。虽然它受到了业界广泛使用的 Tower 库的启发,但在设计上它利用了 Rust 最新的 AFIT (async fn in trait) 和 RPITIT (return position impl trait in trait) 特性。
Motore 主要定义了两个核心 Trait:
-
Service<Cx, Request>:- 代表一个处理请求并异步返回
Result<Response, Error>的功能单元。 - 这是 Motore 中最基础的构件,可以表示客户端、服务器或中间件本身。
- 其核心是
async fn call(&self, cx: &mut Cx, req: Request) -> Result<Self::Response, Self::Error>方法。它接收一个上下文Cx和请求Request,并异步返回结果。
- 代表一个处理请求并异步返回
-
Layer<S>:- 代表一个“装饰器”或“工厂”,用于包装和增强
Service。 - 它接收一个内部
Service(泛型S),并返回一个新的、经过包装的Service(Self::Service)。 Layer本身不直接处理请求,而是用于构建和组合Service链(即中间件栈)。- 其核心是
fn layer(self, inner: S) -> Self::Service方法。
- 代表一个“装饰器”或“工厂”,用于包装和增强
Motore 旨在提供一套协议无关的、可重用的中间件基础结构。它专注于抽象本身,而非 Volo 那样的特定应用领域(如 RPC)的框架,但 Motore 可以作为构建这种框架的基础。
如果你熟悉 Tower 的概念,那么理解 Motore 会更容易,同时也能体会到 AFIT/RPITIT 带来的写法上的简化。
和 Tower 相比,Motore 利用 AFIT 和 RPITIT 简化异步中间件的编写,并减少因类型擦除(如 Box<dyn Service>)带来的性能开销和心智负担。
Motore 还提供了一些辅助工具,如 ServiceBuilder 用于链式调用添加多个 Layer,或更底层的 Stack 用于组合两个 Layer 等。
Volo: 基于 Motore 的 RPC 框架
Volo 是一个功能完备的 RPC 框架,支持 Thrift 和 gRPC。Volo 直接依赖并深度整合了 Motore 作为其内部中间件系统的基础。
-
依赖与重导出:
- Volo 在其
Cargo.toml中直接依赖motorecrate。 - Volo 在其库的入口(
volo/src/lib.rs)重新导出了 Motore 的核心 Trait:pub use motore::{Service, layer, Layer, service};。当你在 Volo 项目中使用volo::Service或volo::Layer时,你实际上用的就是 Motore 那边的 Trait。
- Volo 在其
-
具体实现:
- Volo 框架内部大量使用 Motore 提供的抽象来构建其功能。例如:
- 负载均衡 (
LoadBalanceLayer) 是一个实现了 MotoreLayer的组件。 - 超时控制、日志记录、指标收集等功能都可以通过实现 Motore
Layer来集成。 - 最终用户编写的 RPC 服务处理逻辑(Handler),以及框架生成的客户端调用逻辑,都会被包装成符合 Motore
Service接口的形式。
- 负载均衡 (
- Volo 提供了许多特定于 RPC 场景的
Layer实现,例如处理 Thrift 或 gRPC 协议细节、服务发现集成等,这些实现都遵循 Motore 定义的Layer接口。
- Volo 框架内部大量使用 Motore 提供的抽象来构建其功能。例如:
-
用户交互:
- Volo 用户一般通过
Client::builder()或Server::new()提供的 API 来配置和添加中间件。这些 API 内部就用到了motore::ServiceBuilder、或底层的motore::layer::Stack来将用户提供的Layer套在Service上。 - 用户如果需要编写自定义中间件,也需要实现
motore::LayerTrait(或者直接实现motore::Service来包装另一个 Service)。
- Volo 用户一般通过
为什么需要 Motore?
将核心抽象(Motore)与框架实现(Volo)分离带来了一些好处:
- 模块化与可复用性: Motore 定义的抽象和一些基础 Layer(如超时)是通用的,可以被 Volo 之外的项目拿来写中间件和服务。
- 关注点分离: Motore 专注于提供稳定、高效、符合人体工程学的核心抽象。Volo 则专注于 RPC 框架的业务逻辑和协议细节。