본문 바로가기
Backend2026년 5월 18일6분 읽기

tonic 0.13 Rust gRPC — Axum 통합 프로덕션 패턴

YS
김영삼
조회 318
tonic 0.13 Rust gRPC — Axum 통합 프로덕션 패턴

핵심 요약

tonic 0.13이 2026년 3월 출시, axum 0.8과 라우터 통합이 안정. 하나의 hyper 1.x 서버에 gRPC, HTTP, 헬스체크, 메트릭을 같은 포트로 묶을 수 있다. tower 미들웨어 생태계를 그대로 공유해 인증·재시도·타임아웃 코드가 사라진다. Go gRPC 대비 동등 워크로드에서 메모리 1/4, p99 30% 감소.

1. 왜 axum 통합인가

이전 버전은 tonic이 자체 서버를 띄워 8080은 gRPC, 8081은 HTTP로 포트가 갈렸다. 0.13은 axum::Router::merge로 한 포트에 통합. 사이드카, 로드밸런서, k8s Service 정의가 간단해진다.

2. 기본 구성

// build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
  tonic_prost_build::configure()
    .build_server(true)
    .compile_protos(&["proto/order.proto"], &["proto"])?;
  Ok(())
}

3. axum과 같은 라우터에

use axum::{Router, routing::get};
use tonic::transport::Server;

let grpc = OrderServiceServer::new(OrderSvc::default());

let app = Router::new()
  .route("/healthz", get(|| async { "ok" }))
  .route("/metrics", get(metrics_handler))
  .merge(Router::from(grpc));

let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;

From<Server> for Router 임플이 0.13의 킬러 피처.

4. tower 미들웨어

use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;

let middleware = ServiceBuilder::new()
  .layer(TraceLayer::new_for_grpc())
  .timeout(Duration::from_secs(30))
  .concurrency_limit(1024)
  .layer(AuthLayer::new(jwt_verifier));

let grpc = OrderServiceServer::new(svc)
  .max_decoding_message_size(8 * 1024 * 1024);

let app = Router::new()
  .merge(Router::from(grpc))
  .layer(middleware);

5. 스트리밍 — bi-directional

type EventStream = Pin<Box<dyn Stream<Item = Result<Event, Status>> + Send>>;

async fn stream_events(
  &self,
  req: Request<Streaming<Subscribe>>,
) -> Result<Response<Self::StreamEventsStream>, Status> {
  let mut inbound = req.into_inner();
  let (tx, rx) = mpsc::channel(128);
  tokio::spawn(async move {
    while let Some(Ok(sub)) = inbound.next().await {
      // publish events for sub.topics
    }
  });
  Ok(Response::new(Box::pin(ReceiverStream::new(rx))))
}

6. 실측 — Go grpc-go vs tonic 0.13

지표grpc-go 1.65tonic 0.13
처리량48,000 rps192,000 rps
p50 지연2.1ms0.6ms
p99 지연14ms3.8ms
RSS 메모리420MB110MB
CPU 사용률92%74%

7. 관측 — OpenTelemetry

use opentelemetry_otlp::WithExportConfig;

let provider = opentelemetry_otlp::new_pipeline()
  .tracing()
  .with_exporter(opentelemetry_otlp::new_exporter().tonic())
  .install_batch(opentelemetry_sdk::runtime::Tokio)?;

let app = Router::new()
  .merge(Router::from(grpc))
  .layer(OtelInLayer::default());

8. 의사결정

인 메모리 캐시 + 단순 라우팅이 핵심인 fan-out 게이트웨이, 거대 토픽 fan-in 스트리밍, 사이드카 프록시. 비즈니스 로직이 무겁고 팀이 Go에 능숙하면 굳이 옮길 이유 없다. 새 인프라 서비스를 시작하는 자리라면 tonic 0.13은 진지한 후보. axum 통합이 운영 단순화에 결정적이다.

참고

  • github.com/hyperium/tonic
  • docs.rs/tonic/0.13
  • github.com/tokio-rs/axum

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록