gRPC 이전, 통신기술들은 과연 어떻게 발전하였을까?
PC 나 워크스테이션같은 소형 컴퓨터에대한 개념이 없던시절, 프로그램은 하나의 메인프레임에서 동작하는 모놀리식 구조로 설계되었다. 즉, 모든기능이 한 단말에서 구동되었기에, 네트워크 통신이 그리 중요하지 않았다
하지만, PC나 워크스테이션 같은 소형컴퓨터가 등장하자, 이러한 메인 프레임에서 구동되던 모놀리식 구조의 프로그램을 워크스테이션 서버로 이전하고자 하였다. 하지만 기존의 거대한 모놀리식 구조의 프로그램을 비교적 저사양인 워크스테이션 서버가 감당하긴 힘들었고, 이에 프로그램을 여러 모듈로 분할하여 여러 워크스테이션 서버에 분산시켜 동작하도록 하였다.
또한, 분산된 각 서버를 네트워크 연결로 서비스하였는데, 이것이 바로 Server-Client 모델이다.
이처럼, Server to Server, Server to PC 네트워크 연결/통신 이 중요해지면서 OSI 7계층
이나 각종 네트워크 프로토콜
등, 네트워크 관련 구조나 규약이 정의되고 발전하기 시작한다.
프로세스는 기본적으로 상호독립적으로 가동된다. 즉,
메모리를 공유하지 않고,
각자 자신의 일만 하며
서로 간섭하지 않는다.
하지만 필요에 따라 이러한 프로세스간의 정보교환이 이루어져야할 때가 있는데 이러한 프로세스간의 정보교환 통신에 관련한 방법론을 IPC 라고 한다.
IPC 의 종류로는 Socket
, RPC
, REST
, 파이프
등이 있다.
TCP/IP Socket
Socket 자체는 그저 추상화된 개념이다. 여기서 다루는 내용은 TCP/IP 소켓에 대한 설명이다
어플리케이션 계층에서 전송계층 내의 TCP, UDP 를 이용하여 통신하기위한 수단으로, 통신에 대한 접속점(창구) 역할을 하는 통로이다.
네트워크간 통신
에 속하지만,IPC
에도 속한다.소켓은 대부분의 언어에서 API 형태로 제공하는 기술이기때문에 현재까지도 많이 사용되고있다.
하지만 이러한 소켓에도 아래와 같은 한계가 존재한다.
통신관련 장애를 핸들링
하는것 또한 개발자가 구현해야한다.data formatting
또한 어려워진다.RPC
소켓의 한계를 극복하기 위해 개발된 기술로, 이번 아티클의 주제인 gRPC 또한 RPC 에 속한다.
Remote Procedure Call 즉, 네트워크로 연결된 서버상의 프로시저를 원격으로 호출할 수 있는 기술이다. 네트워크 통신이나 호출작업에 신경쓰지 않고, 원격지의 자원을 로컬자원처럼 활용할 수 있다.
언어 중립적 인터페이스인 IDL(Interface Definication Language) 에 기반한 기술이므로, 다양한 기술스택(언어)를 사용하는 환경에서도 쉽게 확장할 수 있다.
C++
, Java
, Python
, Ruby
, Node.js
, C#
, Go
, PHP
등 많은 major 한 언어들에서 지원하는 기술이다.
RPC 에는 Stub 이라는 핵심개념이 존재하는데, 서버에 저장되어있는 자원의 주소와 클라이언트에 저장되어있는 자원의 주소가 다를 수 있으므로, 함수 호출에 사용한 매개변수를 변환해야한다.
그러지 않으면 메모리 매개변수에 대한 포인터가 다른 데이터를 가리킬 가능성이 높다.
이러한 매개변수의 변환을 담당하는것이 Stub 이다.
Stub 은 client stub
과 server stub
으로 나뉜다.
마샬링
(함수호출에 사용되는 파라미터의 변환) 과 함수 실행 후 서버에서 전달된 결과의 변환을 담당한다.언마샬링
(클라이언트가 전달한 매개변수의 역변환) 및 함수 실행 결과의 변환을 담당한다.stub 을 통한 기본적인 RPC 통신과정
IDL 을 사용하여 호출규약을 정의한다
함수명
, 인자
, 반환값
에대한 데이터형이 정의된 IDL 파일을 rpcgen 으로 컴파일하여 Stub Code를 생성한다.
StubCode 에 명시된 프로시저는 원시코드(컴파일 이전의 코드)의 형태로 작성되며,
상세기능은 server 에서 구현된다. (StubCode 는 클라이언트/서버에 함께 빌드한다)
client 에서 stub 에 정의된 프로시저(함수 등)를 사용한다.
client stub 이 RPC runtime 을 통해 프로시저를 호출한다.
server 에 수신된 프로시저 호출에 대한 로직을 처리하고, 결과값을 반환한다.
최종적으로 Client 는 Server 의 결과값을 반환받아, 원격지(Server) 에 존재하는 함수를 Local 에 있는 함수처럼 사용할 수 있다.
이러한 RPC 는 그당시 상당히 획기적인 방법론이었고, 분산환경과 함께 꾸준히 발전해온 기술이다.
따라서 구현체 또한 SOAP
, CORBA
등 여러가지가 존재한다.
하지만, 구현난이도가 높고, 지원기능에 한계가 있어 제대로 활용되지 못하였는데,
이때 WEB 을 활용해 데이터 통신을 해보려는 시도가 이어졌고 이는 REST 아키텍처 스타일로 발전하며, 기존 RPC 의 자리를 차지하게 된다.
REST
HTTP 1.1 기반의 정보 교환 아키텍처 스타일이다.
URI
를 통해 모든 자원을 명시하고HTTP Method
를 통해 자원에 관한 여러 Operation 을 처리하는 아키텍처이다.자원자체를 표현하기때문에 직관적이며, HTTP 자체의 여러 개념을 사용하여 별도의 작업 없이도 쉽게 도입/사용이 가능하다.
또한 WEB 을 통한 데이터 전달 format 으로 xml 이나 json 을 주로사용하였는데, 이 또한 여러 문제가 존재하였다.
XML
은 tag 기반의 데이터 형식이나, 미리 정의된 태그가 없어, 높은 확장성을 가지지만,JSON
은 이러한 효율성을 간단한 Key - Value 구조를 통해 해결하는듯 하였지만,REST 아키텍처스타일의 한계가 드러나던 와중 나온 구글의 오픈소스 RPC 프레임워크
기존에는 RPC 기능을 지원하지 않고, 전술한 JSON 같은 데이터형식의 메세지를 직렬화하는 Protocol Buffer 만을 제공하는 프레임워크였으나, Protocol Buffer 기반의 Serializer
에 HTTP 2.0
을 결합한 새로운 RPC 프레임워크로 변모하였다.
REST 와는 기반 기술 자체가 다르기때문에 특징 또한 매우 다르다.
그중 가장 두드러지는 차이점은
HTTP 2.0
을 사용한다는것과프로토콜 버퍼
로 데이터를 전달한다는 것이다. 이러한 gRPC 의 특성 덕분에, Proto File 만 배포한다면 환경과 프로그램 언어에 구애받지 않고 서로간의 데이터 통신이 가능하다.
REST 아키텍처 스타일에서 사용하는 HTTP 1.1 과는 달리, HTTP 2.0은 Header 의 압축
과 ServerPush
같은 여러 기술들을 통해 클라이언트의 요청을 최소화 하였다.`
google 에서 개발한 구조화된 데이터를 직렬화하는 기법이다.
이때 직렬화란 데이터 표현을 바이트단위로 변환하는 작업을 의미하는데, 아래 예제처럼
Protocol Buffer 에서 사용하는 데이터 타입에 대한 정의 같은 Protocol Buffer 의 기본 정보를 명세한다.
Message & Field
ProtoFile 에서는 주고받는 data 를 message 로 정의한다. 또한 이 message 는 여러가지 타입의 field 로 구성된다.
required : 해당 필드는 필수로 가져야한다 (proto2 에서만 사용가능)
optional : 해당 필드를 가지지 않거나 하나만 가진다 (proto2 에서만 사용 가능)
repeated : 해당 필드는 임의로반복할 수 있다.필드번호,반복된값의 순서는보존된다. (=배열)
[package=true] : 모든 필드는 key-value 로 저장되기떄문에 repeated 를 사용할 경우, 모든 반복값에 key 가 붙게된다 이때, 해당 옵션을 사용하여 value 만 반복하도록 할 수 있다
proto2 의 경우 required 와 optional 을 필드별로 무조건 명시해주어야한다.
Package
message type 이름을 중첩없이 구분할 때 사용한다 package 를 명시하여 동명의 필드와 명확히 구분할 수 있다.
package 미사용시
package 사용시
Service
RPC 를 통해 서버가 클라이언트에 제공할 함수의 형태를 정의한다.