gRPC란
Java/Spring Boot 개발자 입장에서 처음 gRPC를 접하면 다음과 같은 의문이 생긴다.
- REST API와 무엇이 다른가?
- DTO는 어떻게 정의하는가?
- Front-End에서 직접 호출할 수 있는가?
- 실무에서 언제 사용하는가?
본 글에서는 gRPC의 개념과 REST와의 차이점, 그리고 실제 활용 방안을 정리해본다.
REST vs gRPC
REST
Spring Boot에서는 일반적으로 다음과 같이 API를 구현한다.
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public UserResponse getUser(@PathVariable Long id) {
return new UserResponse(id, "Walter");
}
}
요청
GET /users/1
응답
{
"id": 1,
"name": "Walter"
}
REST는 HTTP와 JSON을 기반으로 동작하며, 사람이 읽고 디버깅하기 쉽다.
gRPC
gRPC는 Google이 개발한 RPC(Remote Procedure Call) 프레임워크이다. REST가 URL과 JSON 중심이라면, gRPC는 함수 호출 중심이다.
userService.getUser(1L);
REST와 비슷한 형태로 원격 서비스를 호출한다.
Proto 파일이란?
gRPC의 핵심은 .proto 파일이다.
예를 들어:
syntax = "proto3";
package user;
service UserService {
rpc GetUser(UserRequest)
returns (UserResponse);
}
message UserRequest {
int64 id = 1;
}
message UserResponse {
int64 id = 1;
string name = 2;
}
이 파일은 다음 세 가지 역할을 동시에 수행한다.
- API 인터페이스 정의
- Request/Response DTO 정의
- 직렬화 규칙 정의
즉, Proto는 OpenAPI + DTO + Interface 를 합쳐놓은 개념으로 이해할 수 있다.
Proto → Java 코드 생성
Proto를 작성한 뒤 protoc 컴파일러를 실행하면 Java 코드가 자동 생성된다.
user.proto
↓
protoc
↓
generated/
├─ UserRequest.java
├─ UserResponse.java
├─ UserServiceGrpc.java
Spring Boot에서 gRPC 구현
생성된 클래스를 이용하여 서비스를 구현한다.
@GrpcService
public class UserGrpcService
extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(UserRequest request, StreamObserver<UserResponse> responseObserver) {
UserResponse response =
UserResponse.newBuilder()
.setId(request.getId())
.setName("Walter")
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
여기서 사용하는
- UserRequest
- UserResponse
- UserServiceGrpc
는 모두 Proto에서 자동 생성된 코드이다.
DTO는 Proto가 대신한다
REST에서는 DTO를 직접 작성한다.
public record UserResponse(
Long id,
String name
) { }
gRPC에서는 DTO를 직접 작성하지 않는다.
message UserResponse {
int64 id = 1;
string name = 2;
}
이 정의만 작성하면 Java DTO가 자동 생성된다.
즉,
REST
↓
DTO 직접 작성
gRPC
↓
Proto 작성
↓
DTO 자동 생성
이런 구조이다.
REST와 gRPC의 성능 차이
REST는 JSON을 사용한다.
{
"id": 1,
"name": "Walter"
}
gRPC는 Protobuf 바이너리를 사용한다.
08 01 12 06 57 61 6c 74 65 72
결과적으로
- Payload 크기 감소
- 직렬화 비용 감소
- 네트워크 비용 감소
효과를 얻을 수 있다.
HTTP/2 기반
gRPC는 HTTP/2를 사용한다.
REST(HTTP/1.1)
Request
Response
Request
Response
gRPC(HTTP/2)
Request1
Request2
Request3
Response1
Response2
Response3
동일 Connection에서 Multiplexing이 가능하다. 서비스 간 호출이 많은 환경에서는 큰 장점이 된다.
Streaming 지원
REST는 일반적으로 Request/Response 구조이다.
Client
↓
Request
30초 대기
Response
gRPC는 Streaming을 지원한다.
Client
↓
Token1
Token2
Token3
Token4
대표적인 활용 사례
- AI 모델 추론
- 실시간 로그
- 실시간 모니터링
- 채팅 시스템
Front-End에서 gRPC 호출 가능할까?
가능은 하다고 한다. 하지만 일반 브라우저는 순수 gRPC를 직접 지원하지 않는다. 따라서 보통 다음 구조가 필요하다.
Browser
↓
gRPC-Web
↓
Envoy
↓
gRPC Server
JavaScript 예시
const request = new UserRequest();
request.setId(1);
client.getUser(request, {}, (err, response) => {
console.log(response.getName());
});
실무에서 많이 쓸 것 같지는 않다.
실무에서 가장 적용해 볼 만한 구조
대부분 다음 구조를 사용한다.
Frontend
↓ REST
API Gateway / BFF
↓ gRPC
User Service
Order Service
Payment Service
AI Service
즉
- 외부 인터페이스 → REST
- 내부 서비스 간 통신 → gRPC
패턴이 가장 일반적이다.
Spring Boot 개발자 관점에서의 체감 차이
비즈니스 로직 관점에서는 REST와 gRPC의 차이가 크지 않다.
REST
@GetMapping
public UserResponse getUser(...)
gRPC
@Override
public void getUser(...)
정도의 차이다. 실제로 개발자가 구현하는 Service, Facade, Repository 계층은 거의 동일하다.
언제 gRPC를 선택해야 할까?
gRPC가 적합한 경우
- 내부 마이크로서비스 간 통신
- 고빈도 호출
- 저지연 요구사항
- AI 모델 서빙
- 다국어(Java, Go, Python) 환경
- Streaming 필요
REST가 적합한 경우
- Frontend 연동
- 외부 업체 연동
- 공개 API
- 단순 CRUD
- 디버깅 편의성 우선
결론
gRPC는 REST를 대체하기 위한 기술이라기보다는, REST가 잘 해결하지 못하는 내부 서비스 간 고성능 통신 문제를 해결하기 위한 기술이라고 볼 수 있다. 다음과 같이 정리할 수 있다.
Frontend
↓ REST
API Gateway / BFF
↓ gRPC
Internal Services
즉,
REST는 외부 인터페이스, gRPC는 내부 서비스 간 통신
이라는 역할 분담이 현재 가장 널리 사용되는 아키텍처 패턴이다.
Spring Boot 개발자 입장에서 gRPC는 생각보다 어렵지 않다.
Controller가 gRPC Service로 바뀌고, DTO 대신 Proto를 사용한다고 이해하면 대부분의 개념을 빠르게 습득할 수 있다.