connect-rust 加入了 Connect 项目
Anthropic 开发了 connect-rust,现已将其贡献给 Connect 项目。至此,Rust 与 Go、Node.js、Web、Swift、Kotlin、Dart、Python 一样,拥有了官方的 Connect 实现。
包含哪些内容
connectrpccrate:支持 Connect、gRPC 和 gRPC-Web 协议的服务端与客户端。- Tower 和 Axum 集成,另有独立的 Hyper 服务器,不想引入框架时可以直接使用。
- gRPC 健康检查和服务器反射,分别在
connectrpc-health和connectrpc-reflectioncrate 中。 - Buffa:零拷贝 Protobuf 运行时,支持 Editions 和 ProtoJSON。
使用效果
仓库中的 examples/eliza 用 Rust 实现了经典的 ELIZA 聊天机器人。客户端可以连接本地 Rust 服务器,也可以连接 https://demo.connectrpc.com 上的在线演示。
创建客户端只需三行代码:
let http = make_transport(&args, &base_uri)?;
let config = ClientConfig::new(base_uri);
let client = ElizaServiceClient::new(http, config);ElizaServiceClient 由服务的 Protobuf schema 生成——见下文。
Introduce 是服务端流式调用,Eliza 会发送几句话,客户端逐条打印收到的内容:
let mut intro = client
.introduce(IntroduceRequest {
name: name.to_owned(),
..Default::default()
})
.await?;
while let Some(msg) = intro.message().await? {
println!("Eliza> {}", msg.view().sentence);
}view() 以借用方式访问解码后的消息,读取 sentence 不会从响应缓冲区复制任何数据。完整示例还包含双向的 Converse 循环、TLS 和 mTLS 参数,以及同一 schema 对应的服务端代码。
工作原理
Tower 是异步 Rust 中间件的事实标准:Axum、tonic,以及开发者栈中已有的超时、重试、追踪和限流等层都构建于其上。connectrpc 同样如此。Connect 路由器是一个 tower::Service,因此原生支持所有 Tower 层,并能直接嵌入兼容 Tower 的 HTTP 框架。通过 Axum 时,路由器的 .into_axum_service() 会对接 Axum 的 fallback_service,使 Connect RPC 与普通 HTTP 路由共享同一个服务器:比如健康检查、静态文件和 OAuth 回调。这一转换由 axum feature 提供;server feature 则内置了一个独立的 Hyper 服务器,如果你根本不想引入任何框架的话。
单个服务器同时处理三种协议和全部四种 RPC 类型,因此一个 Rust 服务无需维护两套栈,就能同时向浏览器(gRPC-Web)和 gRPC 客户端提供服务。
消息序列化由 buffa 提供——这是 Anthropic 在开发 connect-rust 的同时构建的 Protobuf 运行时。Buffa 能生成拥有所有权的消息类型,也能生成借用视图,因此字符串和字节字段可以直接指向请求缓冲区,而不必分配新的 String 或 Vec<u8>。只读取消息的处理器只需处理借用的 &str 和 &[u8] 字段;需要保留消息的代码再将其转为拥有所有权的值。Buffa 还支持 Protobuf Editions 和 ProtoJSON。
该实现通过了完整的 Connect 合规测试套件,涵盖三种协议、共计 3,600 项服务端和 6,872 项客户端测试。目前仍处于 pre-1.0 阶段,API 在 0.x 版本中可能会有变动,但它并非原型:它已在 Anthropic 的生产环境中运行。在一项以解码为主、字符串密集的负载基准测试中,它在高并发下比 tonic 提升了约三分之一的吞吐量,且分配器消耗的 CPU 时间大幅减少。
客户端、服务端、TLS 和 Axum 各组件均由 feature flag 控制,仅编译实际使用的部分。最低支持的 Rust 版本为 1.88。
代码生成
生成 Rust 代码有三种方式。
生成 SDK。如果架构定义保存在 BSR(Buf Schema Registry)中,cargo 可以从 BSR 的 cargo 注册表 拉取生成的代码,像处理其他依赖一样简单:一个 crate 包含由 Buffa 生成的 Protobuf 类型,另一个包含 Connect 客户端和服务 trait。无需生成步骤,也无需提交生成文件。
# .cargo/config.toml
[registries.buf]
index = "sparse+https://buf.build/gen/cargo/"
credential-provider = "cargo:token"$ cargo login --registry buf # 粘贴 "Bearer <your BSR token>"
$ cargo add --registry buf \
connectrpc_eliza_connectrpc_rust@^0.9.0-0 \
connectrpc_eliza_anthropics_buffa@^0.9.1-0在构建时生成代码。 connectrpc-build 从 build.rs 运行代码生成,无需安装任何 插件 二进制文件,也无生成文件需要提交:
fn main() {
connectrpc_build::Config::new()
.files(&["greet/v1/greet.proto"])
.use_buf()
.include_file("_connectrpc.rs")
.compile()
.unwrap();
}use_buf() 使用 Buf CLI 编译描述符;若不指定该选项,connectrpc-build 则通过外部调用 protoc 完成。无论如何,PATH 中需要存在两者之一。
提交生成结果。如果你希望沿用传统的 buf generate 流程(使用本地或远程插件),同样可以这样做。项目 README 中有详细说明。
此次迁移的意义
Iain McGinniss 和 Drew Sacamano 在 RFC 007 中将 Rust 提名为官方实现。目前仓库已移至connectrpc 组织名下,所有 issues、pull requests 和版本发布均在该组织下进行,Iain 继续担任维护者。Buffa 是一个通用的 Protobuf 运行时,而非 Connect 组件,因此仍保留在 anthropics/buffa。
致谢
感谢 Anthropic 将 connect-rust 贡献给 Connect 项目,尤其要感谢主导开发的 Iain McGinniss。两个项目的合并大约花了六周时间,在 Iain 的指导下,大部分工作由 Claude Opus 4.6 完成。
Iain 的文章 Zero-copy protobuf and ConnectRPC for Rust 深入介绍了 Buffa 的零拷贝方案、Connect 的实现细节以及基准测试结果。
下一篇