본문 바로가기

Data Engineering/Micro Service

[gRPC] Go코드와 함께하는 gRPC

1. 관련 개념


Static Linking: 정적 링킹

 

프로그래밍 언어가 컴파일링 과정 중에 코드가 기계어 (OBJ) 파일로 변환되고, 링킹 과정에서 사용하는 라이브러리를 합쳐 같이 실행 파일을 만드는 과정.

 

따라서 실행 파일에 코드와 라이브러리가 모두 합쳐져 있어 용량이 크다.

 

출처: https://medium.com/@abhishekjainindore24/static-library-vs-dynamic-library-understanding-the-differences-26e47cac93b6

 


Dynamic linking: 동적 링킹.

실행 파일안에 라이브러리 코드가 복사되는 것이 아니라, 메모리 공간에 올라가서 필요할 때 실행 파일이 여러 프로그램이 공유하여 사용하는 방식.

 

실행 파일 안에 소스 코드만 존재하고, 동적 라이브러리는 따로 존재하여 실행 파일 자체의 크기가 작다. 실행 시에도 한번에 모든 동적 라이브러리를 메모리에 로드하지 않고, 필요할 때 메모리에 로드하니 상대적으로 적은 메모리를 사용한다.

 

단, 호환성 문제가 있을 수 있고, 동적 라이브러리(윈도우즈는 .dll, Unix에서는 .so 파일)가 반드시 필요하다.

출처: 위 그림과 동일. Linker 아래를 보면 메모리 주소를 이용하여 런타임에 그 함수를 부른다.

 


RPC(Remote Procedure Call): 원격 프로시저 호출

자신 혹은 다른 컴퓨터의 환경에 존재하는 procedure(함수라고 생각하면 편하다)를 불러 사용한다. 원격 환경과의 통신을 위하여 RPC 프로토콜을 사용한다. stub으로 원격 환경의 procedure를 local이라고 착각하게끔 만들고, 이를 지원하는 IDL(Interface Definition Language)로 데이터를 주고 받는 형식을 작성하여 명명한다. 즉, stub을 통하여 서로 다른 환경의 컴퓨터가 통신을 할 수 있도록 통일해준다는 것이다.

 

Dynamic Linking의 원리와 비슷하지만, RPC는 분산 네트워크 환경의 호스트의 메모리 주소를 사용한다는 차이가 있다.


gRPC(Remote Procedure Call)

HTTP/2 기반에서 작동하고, IDL이 프로토콜 버퍼(.protobuf)이다.

스트리밍을 지원하며, JSON이 아닌 protobuf 형식의 Request와 Response를 받는다.

때문에 binary serialization이 가능하여 HTTP/1.1의 JSON보다 더욱 작은 페이로드를 구현할 수 있다.

 

프로토콜 버퍼 IDL을 지원하는 프로그래밍 언어는 바이너리 형태의 페이로드이기에 OS와 관계없이 모두 호환 가능하다.

단, 바이너리 페이로드이기에 디버깅이 어려울 수 있다.

 

요청을 gRPC로 전송할 때, deadline을 설정하여 서버의 스케쥴링을 도울 수 있다. 

 

출처: https://grpc.io/docs/what-is-grpc/introduction/

 

Protocol Buffer: 프로토콜 버퍼의 특징

프로토콜 버퍼는 특수한 binary encoding 방식이 있는데, 이로 인하여 바이너리 형태로 데이터를 주고 받고, 데이터를 압축하여 전송할 수 있기에 OS와 상관없이 빠른 송수신이 가능한 것이다.

 

출처: https://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html

 

또한 프로토콜 버퍼와 프로그래밍 언어를 호환시키는 코드(이게 stub)는 직접 작성할 필요없이 자동 생성(auto generation)을 할 수 있기에 실수가 발생하지 않는다.

 

그러니 하나의 .proto 파일을 서버와 클라이언트에게 공유하면 각각 stub을 자동 생성할 수 있다.


JSON vs Protocol Buffer

 

JSON

Protocol Buffer

데이터 형식 숫자도 문자열로 변환. 텍스트 형식(key와 ", 줄바꿈 등 다양한 추가 형식 포함) 숫자는 이진 비트로, 문자열은 맨 앞에 길이를 나타내는 varint와 추가적인 string으로 나타남.
구조적인 오버헤드 key와 value를 반복 저장. key의 중복. 필드 번호만으로 데이터 식별.
파싱 속도 문자열 파싱 및 타입 추론이 필요(모두 바이트로 인코딩되기 때문). 이진 데이터이기에 바로 메모리에 매핑할 수 있어 파싱 과정이라는 게 없음.
타입 안정성 런타임에 각 값의 타입을 확인하고 변환. 스키마가 미리 정의되어 있어 타입 검사 불필요.

 

 

위와 같은 이유로 네트워크 대역폭 사용량이 JSON에 비해 매우 줄어들기에 마이크로서비스 간 통신에 매우 적합하다.

 


다양한 사용 사례:

빠르고, 스트리밍을 지원하며, 네트워크 대역폭 사용량이 줄어들기에 사용 사례가 다양하다.

 

1. 마이크로서비스 환경

2. 실시간 스트리밍 환경

3. Polyglot 환경

4. 네트워크 속도 제한 환경

4. IPC(Inter-process Communication)를 gRPC로 구현

...


2. Go 코드로 알아보는 gRPC


.proto 파일을 기반으로 자동 생성을 하기 때문에 그 자동 생성을 위한 패키지를 설치해야 한다.

 

apt install -y protobuf-compiler

go install google.golang.org/protobuf/cmd/protoc-gen-go 

 

 

 

proto 파일을 작성해야 한다.

 

syntax = "proto3";

package video;
option go_package = "github.com/ket0825/grpc-streaming/proto";

service VideoGatewayService {
    rpc StreamVideo(VideoRequest) returns (stream VideoChunk);
}

message VideoRequest {
    string video_id = 1;
}

message VideoChunk {
    bytes data = 1;
    int32 chunk_size = 2;
}

 

지금 만드는 것은 Video가 처음으로 들어오는 Gateway 서버이기에 위와 같이 작성하였다.

 

그리고 디렉토리 "proto"를 만들고, 아래 커맨드를 이용하여 stub과 go로 만든 데이터 형식 파일을 만들어주자.

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./api/proto/streaming.proto

 

참고로 proto 파일 기준 --go_out과 --grpc_out을 설정하는 것이다.

 

...

 

아래 코드 주소를 확인하면 최종적으로는 Client와 게이트웨이 서버, 인코딩 서버로 구성하여 gRPC 서버를 완성할 수 있다.

미완성된 부분이 많지만(지속적인 데이터 다운로드 오류 등), 시간이 난다면 더 완성시킬 수 있을 것이다.

코드 주소: https://github.com/ket0825/grpc-streaming

'Data Engineering > Micro Service' 카테고리의 다른 글

[MSA] terraform으로 GKE Autopilot 배포하기  (4) 2025.01.04