1. Introduction to gRPC
- Google의 원격 프로시저 호출 오픈소스 프로젝트
- 서비스 메서드 계약 중심의 통신 방식 (❌ URL 중심의 REST API 방식)
- ✅ 원격 서버 애플리케이션 메서드를 로컬 메서드처럼 호출할 수 있도록 추상화 해줌
- ✅ 보통 HTTP/2 기반으로 동작함
- ➡️ 다양한 언어/환경/기술스택에서 서로 통신할 수 있음
Concept Diagram

- 서비스 인터페이스와 메시지 구조를 미리 정의함
- ✅ 전송 효율 좋음 / 타입 명확 / 코드 생성 가능 / 다국어 환경에서 계약 기반 통신이 쉬움
- ➡️ 분산 시스템에서 서비스 간 호출을 체계적으로 관리하기 좋음
Stub
- 서버 메서드를 로컬 메서드처럼 보이게 해주는 클라이언트 프록시
- ✅ 서버와 동일한 메서드를 제공함
2. Protocol Buffers
- Google이 만든 오픈소스 바이너리 직렬화 포맷/스키마 정의 체계
- ✅ 구조화된 데이터를 효율적으로 직렬화/역직렬화 해줌
- ➡️ JSON보다 payload 작음, 파싱 속도 빠름
Proto Buffer Encoding
- 데이터를 필드 번호(tag) + 타입(wire_type) + 값 형태의 바이너리로 인코딩함
- 필드 이름을 문자열로 반복하지 않고 번호를 사용하므로 더 효율적
- ✅ variant: 정수형 인코딩 방식. 동적 크기 할당
- ✅ len(length-delimited): 문자열 인코딩 방식. 바이트배열에 사용됨. [key] [length] [actual bytes] 구조
versions
- (권장) proto3: 문법이 단순함. 기본값 처리 방식 단순화. 여러 언어 지원.
3. 설정
구성
- .proto: gRPC 서비스와 메시지 구조를 정의하는 계약 파일
- protoc: .proto를 바탕으로 각 언어용 코드를 생성하는 컴파일러
예) proto 파일
더보기
// 서비스 정의
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 요청 메시지
message HelloRequest {
string name = 1;
}
// 응답 메시지
message HelloReply {
string message = 1;
}
Using the API
- .proto 파일에서 서비스 정의를 작성하면, protoc 컴파일러 + gRPC 플러그인이 클라이언트와 서버 코드를 자동으로 생성함
코드) gradle
더보기
protobuf {
protoc {artifact = "com.google.protobuf:protoc:${protobufVersion}"}
plugins {grpc {artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"}}
generateProtoTasks {all()*.plugins { grpc {} }}
}
publishing {
publications {
create('chatmessageV1Stubs', MavenPublication) {
from components.java
artifactId = 'protos'
}
}
repositories {
mavenLocal()
}
}
4. Core concepts, architecture and lifecycle
RPC 타입
| 방식 | 요청/응답 형태 | 특징 |
| Unary RPC | 요청 1개 → 응답 1개 | 가장 기본적인 RPC 방식 |
| Server Streaming RPC | 요청 1개 → 응답 여러 개 | 서버가 여러 응답을 스트림으로 반환함 |
| Client Streaming RPC | 요청 여러 개 → 응답 1개 | 여러 요청을 스트림으로 보내고, 최종 응답 1개를 반환함 |
| Bidirectional Streaming RPC | 요청 여러 개 ↔ 응답 여러 개 | 클라이언트와 서버가 동시에 여러 메시지를 주고받을 수 있음 ⚠️ 요청과 응답이 1:1로 같은 순서로 대응된다 보장하지 못함 |
코드) Unary RPC
더보기
RPC
rpc SayHello(HelloRequest) returns (HelloResponse);
Java
public void unaryExample(
RequestType request,
StreamObserver<ResponseType> responseObserver)
코드) Server Stream RPC
더보기
RPC
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
Java
public void serverStreamingExample(
RequestType request,
StreamObserver<ResponseType> responseObserver)
- Unary와 다르게, responseObserver.onNext()를 여러번 호출할 수 있음
코드) Client Stream RPC
더보기
RPC
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
Java
public StreamObserver<RequestType> clientStreamingExample(
StreamObserver<ResponseType> responseObserver)
코드) Bidirectional Stream RPC
더보기
RPC
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
Java
public StreamObserver<RequestType> bidirectionalStreamingExample(
StreamObserver<ResponseType> responseObserver)
Client Stub 타입
| 종류 | 호출 방식 | 지원 패턴 | 특징 | 예시 |
| Blocking Stub | 동기 | Unary, Server Streaming | 응답 올 때까지 현재 스레드가 기다림 | 가장 직관적, 단순 요청/응답 |
| Async Stub | 비동기 | Unary, Server Streaming, Client Streaming, Bidirectional Streaming | 즉시 반환, 응답은 StreamObserver/콜백으로 처리 | 실시간 처리, 고동시성, 스트리밍 |
| Future Stub | 비동기(Future) | Unary만 지원 | ListenableFuture 반환 | Unary를 비동기로 처리하고 싶을 때 |
예제) BlockingStub
더보기
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.build();
SampleServiceGrpc.SampleServiceBlockingStub stub =
SampleServiceGrpc.newBlockingStub(channel);
SampleRequest request = SampleRequest.newBuilder()
.setName("conan")
.build();
SampleResponse response = stub.createSample(request);
System.out.println(response.getId());
예제) AsyncStub
더보기
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.build();
SampleServiceGrpc.SampleServiceStub stub =
SampleServiceGrpc.newStub(channel);
SampleRequest request = SampleRequest.newBuilder()
.setName("conan")
.build();
stub.createSample(request, new StreamObserver<SampleResponse>() {
@Override
public void onNext(SampleResponse value) {
System.out.println("response id = " + value.getId());
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onCompleted() {
System.out.println("completed");
}
});
예제) BlockingStub
더보기
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.build();
SampleServiceGrpc.SampleServiceBlockingStub stub =
SampleServiceGrpc.newBlockingStub(channel);
SampleRequest request = SampleRequest.newBuilder()
.setName("conan")
.build();
SampleResponse response = stub.createSample(request);
System.out.println(response.getId());
예제) FutureStub
더보기
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.build();
SampleServiceGrpc.SampleServiceFutureStub stub =
SampleServiceGrpc.newFutureStub(channel);
SampleRequest request = SampleRequest.newBuilder()
.setName("conan")
.build();
ListenableFuture<SampleResponse> future = stub.createSample(request);
future.addListener(() -> {
try {
SampleResponse response = future.get();
System.out.println("response id = " + response.getId());
} catch (Exception e) {
e.printStackTrace();
}
}, Executors.newSingleThreadExecutor());
Channel
- RPC 호출을 위한 추상적 연결 통로 (host+port)
- ✅ Client에서 Stub을 만들 때 사용함
- ✅ 연결 재사용, name resolution, load balancing, keepalive, 메시지 압축 등
Metadata
- RPC 호출에 대한 부가 정보
- ✅ key-value 쌍의 리스트로 구성됨
- ✅ ex) 인증 토큰, trace_id, request_id, tenant 등
Deadlines
- RPC가 완료되기까지 기다릴 최대 시간을 지정할 수 있음
- ⚠️ 이 시간이 지나면 강제 종료됨
- ‼️ DEADLINE_EXCEEDED 에러 발생
출처
'Network' 카테고리의 다른 글
| [gRPC] Status Codes (0) | 2026.04.17 |
|---|---|
| [gRPC] Deadlines (0) | 2026.04.17 |
| [IBM Technology] What are DNS Zones And Records? (0) | 2025.03.29 |
| [IBM Technology] What is DNS? (0) | 2025.03.29 |