gRPC는
HTTP/2
를 기반으로 고성능의 네트워크 구현을 가능하게 한다.
소켓(socket) 프로그래밍
클라이언트-서버 모델이 처음 등장할 무렵, 소켓(socket) 프로그래밍을 통해 클라이언트는 서버에 자료를 요청하고 받았다. 물론 지금도 서버에서 푸시를 주거나 채팅 서버를 운영할 때 서버를 이용하곤 한다.
소켓에는 다음과 같은 전제가 존재한다.
- 네트워크는 언제나 빠르고 장애가 없다.
- 서버는 클라이언트가 요청하면 언제든 즉시 응답한다.
- 클라이언트는 언제든 서버와 바로 연결한다.
이런 전제 조건들이 갖춰지지 않으면, 소켓 방식은 제대로 작동하지 않는다. 하지만 현실에서는 얼마든지 네트워크나 서버, 클라이언트가 느려질 수 있고 문제가 발생할 수 있다. 따라서 소켓 프로그래밍을 할 때는 발생 가능한 모든 예외 상황들을 미리 예측하고 대비하여 구현해야 하는 문제가 존재한다.
다른 컴퓨터의 프로그램의 프로시저를 실행하는 프로그램을 허용하는 프로토콜
소켓 프로그래밍의 한계를 극복하기 위해 나온 개념이 RPC(Remote Procedure Call)
이다. RPC에서는 이름이 나타내는 바와 같이 원격 호출 규약을 바탕으로 통신이 진행된다. IDL(Interface Definition Language)를 활용해 원격으로 메소드나 함수를 호출할 수 있다. 네트워크 통신과 관련된 작업을 신경쓰지 않고 원격지에 위치한 프로그램을 로컬에 있는 프로그램처럼 사용할 수 있다. RPC는 성능이 최우선인 환경에서 여전히 사용 중이다. 그러나 REST에 비해 그 구현이 매우 복잡하고 개발 속도가 더디다.
개발자가 원격 상호 작용에 대한 세부 정보를 명시적으로 코딩하지 않아도 되고 프레임워크가 자동으로 핸들링한다. 클라이언트 코드에서는 직접 서버 코드의 함수를 호출하는 것처럼 보이며 클라이언트의 코드 언어와 서버 코드 언어가 다른 언어로 쓰일 수 있다.
로컬/원격을 포함한 프로그램 객체 간의 메소드 호출 표준화를 위해 OMG에서 정의한 규격으로 다양한 언어를 지원한다. RPC와 같이 원격 프로그램을 로컬에 있는 것처럼 사용할 수 있다. COBRA 역시 디자인 및 제작이 너무 어렵고 비동기 메시지 구현이 불가능한 등의 문제점으로 인해 일반적으로 사용되지는 않는다.
서로 다른 JVM 간의 메소드 호출을 지원한다. RPC와 같이 원격 프로그램을 로컬에 있는 것처럼 사용할 수 있다. RMI는 Java만 지원한다. 네트워크 처리 시간이 다소 느리고 사이즈가 크거나 복잡한 객체가 전달될 경우 오버헤드가 크다.
SOAP에서는 HTTP와 XML을 함께 사용한다. 서버는 서비스 사용법(WSDL)을 작성해 서비스 목록(UDDI)으로 전송한다. 클라이언트는 UDDI를 통해 목록을 LookUp하고 SOAP 형태의 메세지로 서버에 요청을 한다. SOAP 역시 복잡성이 단점이다. SOAP 헤더, 바디, Fault 등의 envelope 방법과 보안 및 트랜잭션은 이해하기도 쉽지 않고 복잡하다. 또, REST에 비해 무거우며 개발하기도 어렵다.
REST는 HTTP/1.1을 사용하며 URI를 자원(Resource)으로 표현하는 방식이다. URI는 동사가 아닌 명사 형태로 표현되며 GET
, POST
, PUT
, DELETE
의 메소드를 통해 CRUD가 진행된다.
기존에는 HTTP 처리 결과를 제공할 때 Status Code는 200으로 실제 처리 결과는 Body에 작성했다. REST에서는 처리결과를 헤더의 Status Code를 활용해 표현한다.
기존 프레임워크에 비해 REST가 갖는 장점은 직관성
과 단순성
이다. REST는 누구나 쉽게 이해 가능하고 개발이 빠르다. URI는 자원 그 자체를 표현하고 HTTP 메소드를 활용해 그 자원을 접근하므로 URI가 단순하고 일관된다. 서버와 클라이언트가 완전히 분리되어 결합도가 매우 낮다. 독립적인 개발이 가능하여 원하는 서비스를 다양한 플랫폼을 통해 쉽고 빠르게 배포할 수 있다. 특정 메소드의 세부적인 표현문구를 JSON, XML 등 다양한 언어를 이용하여 작성할 수 있고 간결한 헤더 표현으로 가독성이 향상된다.
다만 HTTP 메소드만을 이용하기에 메소드 형태가 제한적이다. 또 표준이 부재하여 공식적인 API 가이드라인이 존재하지 않는다. 나아가 JSON이나 XML 형태로 통신하기 때문에 비효율적이고 데이터 낭비가 존재한다.
예를 들어 MSA에서 서버1과 서버2는 자바로 구성되어 있다고 가정해보자 서버1과 서버2가 REST API로 서로에게 접근한다면 한쪽에서는 데이터를 JSON으로 만들고 다른 한쪽에서는 JSON 데이터를 받아 그것을 파싱하는데 이는 상당한 비효율을 야기한다.
또, JSON의 특성상 string 형태로 존재하고 key/value 값 형태이기 때문에 불필요한 데이터 낭비를 야기한다.
2,000,000,000개
구글이 일주일동안 띄우는 컨테이너의 수이다.
10,000,000,000개
구글이 1초 동안 던지는 원격 호출의 수이다.
그래서 gRPC가 탄생했다.
gRPC는 간결하고 고성능인 오픈소스(BSD License) 기반 RPC 프레임워크이다. 과거 구글에서는 Stubby라는 RPC 프레임워크를 사용해 문제를 해결했다. 이것을 개선하고 HTTP/2 기반의 오픈소스 프레임워크로 등장시킨 것이 바로 gRPC이다.
1. Protocol Buffer
gRPC는 커뮤니케이션 프로토콜과 데이터 스토리지 등에서 Protocol Buffer를 사용해 데이터를 교환한다 Protocol Buffer는 프로그래밍 언어와 플랫폼에 독립적이며 구조화된 데이터를 직렬화 하는 방식으로 사용된다. XML과 유사한 기능을 수행하지만 작고, 단순하고 빠르다.
2. 4가지 스트리밍 방식
Unary
: 일반적인 클라이언트/서버 통신과 같이 1회에 리퀘스트에 1회의 리스폰스가 이루어지는 구조서버 스트리밍
: 클라이언트는 1회 요청하며 서버에서 지속적으로 응답하는 구조클라이언트 스트리밍
: 클라이언트에서 지속적으로 요청하며 서버가 1회 응답하는 구조양방향 스트리밍
: 클라이언트와 서버가 지속적으로 데이터를 주고받는 구조
3. 3가지 Stub
Blocking Stub
: 동기적으로 작동하는 Stub이다.(Async) Stub
: 비동기적으로 작동하는 Stub이다.
4가지 스트리밍 방식을 지원하는 유일한 Stub이다.Future Stub
1. 가볍다.
gRPC는 Protocol Buffer라는 Binary Protocol을 사용한다. 네트워크 및 메모리 효율성이 좋다. Serialize/Deserialize 부하가 Text/JSON 대비 더 낮아 CPU 효율성이 좋다.
2. HTTP/2를 사용한다.
헤더 컴프레션이 가능하여 네트워크 효율성이 개선되고, Connection Multiplexing, 클라이언트/서버 간 양방향 스트리밍 등이 가능하여 활용 가능한 분야가 다양하다.
3. 압도적 성능
gRPC의 초당 처리량이 HTTP/1.1 JSON 대비 무려 3배에 이른다. CPU 사용률을 고려시 실질적인 성능 차이는 11배에 이른다.
4. 다양한 언어 지원
Proto 파일 하나로 10가지 언어로 자동 작성된다. Polyglot 서비스, 즉 여러 언어로 작성된 클라이언트/서버가 동시에 존재하는 상황에 최적화되어 있다.
5. JSON/XML 등 지원
JSON/XML도 지원한다. 물론 성능 향상 효과는 적어질 것이다.
6. 자동 생성
Proto 파일을 통해 자동생성 되는 부분이 많아 기존 RPC에 비해 단순하다.
1. 브라우저에서 사용하기 곤란하다.
Proxy를 이용해 사용할 수는 있으나 복잡하며 현실적으로 서버 간 모바일 네이티브 앱과 서버 간 통신에만 국한되어 사용한다.
2. 클라이언트 쪽 업데이트 사항 발생시 부담이 된다.
3. Binary Data이기에 사람이 읽을 수 없다.
4. Rest 보다는 복잡하다.
- 브라우저가 필요 없는 백엔드 서버 간 통신
- 자원이 빈약한 디바이스와 서버 간 통신
- 바이트/호출횟수/CPU 수 등으로 과금되는 클라우드 환경에서의 비용 절감
1. 클라이언트는 stub 생성 (서버랑 같은 메소드 제공)
2. stub는 gRPC 프레임워크를 호출 (내부 네트워크를 통해서 호출)
3. 클라이언트와 서버는 서로 상호작용을 위해 stubs 사용, 서로의 코어 서비스 로직의 권한만 필요