본문 바로가기
Go

[gRPC] gRPC의 등장배경과 gRPC 이전의 통신

by yongckim 2021. 12. 22.
728x90
반응형

마이크로서비스 아키텍처와 클라우드 네이티브 아키텍처의 출현으로 기능이 세분화되고 의존성이 낮은 마이크로서비스로 분리되었습니다.

여러개의 마이크로서비스로 분리되면서 각각의 프로세스(서비스)들은 어떠한 통신기술(RESTful, IPC 등등..)을 사용해 네트워크로 통신을하게 되었습니다. 

 

예를 들어 위와 같이 온라인 판매 시스템을 마이크로서비스 아키텍처 기반으로 구현한다면 각각의 웹 UI, 상품 검색, 주문 관리, 결제, 배송 관리 같은 서비스들이 네트워크 상으로 연결되어 데이터를 주고 받게 되었습니다.

그래서 프로세스 간 통신을 하면서 네트워크의 트래픽이 많아지게 되어 효율적인 통신 방식이 중요한 부분으로 떠오르게 되었습니다.

프로세스 간 통신(IPC)

프로세스간의 서로 데이터를 주고받는 방법을 IPC(Inter-Process Communication)라고 부릅니다.

다양한 IPC가 존재하지만 클라이언트 - 서버 구조에서 사용되는 방법들을 위주로 알아보겠습니다.

Socket

소켓은 통신의 양 끝점을 의미하며, 두 프로세스가 네트워크 상에서 통신을 하려면 양 프로세스가 하나씩 총 두개의 소켓을 필요로합니다.

각 소켓은 IP주소와 포트 번호 두가지를 결합해서 구별합니다.

일반적으로 소켓은 클라이언트 - 서버 구조를 사용하며 서버는 지정된 포트에 클라이언트 요청 메시지가 도착하기를 기다리고 있다가 요청이 수신되면 서버는 클라이언트 소켓으로부터 연결 요청을 수락하여 클라이언트와 서버가 연결됩니다.

소켓을 이용한 통신은 분산된 프로세스 간에 널리 사용되고 효율적이지만 스레드간의 구조화되지 않은 바이트 스트림만을 통신하기에 바이트 스트림 데이터를 구조화하여 해석하는 것과 클라이언트와 서버에 연결과 같은 부분을 직접 구현해야 하기 때문에 구현에 어려움이 있다는 단점이 있습니다.

 

원격 프로시저 호출(Remote Procedure Calls, RPC)

RPC란 네트워크로 연결된 서버의 프로시저(함수, 메서드 등)를 원격으로 호출하는 기능입니다.

RPC를 사용하면 클라이언트 - 서버 간의 통신을 위한 연결 부분을 직접 구현하지 않고 원격의 서버에 프로시저를 호출할 수 있습니다.

RPC는 IDL(Interface Definition Language)를 사용하여 클라이언트와 서버간의 호출 규약을 정의하며, Stub을 통해 프로시저 호출에 사용되는 매개변수를 변환합니다.

Stub을 통해 매개변수 변환을 하기 때문에 원격 서버의 프로시저의 호출을 할 때 원격 서버에서 로컬 함수를 호출하는 것처럼 사용할 수 있습니다.

클라이언트 Stub은 함수 호출에 사용된 매개변수의 매개변수의 변환(Mashalling)과 함수 실행 후 서버에서 전달된 결과의 역변환(Unmahshalling)을 담당합니다.

클라이언트 Stub에 대응되는 서버 측의 Stub인 Skeleton은 클라이언트가 전달한 매개변수의 역변환과 함수 실행 후 결과의 변환을 담당합니다.

이제 RPC가 어떻게 통신하는지 알아봅시다.

  1. 클라이언트는 매개변수를 클라이언트 Stub에 전달합니다.
  2. 클라이언트 Stub에서 매개변수를 변환(Mashalling)합니다.
  3. RPC 클라이언트 런타임 라이브러리 함수를 호출하여 서버에 변환한 매개변수와 함께 요청합니다.
  4. 서버 RPC 런타임 라이브러리 함수는 요청을 수락하고 서버 Stub 프로시저(Skeleton)를 호출합니다.
  5. 서버 Stub은 네트워크 버퍼에서 매개변수를 검색하여 네트워크 전송 형식에서 서버에 필요한 형식으로 변환합니다.
  6. 서버 Stub은 서버에서 실제 프로시저를 호출합니다.

위의 과정이 이뤄지면 원격 프로시저가 실행되어 출력 매개 변수 및 반환 값을 생성할 수 있습니다. 그리고 서버에서 다시 클라이언트로 값을 반환해주기 위해 다음 과정을 진행합니다.

  1. 원격 프로시저는 해당 데이터를 서버 Stub에 반환합니다.
  2. 서버 Stub은 네트워크를 통해 전송하는 데 필요한 형식으로 출력 매개 변수를 변환하고 RPC 런타임 라이브러리 함수로 반환합니다.
  3. 서버 RPC 런타임 라이브러리 함수는 네트워크의 데이터를 클라이언트 컴퓨터로 전송합니다.
  4. 클라이언트 RPC 런타임 라이브러리는 원격 프로시저 반환 값을 받아 클라이언트 스텁에 반환합니다.
  5. 클라이언트 Stub을 해당 데이터를 클라이언트 컴퓨터에서 사용하는 형식으로 역변환 합니다.
  6. 클라이언트 Stub은 클라이언트 메모리에 데이터를 기록하고 결과를 클라이언트의 호출 프로그램에 반환합니다.

RPC는 원격의 서버를 로컬환경처럼 사용하고 IDL 기반의 뛰어난 확장성, 분산 프로그래밍 환경을 구현하는데 유용하다는 점 등 많은 장점이 있지만 여전히 구현하는데 많은 어려움이 발생했습니다.

 

REST(Representaional State Transfer)

REST는 분산된 애플리케이션을 리소스 모음으로 모델링하는 자원 지향 아키텍처기반이며, 자원에 액세스하는 클라이언트가 해당 자원의 상태(생성, 읽기, 업데이트 또는 삭제)를 변경할 수 있습니다.

여기서 자원들은 보통 HTML이나 JSON같은 파일들을 의미합니다. 

REST는 웹 애플리케이션을 고유한 식별자(URL)로 액세스할 수 있는 리소스 모음으로 모델링합니다. 클라이언트는 HTTP 메서드(GET, POST, DELETE 등..)를 이용해 서버에 원하는 작업을 요청합니다.

REST는 HTTP를 이용하여 통신하기 때문에 이전에 알아보았던 방법보다 클라이언트 - 서버간의 통신이 쉽다는 장점이 있습니다.

HTTP와 JSON을 이용한 RESTful(REST 방식의 웹 서비스를 의미합니다.) 애플리케이션 구축은 마이크로서비스를 구축할 때 많이 사용되었지만 마이크로서비스가 많아지고 이들 간의 트래픽 증가로 RESTful 서비스는 여러 문제점을 드러냈습니다.

 

먼저, 텍스트 기반 메시지 프로토콜이 비효율적이라는 점입니다.

본질적으로 RESTful 서비스는 HTTP 1.x와 같은 텍스트 기반 전송 프로토콜로 구축됩니다.

서비스간에 통신을 할 경우 JSON 처럼 사람이 읽을 수 있는 텍스트 기반 포맷을 사용할 필요가 없기 때문에 JSON과 같은 텍스트 포맷을 사용하는 것은 비효율적입니다.

RESTful 서비스간에 통신하는 과정을 알아봅시다.

클라이언트 애플리케이션은 서버로 전송할 바이너리 콘텐츠를 만든 후에 해당 바이너리 구조체를 텍스트로 변환(HTTP 1.x는 텍스트 기반 메시지를 전송해야 함)한 후 네트워크를 통해 텍스트를 전송(HTTP)하고 서버측에서 다시 바이너리 구조로 변환합니다.

위처럼 바이너리->텍스트->바이너리로 데이터를 변환하는 과정을 거치는것보다는 바로 바이너리 형태로 보내는 것이 더 효율적일 것입니다.

 

두번째로, 엄격한 타입 점검이 부족합니다.

폴리글랏 기술로 구축돼 네트워크를 통해 제공되는 서비스가 점점 증가함에 따라 명확하고 엄격하게 점검되는 서비스 정의가 더 중요해졌습니다.

기존 RESTful 서비스에서 사용되는 OpenAPI/Swagger와 같은 대부분 서비스 정의 기술은 근간의 아키텍처 스타일이나 메시징 프로토콜에 처음부터 고려되지 않아 이와 잘 통합되지 않습니다.

이는 분산 애플리케이션 구축에 많은 비호환성, 런타임 에러, 상호호환성 이슈 등의 문제를 야기합니다.

예를 들면, RESTful 서비스를 개발할 때는 서비스 정의나 애플리케이션 사이에 공유되는 정보의 타입 정의가 따로 요구되진 않습니다.

오히려 서비스되는 텍스트 포맷을 확인하거나 OpenAPI와 같은 서드파티 API 정의 기술을 사용하게 됩니다. 결국 최신의 엄격한 타입 서비스 정의 기술과 폴리글랏용 서버 및 클라이언트 측 중요 코드를 생성하는 프레임워크의 필요성이 증대됩니다.

 

마지막으로, REST 아키텍처 스타일 강제의 어려움이 있습니다.

아키텍처 스타일로서 REST는 실제 서비스 구축에 도움이 되는 좋은 사례들을 많이 가지고 있습니다. 하지만 HTTP와 같은 구현 프로토콜의 일부로 통합되지 않아 구현 단계에서 REST 규칙을 적용하는 것이 쉽지 않습니다. 결국 대부분의 RESTful 서비스는 실질적으로 REST 스타일의 기본 규칙을 준수하지 않는 경우가 많아 단순 HTTP 서비스로 제공되는 경우가 많습니다.

결국 RESTful 서비스의 일관성관 규칙을 유지하는데 개발 팀에 많은 노력과 시간을 소비하게 됩니다.

 

이와 같은 문제점으로 다양한 메시지 프로토콜들이 등장하게 되었습니다.

 

반응형