RPC 통신과 gRPC

2025. 1. 12. 12:18·gRPC

 

 

 

gRPC 시작에서 운영까지 | 카순 인드라시리 - 교보문고

gRPC 시작에서 운영까지 | 클라우드 및 마이크로서비스 아키텍처의 출현으로 오늘날 애플리케이션은 프로세스간 통신 기술을 사용해 연결되며, gRPC는 가장 널리 사용되는 효율적인 통신 기술 중

product.kyobobook.co.kr

위 책의 내용과 별도로 공부한 내용들을 정리하고자 작성한 글입니다.

 

 

IPC

프로세스들은 기본적으로 상호독립적이다.

메모리를 공유하지 않기 때문에 각자 자신의 일만 수행하며 서로 간섭을 하지 않는다.

그러나 필요에 따라서 프로세스 간 정보를 교환해야 하는데,

별도의 수단을 통해서 프로세스 간 통신을 하는 방법론을 통칭하여 IPC(Inter Process Communication)라고 한다.

 

 

 

RPC

위와 같은 프로세스 간 통신(IPC)의 방법론 중에 하나인 RPC는 Remote Procedure Call의 약자로,

네트워크를 통해 다른 컴퓨터에서 실행되는 프로시저나 함수를 호출할 수 있는 기술이다.

즉, RPC는 클라이언트가 네트워크를 통해 원격 서버에서 함수나 메서드를 호출하는 방식으로

마치 클라이언트가 로컬에서 함수를 호출하는 것처럼, 원격 서버에서 정의된 함수를 호출할 수 있다.

 

RPC에서 IDL

 

우선적으로 RPC 통신을 하기 위해서는 서비스 인터페이스를 정의 해야한다.

원격으로 호출되는 메서드 종류, 해당 메서드를 호출하기 위한 파라미터, 메시지 형식 등을 포함하는데,

이와 같은 서비스 정의에 사용되는 언어를 인터페이스 정의 언어(IDL, Interface Definition Language)라고 한다.

 

뒤에서 설명하고자 하는 gRPC의 경우,

Protocol Buffers를 IDL로 사용해 서비스 인터페이스를 정의하게 된다.

이 프로토콜 버퍼는 언어에 구애받지 않고 플랫폼 중립적이며 확장 가능한 메커니즘으로 구조화된 데이터를 직렬화하고자 사용된다.

 

 

 

gRPC

등장 배경

프로세스 간 통신은 보통 동기적 스타일과 비동기적 방식의 스타일로 구성된다.

클라우드 네이티브 애플리케이션이나 마이크로서비스용 동기적 스타일의 통신을 구축할 때에는

주로 RESTful 서비스로 구성하는데, 많은 경우 RESTful 서비스는 프로세스 간 통신을 구축할 때 부피가 크고 비효율적이며 에러가 쉽게 발생되기 때문에 좀 더 효율적이고 확장성이 높으며 느슨하게 결합되는 프로세스 간 통신 기술이 종종 요구된다.

gRPC는 주로 통신에 동기식 스타일을 사용하지만, 초기 통신이 설정되면 완전 비동기식이거나 스트리밍 모드에서 작동할 수 있다.

 

 

gRPC란

gRPC는 google 사에서 개발한 오픈소스 RPC(Remote Procedure Call) 프레임워크이다.

이전까지는 RPC 기능은 지원하지 않고, 메세지(JSON 등)를 Serialize할 수 있는 프레임워크인 Protocol Buffer 만을 제공해왔는데,

Protocol Buffer 기반 Serializer에 HTTP/2를 결합하여 RPC 프레임워크를 탄생시키게 된다.

 

즉, gRPC는 분산 애플리케이션이나 마이크로서비스 구축을 위해 사용되는 고성능 RPC를 기반으로 하는

최신 프로세스 간 통신 스타일로, 마이크로서비스와 클라우드 네이티브 애플리케이션의 출현으로 gRPC 채택이 증가하고 있다.

 

위에서 간략히 말한 것처럼 gRPC는 Protocol Buffers를 IDL로 사용해 서비스 인터페이스를 정의한다.

서비스 인터페이스 정의는 proto 파일에 표현되며, Protocol Buffer 메시지로 RPC 메서드 파라미터 및 반환 타입과 함께 gRPC 서비스를 일반 Protocol Buffer 형식으로 정의한다.

 

다음과 같이 프로토콜 버퍼를 사용하여 서비스를 정의할 수 있다.

//  ProductInfo.proto

syntax = "proto3";
package productInfo;
option go_package = "/productInfo";

// 1
service ProductInfo {
    rpc addProduct(Product) returns (ProductID);
    rpc getProduct(ProductID) returns (Product);
}

// 2
message Product {
    int64 id = 1;
    string name = 2;
    string description = 3;
}

message ProductID {
    int64 value = 1;
}

 

위 코드에서 주석 1번과 같이 gRPC 서비스의 서비스 인터페이스를 정의하고, 

2번과 같은 방식으로 메시지 형식/타입을 정의할 수 있다.

또한 다른 프로젝트와의 이름 충돌을 방지할 수 있는 패키지 이름을 지정할 수 있는데,

패키지와 함께 서비스 정의를 사용해 서비스나 클라이언트 코드를 생성할 때 동일한 패키지는 각각의 프로그래밍 언어 형식으로 작성된다.

 

그리고 각 메시지는 필드라는 이름의 이름-값을 포함하는 작은 논리적 레코드며,

메시지 바이너리 형식에서 필드를 식별하기 위한 고유 필드 번호를 갖는다.

  • id = 1, name = 1, description = 1;  ---> X
  • id = 1, name = 2, description = 3; ---> O

 

서비스 정의가 완료되면, Protocol Buffer Compiler인 protoc를 사용하여

서버 측(서버 스켈레톤)이나 클라이언트 측(클라이언트 스텁) 코드를 생성할 수 있다.

프로토콜 버퍼용 gRPC 플러그인을 사용하면 gRPC 서버 측과 클라이언트 측 코드뿐만 아니라 정의된 메시지 타입의 데이터 지정, 직렬화, 데이터 취득의 일반 프로토콜 버퍼 코드도 생성할 수 있다.

 

예시로

MacOS에서 Go 언어를 사용한다면, 아래와 같은 절차와 함께 프로토콜 버퍼 컴파일러용 플러그인을 설치하게 된다.

https://grpc.io/docs/languages/go/quickstart/

brew install protobuf
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
export PATH="$PATH:$(go env GOPATH)/bin"

 

이후에 아래와 같은 명령어를 통해서 protoc를 사용한다면

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    {경로}/ProductInfo.proto

 

다음과 같이 두 개의 파일들이 재생성되는데, 

위에서 말한 것처럼 서버 측이나 클라이언트 측 코드뿐만 아니라 프로토콜 버퍼 코드가 생성된다.

  • {경로}/ProductInfo.pb.go -> Protocol Buffers 메시지와 데이터 구조가 정의됨
  • {경로}/ProductInfo_grpc.pb.go -> gRPC 클라이언트와 서버 인터페이스가 정의됨

 

이후 gRPC 서버 측에서는 작성한 서비스 정의를 구현한다.

그리고 gRPC 서버를 실행해 클라이언트에서의 요청을 수신하고 해당 요청을 서비스 구현으로 지정(dispatch)한 다음, 서비스 결과를 다시 클라이언트로 반환하게 된다.

 

클라이언트-서버 메시지 흐름

gRPC 클라이언트가 gRPC 서비스를 호출할 때 클라이언트의 gRPC 라이브러리는 프로토콜 버퍼를 사용해 원격 프로시저 호출 프로토콜 버퍼 형식으로 마샬링(marshaling)하고, HTTP/2를 통해 전송된다.

서버 측에서는 요청을 언마샬링(unmarshaling)하고 각 프로시저 호출은 프로토콜 버퍼에 의해 실행한다.

응답도 클라이언트에서 서버와의 요청과 유사한 흐름을 갖는다.

마샬링(marshaling)은 파라미터와 원격 함수를 네트워크상에 전송되는 메시지 패킷으로 패킹하는 프로세스
언마샬링(unmarshaling)은 메시지 패킷을 각 메서드 호출로 다시 복원(unpack) 하는 것이다.

 

 

 

장점

프로세스 간 통신 효율성

gRPC는 JSON이나 XML과 같은 텍스트 형식을 사용하는 대신 프로토콜 버퍼 기반 바이너리 프로토콜을 사용해 gRPC 서비스 및 클라이언트와 통신한다.

또한 HTTP/2 위에 프로토콜 버퍼로 구현되기에 프로세스 간 통신 속도가 매우 빨라지며, 가장 효율적인 프로세스 간 통신 기술 중 하나가 된다.

 

엄격한 타입 점검 형식

gRPC 서비스 정의는 애플리케이션 간 통신에 사용할 데이터 타입을 명확하게 정의한다.

정적 타이핑은 여러 팀과 기술에 걸친 클라우드 네이티브 애플리케이션을 구축할 때 발생할 수 있는 대부분의 런타임과 상호운용 에러를 극복하는 데 도움이 되므로 분산 애플리케이션 개발이 훨씬 안정적으로 이루어진다.

 

양방향 스트리밍

gRPC는 클라이언트나 서버 측 스트리밍을 기본적으로 지원하며 서비스 정의 자체에 포함되기 때문에 스트리밍 서비스나 스트리밍 클라이언트를 훨씬 쉽게 개발할 수 있다. 아울러 기존의 요청-응답 스타일 메시징 방식이나 클라이언트 및 서버 측 스트리밍을 구축하는 기능은 기존 RESTful 메시징 스타일에 비해 주요 장점이 된다.

 

언어 독립성

gRPC는 다양한 언어를 지원한다. 클라이언트와 서버가 서로 다른 언어로 작성되어 있어도 상호 작용이 가능하다.

https://github.com/protocolbuffers/protobuf/blob/main/docs/third_party.md

 

 

단점

서비스 정의의 급격한 변경에 따른 개발 프로세스 복잡성

gRPC 서비스 정의가 급격히 변경되면 일반적으로 클라이언트와 서버 코드 모두 다시 생성해야 한다.

이는 기존의 지속적인 통합(CI) 프로세스에 통합돼야 하며, 전체 개발 수명 주기를 복잡하게 할 수 있다.

그러나 대부분의 gRPC 서비스 정의 변경은 서비스 계약을 위반하지 않게 수용될 수 있고,

gRPC는 주요 변경 사항이 없는 한, 다른 버전의 proto를 사용해 클라이언트 및 서버와 문제없이 상호운용할 수 있다.

즉, 대부분의 경우 코드 재생성은 필요하지 않다.

 

외부 서비스 부적합

인터넷을 통해 애플리케이션이나 서비스를 외부 클라이언트에 제공하려는 경우, 대부분의 외부 사용자는 gRPC가 새롭기 때문에 적합하지 않을 수 있다. 계약 기반(contact-driven)이면서 강력한 타입 속성을 갖는 gRPC 서비스는, 외부 당사에게 노출되는 서비스의 유연성을 방해할 수 있으며, 외부 사용자는 훨씬 적은 제어권을 갖는다.

이러한 문제에 대한 해결책으로 gRPC gateway가 존재한다고 한다.

 

상대적으로 작은 생태계

gRPC 생태계는 여전히 기존 REST나 HTTP 프로토콜에 비해 상대적으로 작다.

브라우저와 모바일 애플리케이션에서 gRPC의 지원도 여전히 초기 단계다.

 

 

 

REST vs gRPC

REST는 HTTP/1.1 기반으로 URI를 통해 모든 자원(Resource)을 명시하고 HTTP Method를 통해 처리하는 자원 지향 아키텍쳐이다. 

자원 그 자체를 표현하기에 직관적이고, HTTP를 그대로 계승하였기에 별도 작업 없이도 쉽게 사용할 수 있다는 장점으로 현대에 매우 보편화되어있다.

그러나 마이크로서비스가 많아지고 이들 간의 네트워크 상호작용이 확산되면서, 아래와 같은 몇 가지 주요 제한 사항이 존재한다.

 

비효율적 텍스트 기반 메시지 프로토콜

RESTful 서비스는 HTTP 1.x와 같은 텍스트 기반 전송 프로토콜로 구축되며 JSON처럼 사람이 읽을 수 있는 텍스트 포맷을 활용한다.

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

반면에 gRPC의 경우 JSON도 지원은 하지만 기본적으로 Protocol Buffer 기반 바이너리 프로토콜을 사용하여 통신하므로

Call 하는 부분에 대해서 담기는 사이즈가 JSON에 비해 압도적으로 작다.

또한 HTTP/2 위에 프로토콜 버퍼로 구현되기에 프로세스 간 통신 속도가 매우 빠르다.

HTTP/1.1은 기본적으로 클라이언트의 요청이 들어올 때만 서버가 응답을 하는 구조로, 매 요청마다 connection을 생성해야 한다.
cookie 등 많은 메타 정보들을 저장하는 무거운 header가 요청마다 중복 전달되어 비효율적이고 느린 속도를 보여주게 된다.

HTTP/2에서는 한 connection으로 동시에 여러 개의 메시지를 주고 받으며, header를 압축하여 중복 제거 후 전달하기에
version 1에 비해 훨씬 더 효율적이다. 또한 필요 시 클라이언트 요청 없이도 서버가 리소스를 전달할 수도 있기 때문에 클라이언트 요청을 최소화할 수 있다.

HTTP/1.1 vs HTTP/2

 

엄격한 타입 점검의 부족

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

오히려 서비스되는 텍스트 포맷을 확인하거나 OpenAPI와 같은 서드파티 API 정의 기술을 활용한다.

결국 최신의 엄격한 타입 서비스 정의 기술과 polyglot용 서버 및 클라이언트 측 중요 코드를 생성하는 프레임워크의 필요성이 증대된다.

polyglot: 기술 분야에서는 요구 사항이나 시스템 성격에 맞는 다양한 언어를 사용해 개발하는 것을 뜻함

 

 

REST 아키텍처 스타일 강제의 어려움

아키텍처 스타일로서 REST는 실제 서비스 구축에 도움이 되는 좋은 사례를 많이 갖고 있다.

그러나 HTTP와 같은 구현 프로토콜 일부로 통합되지 않아 구현 단계에서 REST 규칙을 적용하는 것이 쉽진 않다.

결국 대부분 RESTful 서비스는 실질적으로 REST 스타일의 기본 규칙을 준수하지 않는 경우가 많아 단순 HTTP 서비스로 제공되는 경우가 많다. 이는 RESTful 서비스의 일관성과 규칙을 유지하는 데 개발 팀의 많은 시간을 소비하게 된다.

 

 

  REST gRPC
프로토콜 HTTP/1.x HTTP/2
데이터 형식 JSON or XML (텍스트 형식, 가독성 높음, 용량 큼 Protobuf (이진 형식, 고속, 용량 절약)
성능 텍스트 기반 직렬화로 느리고 네트워크 대역폭 소모 높음 이진 데이터로 직렬화하여 빠르고 네트워크 효율적
통신 모델 요청-응답 모델 (단방향) 양방향 스트리밍 및 멀티플렉싱 지원
개발 생산성 직관적인 설계, Swagger/OpenAPI 같은 문서화 도구와 쉽게 통합 .proto 파일로 API 정의, 다양한 언어 지원 (자동 코드 생성)
확장성 REST API 설계의 유연성과 단순함으로 다양한 시스템에 쉽게 확장 가능 네트워크 효율성이 뛰어나고, 대규모 분산 시스템에 적합

 

 

 

 

기타

배민의 WoowaBoot

배민 개발 팀에서는 가게 탐색 -> 주문 전환 과정에서 특정 시기에 트래픽이 급격하게 증가하였고,

모놀리식 형태로 마이크로서비스 형태의 여러개의 서비스로 분리하는 과정에서

공통적으로 사용되는 코드를 각각의 서비스에서 어떻게 사용할지에 대한 고민이 존재했습니다.

 

lib 방식, REST API 방식을 고민하다가

데이터를 얻기 위한 각각의 client code를 구현하거나 데이터 일관성 같은 문제들을 해결할 수 있는 RPC 방식을 선택하게 됩니다.

 

그러나 개발자들이 RPC에 익숙하지 않은 상태라는 우려되는 요소와,

RPC 구현체(gRPC, Thrift)에 맞추어 800개가 넘는 IDL을 작성하기 쉽지 않아

 

Java의 클래스, 인터페이스를 통한 추상화를 활용하여 Woowaboot인 자체적인 RPC 모듈을 만들게 된 내용이 인상적이였습니다.

 

LINE의 Armeria

Armeria를 gRPC 앞단에 Wrapper 형태로 적용하면 Service Discovery, Load Balancing, Health Check, Circuit Breaker, Actuator 등의 클라이언트와 서버의 통신 구조에서 필요한 여러 가지 기능들을 쉽게 적용할 수 있다고 이해했습니다.

 

이러한 기능들을 Armeria의 Decorator를 사용하면 요청/응답 흐름에 대해 로깅, 모니터링 등의 기능을 쉽게 추가할 수 있었습니다.

gRPC만 사용하는 경우에는 이러한 부가 기능들을 직접 구현하거나 라이브러리를 사용해야 하는 번거로움이 있지만, Armeria를 통해서 손쉽게 설정할 수 있어 보였습니다.

CircuitBreaker cb = CircuitBreaker.builder("infcon-cb")
                                .failureRateThreshold(0.5f)
                                .minimumRequestThreshold(5)
                                .build();
                                
CircuitBreakerRule cbRule = CircuitBreakerRule.builder()
          .onException()
          .onGrpcTrailers((ctx, trailers) -> trailers.getInt("grpc-status", -1) != 0)
          .thenFailure();
                      
var stub = GrapcClients
		.builder("http", healthCheckedGroup)
        .decorator(CircuitBreakerClient.newDecorator(cb, cbRule))
        .build(InfconServiceBlockingStub.class);

 

결국 gRPC도 HTTP 프로토콜 위에서 동작하는 프로세스 간 통신 방식이므로 REST 방식에서 발생하던 여러 네트워크 쪽 문제들에 대한 에러 핸들링을 위해서 여러 가지 기능들을 제공하는 것 같습니다.

 

 

 

 

 

참고

 

Introduction to gRPC

An introduction to gRPC and protocol buffers.

grpc.io

 

RPC와 REST 비교 - API 아키텍처 간의 차이점 - AWS

원격 프로시저 호출(RPC)과 REST는 모두 인터넷 통신을 위해 해당하는 클라이언트와 서버 시스템 인터페이스를 설계하는 방법입니다. 그러나 구조, 구현 및 기본 원칙은 다릅니다. REST를 사용하여

aws.amazon.com

 

gRPC와 REST 비교 - 애플리케이션 설계의 차이 - AWS

REST는 소프트웨어 구성 요소 간 데이터 교환을 위한 일련의 규칙을 정의하는 소프트웨어 아키텍처 접근 방식입니다. REST는 웹의 표준 통신 프로토콜인 HTTP를 기반으로 합니다. RESTful API는 생성,

aws.amazon.com

 

[네이버클라우드 기술&경험] 시대의 흐름, gRPC 깊게 파고들기 #1

안녕하세요, 네이버 클라우드 플랫폼입니다. 이번 시간을 포함해 총 2회차에 걸쳐 gRPC에 대해서 집중 ...

blog.naver.com

 

gRPC란? 그리고 golang에서 사용하기

 

devocean.sk.com

 

REST에서 gRPC로: 차세대 API 통신 방식 도입기

[kt cloud 플랫폼Innovation팀 강솔 님]   REST에서 gRPC로: 차세대 API 통신 방식 도입기 내부 서비스 간 효율적인 통신 체계 구측을 위하여 gRPC를 새롭게 도입하게 되었습니다.이번 테크블로그를 통해

tech.ktcloud.com

 

 

 

 

 

 

'gRPC' 카테고리의 다른 글

Protocol Buffer와 인코딩/디코딩 그리고 gRPC 내부 통신 동작 원리  (0) 2025.04.07
gRPC 통신 구현해보기 (서버 : Java / 클라이언트 : Go)  (0) 2025.01.23
'gRPC' 카테고리의 다른 글
  • Protocol Buffer와 인코딩/디코딩 그리고 gRPC 내부 통신 동작 원리
  • gRPC 통신 구현해보기 (서버 : Java / 클라이언트 : Go)
개발이조아용
개발이조아용
IT 개발에서 배운 성장의 기록을 작성합니다.
  • 개발이조아용
    계속 하다 보면?!
    개발이조아용
  • 전체
    오늘
    어제
    • 분류 전체보기 (67)
      • Tibero DB (Tmax AI Bigdata .. (7)
      • Git (2)
      • CI CD (2)
      • Redis (3)
      • SpringBoot (16)
      • SQL 문제 풀이 (8)
      • Apache Kafka (8)
        • 오류 해결 (3)
        • 개념 정리 (4)
        • 보안 (1)
      • Nginx (3)
      • SW마에스트로 (3)
      • Kubernetes (4)
      • AWS (5)
      • gRPC (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    redis
    SQL
    Git
    Redis 개념
    nginx
    Kafka 개념
    SASL 인증
    Tibero
    grpc
    SpringBoot
    DynamoDB 연동
    소프트웨어 마에스트로
    leetcode
    Kafka 오류
    sql 문제
    K8S
    Kafka SASL
    MSA
    redis script
    KAFKA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
개발이조아용
RPC 통신과 gRPC
상단으로

티스토리툴바