05
微服务与分布式:reqwest 与 gRPC
reqwest, tonic, Resilience
单体写够了,就要拆微服务。服务之间怎么通信?HTTP 用 reqwest(Rust 版 requests),gRPC 用 tonic。这一章讲清楚两种 RPC 的姿势,再加限流熔断这些生产必备的韧性组件。
reqwest:异步 HTTP 客户端
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.build()?;
// GET JSON
let resp = client.get("https://api.example.com/users")
.bearer_auth("token")
.send().await?
.json::<Vec<User>>().await?;
// POST JSON
let resp = client.post("https://api.example.com/orders")
.json(&NewOrder { item: "book".into() })
.send().await?;
gRPC:tonic 框架
tonic 是 Rust 的 gRPC 框架,配合 prost(protobuf 代码生成)。你写一个 .proto 文件,tonic-build 在编译期生成 Rust trait,你只要实现这个 trait。
// proto/order.proto
syntax = "proto3";
package order;
service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
}
message GetOrderRequest { int64 id = 1; }
message Order { int64 id = 1; string item = 2; }
// build.rs —— 编译期生成代码
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure().compile_protos(&["proto/order.proto"], &["proto"])?;
Ok(())
}
// src/main.rs —— 实现 trait
pub mod order { tonic::include_proto!("order"); }
use order::{order_service_server::{OrderService, OrderServiceServer}, *};
struct MyOrderService;
#[tonic::async_trait]
impl OrderService for MyOrderService {
async fn get_order(
&self,
req: tonic::Request<GetOrderRequest>,
) -> Result<tonic::Response<Order>, tonic::Status> {
Ok(tonic::Response::new(Order {
id: req.into_inner().id,
item: "book".into(),
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic::transport::Server::builder()
.add_service(OrderServiceServer::new(MyOrderService))
.serve(([0,0,0,0], 50051).into())
.await?;
Ok(())
}
韧性组件:限流、熔断、消息队列
| 能力 | crate | 说明 |
|---|---|---|
| 限流 | governor | 令牌桶算法,Rust 限流首选 |
| 并发限制 | tower::limit::ConcurrencyLimit | Axum 中间件,限制同时在飞请求数 |
| RabbitMQ | lapin | 异步 AMQP 客户端 |
| Kafka | rdkafka | librdkafka 绑定,生产级 |
| 分布式追踪 | tracing-opentelemetry | 对接 Jaeger / OTLP |
健康检查与分布式追踪
生产微服务的标配:健康检查 endpoint 给负载均衡探活,分布式追踪给运维看请求链路。Rust 里这两件事都很便宜。
// 健康检查:/healthz 给 K8s/LB 探活
async fn healthz() -> &static str { "ok" }
// readiness:依赖都活着才返回 200
async fn readyz(State(pool): State<sqlx::PgPool>) -> (axum::http::StatusCode, &static str) {
if sqlx::query("SELECT 1").execute(&pool).await.is_ok() {
(axum::http::StatusCode::OK, "ready")
} else {
(axum::http::StatusCode::SERVICE_UNAVAILABLE, "not ready")
}
}
分布式追踪用 tracing-opentelemetry:Axum 的 TraceLayer 会自动把 W3C traceparent 头透传下去,tonic 拦截器把 span context 塞进 gRPC metadata。一个请求跨服务的完整路径在 Jaeger 里一目了然。
记
本章小结
① HTTP 调用用 reqwest,gRPC 用 tonic + prost,proto 先行。
② 生产韧性:governor 限流、tower 并发限制、lapin/rdkafka 消息队列、tracing-opentelemetry 追踪。
③ 健康检查分 /healthz(进程活着就行)和 /readyz(依赖都活着),给 K8s/LB 用。