gRPC가 왜 나왔을까
MSA한테 REST API는 한계가 있었다
REST는 JSON과 XML 기반의 데이터 직렬화를 토대로 가장 대중화된 통신 방법이다. 그런데 이런 텍스트 데이터의 직렬화는 성능과 데이터 크기 면에서, 특히나 대규모 서비스의 실시간 스트리밍이나 양방향 통신에는 적합하지 않은 비효율적 구조를 갖고 있다.
더불어 근래의 대규모 분산 시스템와 MSA 아키텍처 확산으로 효율적인 서비스 간 통신 방신이 요구되어 오는데, 다양한 언어로 작성되었을 MSA가 서로 통신할 수 있는 다중 언어 지원 및 타입 안전성도 요구되어왔다.
이에 대해 Google은 한 발 빨랐다. Google은 이미 갖춰진 대규모 분산 시스템에서 효율적인 통신을 위해 Stubby라는 RPC프레임워크를 썼는데, 이게 꽤 성공적이어서 오픈소스화하였고 다양한 언어와 프로토콜을 지원하는 gRPC를 개발하여 공개했다.
gRPC가 가능하게 하는 여러 통신방식들
그렇다면 이 gRPC가 어떤 일을 할 수 있느냐, 통신 측면에서 보면 아래와 같이 일대일~ 다대다까지 다양하게 가능하다.
- Unary: REST와 유사하게 클라이언트가 하나의 요청을 보내고 서버가 하나의 응답을 반환할 수 있다
- Server Streaming: 서버가 여러 응답을 스트리밍으로 전송할 수 있다
- Client Streaming: 클라이언트가 데이터를 스트리밍으로 보내고 서버가 하나의 응답을 반환할 수 있다
- Bidrentional Streaming: 클라이언트와 서버가 양방향 스트리밍으로 데이터를 주고 받을 수 있다
이는 gRPC가 REST의 HTTP/1.1 기반과 달리 HTTP/2를 사용하여 멀티플렉싱을 통해 한 개의 TCP 연결에서 여러 요청/응답을 동시 처리하게 할 수 있게 되었기 때문이다. 이러한 특징을 잘 쓰고자 한다면 MSA, 실시간데이터스트리밍(채팅이라든지), 다중언어환경의 시스템에서 적용해볼 수 있다.
gRPC의 기본 개념들
Remote Procedure Call (RPC)
Process는 자신이 갖고 있는 함수만 호출하여 실행할 수 있는 게 일반적이다. 그런데 RPC의 경우, 네트워크를 통한 메시징을 수행시킴으로써 본인뿐만 아니라 다른 주소공간의 프로세스의 함수도 실행하는 매직을 실현한다. 이는 클라이언트가 서버의 메서드를 네트워크를 통해 호출하는 방식이다. 마치 로컬 함수처럼 보이는데, 실제로는 네트워크를 통해 데이터를 전송하여 서버에서 처리된다.
Protocal Bufferes (Protobuf)
Protobuf라고 하여 데이터 직렬화를 위한 Google 포맷이 존재한다. 앞서 말한 텍스트 형식의 JSON/XML에 비해 빠르고 가볍고, .proto 파일로 데이터와 서비스를 정의하여 서버와 클라이언트에서 사용될 코드로 컴파일된다. 이 포멧 덕분에 강력한 타입 안정성이 제공되기도 하고 효율적인 통신에 기여하는 주요 요소가 된다.
gRPC 동작과정
우선 사전에 .proto 파일을 보자. 클라이언트와 서버 간의 인터페이스를 정의하는 파일이며 아래와 같은 형태다.
service MyService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
이제 Protocol Bufferes 컴파일러(protoc)가 서버와 클라이언트 코드를 자동으로 생성할 예정이다.
그럼 생성된 코드를 기반으로 서버는 서비스 메서드를 구현하고, 클라이언트는 Stub을 통해 메서드를 호출한다.
여기서 stub은 클라이언트가 메서드를 호출하기 위한 Proxy 객체로 데이터의 역직렬화/직렬화 동작을 수행한다. 이에 대해 그림으로 그려보면 아래와 같다.
찬찬히 보면 아래와 같다.
1. Client
클라이언트가 RPC를 통해 원격 서버의 메소드를 호출하고자 한다.
2. Client-Stub
Sub가 Client의 요청을 직렬화하고, 직렬화된 데이터를 요청(Requast) 형태로 만들어 RPC Protocol에 전달해준다.
3. Client-RPC Protocol
직렬화된 데이터를 네트워크를 통해 서버의 Stub으로 전송시킨다.
4. Server-RPC Protocol
수신받은 직렬화 데이터가 Stub으로 전달된다
5. Server-Stub
직렬화 데이터를 역질렬화하며 서버 메서드가 사용할 수 있는 형태로 변환하고, 서버측의 실제 메소드 (sayHello)를 호출한다
그리고 응답은 또 순서대로 진행되는 형태다.
이처럼 마치 택배 시스템으로 생각하면, Client stub은 클라이언트가 보낼 택배를 포장(직렬화)해서 택배 회사에 전달을 했고, 택배 회사로부터 받은 응답(결과)를 개봉(역직렬화)에서 클라이언트한테 제공하는 모습으로 이해할 수 있다.
쩡리
gRPC는 단순히 REST를 대체하는 기술로 보기보다, 새로운 통신 패러다임을 제공하여 효율성을 극대화할 수 있는 상향 선택지라고 여길 수 있다. 특히 제일 초반에 말한 것과 같이 대규모 MSA 환경, 실시간 데이터 스트리밍, 다중 언어 환경에서 그 진가가 발휘된다.
# Reference