프로그래밍/gRPC

2. [gRPC] gRPC 동작 원리

코딩도치 2022. 1. 4. 03:25
반응형

안녕하세요. 코딩도치입니다~

 

오늘은 gRPC의 동작 원리에 대해서 공부해보도록 하겠습니다.

 

이번에 알아볼 것은 저수준의 gRPC 통신과 관련된 내용입니다.

 

사실 gRPC 애플리케이션 개발자는 사용되는 인코딩 기술, 네트워크에서 작동하는 방식 등의 세부적인 내부 처리를 알 필요는 없습니다.

하지만, 실 서비스 환경에서 gRPC를 사용할 때, 통신 관련 문제를 해결하려면 저수준의 gRPC 메시지 흐름을 이해하는 것이 좋습니다.

 

gRPC 클라이언트와 서버의 역할

RPC 시스템에서

서버는 클라이언트에 의해서 원격으로 호출되는 메서드의 기능을 구현하고, 클라이언트는 서버의 메서드를 호출해서 사용하게 됩니다.

이 때, 클라이언트는 원격 메서드의 추상화를 제공하는 stub이라는 객체를 통해서 메서드를 사용하게 됩니다.

 

먼저 전체적인 RPC의 흐름에 대해서 알아보겠습니다.

 

클라이언트가 원격 메서드를 호출했을 때, 수행되는 일련의 과정은 다음과 같습니다.

꽤 심플한 구성을 가지고 있습니다.

 

클라이언트에서 stub 객체의 getProduct() 메서드를 호출하면,

stub은 서버로 전송하고자 하는 데이터(메시지)를 구성하고 인코딩하여, 인코딩 메시지를 만듭니다.

 

그렇게 만들어진 인코딩 메시지에 HTTP 헤더를 추가하여 HTTP 요청을 생성하고, HTTP/2 연결 네트워크를 통해서 서버로 전송합니다.

 

(이때, gRPC의 모든 HTTP 요청은 콘텐츠 타입이 application/grcp로 시작하는 POST 요청이고, 호출하고자 하는 원격 함수 정보(getProduct)는 헤더에 담아서 전송합니다.)

 

 

서버는 HTTP 헤더에서 클라이언트가 어떤 함수를 호출할 것인지 확인하고, 메시지를 stub에 넘기게 됩니다.

 

stub은 전달받은 메시지를 디코딩하고, 실제 getProduct() 메서드를 로컬에서 수행하게 됩니다.

 

여기서 gRPC의 주요 차이점메시지를 인코딩하는 방식HTTP/2 연결을 통한 전송을 한다는 것입니다.

 

- 메시지 인코딩

 

gRPC는 메시지 인코딩을 위해서 프로토콜 버퍼를 사용하는데요.

메시지를 정의하는 방법에 따라 메시지 인코딩 방식이 결정되기 때문에, 메시지를 올바르게 작성하는 것이 중요합니다.

 

프로토콜 버퍼로 인코딩된 메시지 바이트 스트림의 구성은 다음과 같습니다.

태그는 필드 인덱스와 와이어 타입, 이 두 가지 값을 가지고 만들어집니다.

 

message Product {
  string id = 1;
  string name = 2;
  string description = 3;
  float price = 4;
}

.proto 파일에 메시지를 정의할 때 각 필드에 할당한 고유 번호가 바로 필드 인덱스입니다.

 

아래는 공식 프로토콜 버퍼 인코딩 문서에서 제공하는 와이어 타입 테이블입니다.

와이어 타입은 값의 길이를 찾기 위한 정보를 제공하는데요.

필드가 가질 수 있는 데이터 타입들(int32, stirng 등)이 Type으로 매핑되어 있는 것을 확인할 수 있습니다.

필드 인덱스의 바이너리 표현을 세 자리만큼 왼쪽으로 쉬프트하고, 와이어 타입의 바이너리 값과 비트 OR 연산을 하여 태그 값을 결정하게 됩니다.

 

다음으로 필드의 데이터 값도 인코딩이 되어야 하는데요.(위 그림에서 값에 해당)

프로토콜 버퍼는 여러 데이터 타입에 따라 다른 인코딩 기술을 사용합니다.

예를 들어, 문자열 값은 'UTF-8'을 사용해 인코딩하고, int32 값은 '가변 길이 정수'라는 인코딩 기술을 사용합니다.

 

가변 길이 정수, 부호 있는 정수, 비가변 길이 정수 숫자, 문자열 타입 등 다양한 인코딩 기술이 있습니다.

 

이렇게 데이터 타입에 따라서 인코딩 방식을 달리 하기 때문에, 메시지를 올바르게 작성하는 것이 중요한 것입니다.

 

- 네트워크 전송

 

메시지를 전송하기 전에,

상대방이 쉽게 정보를 추출할 수 있는 방식으로 데이터를 패키징 하는 메시지 프레이밍이라는 과정을 먼저 수행해야 하는데요.

 

gRPC는 '길이-접두사 지정 메시지 프레이밍'이라는 기술을 사용합니다.

'길이-접두사 지정' 방식은 메시지 자체를 전송하기 전에 각 메시지의 크기를 기록하는 프레이밍 방식입니다.

메시지의 크기는 유한하고, 메시지 크기를 나타내기 위해 4바이트를 할당하기 때문에

gRPC 통신은 최대 4GB 크기의 메시지를 처리할 수 있습니다.

 

메시지의 크기 외에도 데이터의 압축 여부를 나태내는 1바이트 부호없는 정수가 있습니다.

압축 플래그 값이 1인 경우, HTTP 메시지 인코딩 헤더에 선언된 메커니즘을 사용해 바이너리 데이터가 압축됐음을 나타냅니다.

압축 플래그 값이 0인 경우, 메시지 바이트 인코딩이 발생하지 않았음을 나타냅니다.

 

수신측에서는 메시지를 받으면 먼저 첫 번째 바이트를 읽어 메시지의 압축 여부를 확인하고,

다음 4바이트를 읽어 인코딩된 바이너리 메시지의 크기를 얻어내서, 스트림에서 정확한 바이트 길이를 읽어낼 수 있습니다.

 

- HTTP/2

 

HTTP/2는 이전 HTTP/1.1의 보안, 속도 등과 관련된 문제를 개선하고자 도입되었습니다.

HTTP/2에서 클라이언트와 서버 간의 모든 통신은 단일 TCP 연결을 통해 처리가 되고, 양방향 바이트 흐름을 전달할 수 있습니다.

 

네트워크를 통해 요청이나 응답 메시지를 보내기 위해서는 메시지와 함께 추가 헤더를 보내야합니다.

또한 스트림 종료를 알려줄 수 있는 정보(스트림 종료 플래그, 트레일러)를 전송해야합니다.

 

클라이언트 요청 메시지 -> 요청 헤더 + 길이-접두사 지정 메시지 + 스트림 종료 플래그

서버 응답 메시지 -> 응답 헤더 + 길이-접두사 지정 메시지 + 트레일러

 

클라이언트에서 gRPC 채널을 만들면 내부적으로 서버와 HTTP/2 연결을 만들게 됩니다.

이렇게 생성된 채널은 서버로 여러 원격 호출을 보낼 수 있도록 재사용됩니다.

 

HTTP/2 통신의 단위는 프레임인데요.

'길이-접두사 지정 메시지'가 하나의 데이터 프레임에 맞지 않으면, 여러 데이터 프레임으로 분리되어 전송됩니다.

 

HTTP/2 네트워크는 양방향 스트림이기 때문에 다양한 통신 패턴이 있을 수 있습니다.

각 통신 패턴마다 메시지 흐름은 다음과 같습니다.

 

단순 RPC(클라이언트 단일 요청 -> 서버 단일 응답)

서버 스트리밍 RPC(클라이언트 단일 요청 -> 서버 여러 응답)

클라이언트 스트리밍 RPC(클라이언트 여러 요청 -> 서버 단일 응답)

양방향 스트리밍 RPC(클라이언트 여러 요청 -> 서버 여러 응답)

 

마지막으로 gRPC 구현 아키텍처 레이어입니다.

(언어에 구애 받지 않는 프로토콜 버퍼를 사용하기 때문에, 언어마다 아키텍처 레이어가 약간씩 다를 수 있습니다.)

https://grpc.io/blog/grpc-stacks/

 

Visualizing gRPC Language Stacks

Here is a high level overview of the gRPC Stacks. Each of the 10 default languages supported by gRPC has multiple layers, allowing you to customize what pieces you want in your application.

grpc.io

 

위와 같이 gRPC 구현은 여러 레이어로 구성되고, 기본 레이어는 gRPC 코어 레이어(gRPC Java Core) 입니다.

gRPC 코어 레이어는 상위 레이어의 모든 네트워크 작업을 추상화하여, 개발자가 네트워크를 통해 RPC호출을 쉽게 할 수 있도록 합니다.

아울러 코어 레이어는 인증 필터, 데드라인 필터 등 핵심 기능의 확장을 제공합니다.

 

gRPC는 언어 바인딩을 제공하기 때문에, 이러한 언어 바인딩(Generated Stubs) 위에서 애플리케이션 레이어가 구현됩니다.

언어 바인딩 레이어 에서 소스코드가 생성되고, 그렇게 생성된 코드를 사용하여 애플리케이션 로직을 작성하는 것입니다.

 

네, 이렇게 gRPC의 저수준 통신에 대해서 상세히 알아봤는데요.

 

정리해보겠습니다.

 

gRPC는 프로토콜 버퍼와 HTTP/2라는 빠르고 효율적인 프로토콜 위에서 구축되었습니다.

프로토콜 버퍼는 일반 JSON 페이로드보다 크기가 작고 강력한 형식의 바이너리 페이로드를 생성하고, HTTP/2는 단일 TPC연결을 통해 데이터에 대한 여러 요청을 병렬로 보낼 수 있습니다.

그래서 gRPC 애플리케이션이 다른 애플리케이션보다 더 빠르고 단순하며 견고할 수 있는 것입니다.

 

다음에는 이어서, 간단한 예제를 통해 직접 gRPC를 사용해보도록 하겠습니다. 

 

감사합니다.

 

참고자료

gRPC 시작에서 운영까지 - http://www.yes24.com/Product/Goods/94489227

 

gRPC 시작에서 운영까지 - YES24

클라우드 및 마이크로서비스 아키텍처의 출현으로 오늘날 애플리케이션은 프로세스간 통신 기술을 사용해 연결되며, gRPC는 가장 널리 사용되는 효율적인 통신 기술 중 하나이다. 이 책은 gRPC를

www.yes24.com

 

반응형

'프로그래밍 > gRPC' 카테고리의 다른 글

1. [gRPC] gRPC 소개  (4) 2021.12.31