오늘의 질문:
오늘의 목표:
오늘의 참고 자료
나온지 1-2년 정도 된 따끈한 영상이라서 그런지 여전히 잘 돌아간다.
영상을 따라한다고 바로 돌아가는 것은 아니고, GitHub 패치가 되어 있어 레포를 클론하면 바로 동작한다.
syntax = "proto3";
package calculator;
service Calculator {
rpc Add(CalculationRequest) returns (CalculationResponse);
rpc Divide(CalculationRequest) returns (CalculationResponse);
}
message CalculationRequest {
int64 a = 1;
int64 b = 2;
}
message CalculationResponse { int64 result = 1; }
service Admin {
rpc GetRequestCount(GetCountRequest) returns (CounterResponse);
}
message GetCountRequest {}
message CounterResponse { uint64 count = 1; }
위와 같이 간단한 calculator proto 파일을 정의한다.
Calculator 서비스는 2개의 메서드가 있는데
여기까지는 gRPC를 사용할 때 언어 무관하게 공통적으로 셋업해주어야 하는 부분이다.
use std::error::Error;
use std::{env, path::PathBuf};
fn main() -> Result<(), Box<dyn Error>> {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
tonic_build::configure()
.file_descriptor_set_path(out_dir.join("calculator_descriptor.bin"))
.compile(&["proto/calculator.proto"], &["proto"])?;
tonic_build::compile_protos("proto/calculator.proto")?;
Ok(())
}
# Cargo.toml
[build-dependencies]
tonic-build = "0.11"
다른 cargo 프로젝트와 조금 다른 점이 있다면, 빌드를 하는 과정에 protoc이라는 외부 디펜던시를 사용하는 과정이 포함된다는 것이다.
따라서 cargo build 만으로 해결되는 것이 아니라, 따로 해당 protoc을 실행시켜 proto 파일을 컴파일하는 과정을 기술한 build.rs 또한 추가해야 한다. tonic_build 라는 모듈에서 이를 쉽게 해줄 수 있는 api를 제공한다.
use proto::calculator_client::CalculatorClient;
use std::error::Error;
pub mod proto {
tonic::include_proto!("calculator");
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let url = "http://[::1]:50051";
let mut client = CalculatorClient::connect(url).await?;
let req = proto::CalculationRequest { a: 4, b: 5 };
let request = tonic::Request::new(req);
let response = client.add(request).await?;
println!("Response: {:?}", response.get_ref().result);
Ok(())
}
pub mod proto {}를 선언하면, tonic crate에서 자동으로 calculator 와 관련된 struct과 함수들을 자동으로 선언해주므로,
calculator와 관련된 add, Request 등의 함수들을 바로 사용할 수 있게 된다.
위 코드에서 보이는 것처럼 Calculatorclient를 바로 사용할 수 있다.

/// Generated client implementations
이미지의 위 주석에서 보이는 것처럼
pub struct CalculatorClient를 만들어준다.
서버는 조금 더 복잡하다.
client 에서 보았듯이, calculator_server가 자동으로 생성된다.
calculator_server 로 동작하기 위해서는 우선, Calculator로서 동작하는 어떤 실체를 만들어야 한다.

자동으로 생성된 calculator.rs 를 보면 proto 파일에 정의된 형태의 trait가 만들어진 것을 볼 수 있다. 위 trait를 구현한 어떤 서비스를 만들면 Calculator server에 등록할 수 있다.

위와 같이 Calculator 를 impl 하는 CalculatorService 를 완성해 준 다음,

main 함수에서 이를 생성하고

CalculatorService를 이용해 CalculatorServer를 생성하고,
이 생성된 서버를 add_service 함수를 통해 등록해주면, grpc 서버로서 Calculator 서비스를 서빙하게 된다.
gRPC의 강점은 역시 언어에 구애받지 않고, 바로 다른 종류의 언어를 사용하는 클라이언트에서 사용할 수 있다는 점이 있다.
https://github.com/dreamsofcode-io/grpcalculator-web
위 레포를 받고
vite run dev
npm run dev
bun run dev
셋 중 아무거나 원하는 걸로 실행을 하면 간단한 웹 페이지가 뜨게 된다.

간단하고 흔한 react 웹 페이지인데, 사용법이 이렇게 간단하다.
grpc transport에 연결하고, CalculatorClient를 생성하고, 거기에 add 함수를 실행시키면 원격으로 해당 함수가 실행된다.

이렇게 서버로부터 결과를 잘 받아오는 것을 확인할 수 있다.

Rust에서 간단한 gRPC 사용법을 알아봤다. 매우 간단해서 편하게 사용할 수 있다.