Post

gRPC란?

gRPC(Google Remote Procedure Call)는 구글에서 개발된 고성능 RPC 프레임워크이다. HTTP/2에서 동작하며 양방향 스트리밍 및 흐름 제어를 제공한다.
gRPC는 원격으로 호출할 수 있는 메서드를 지정하여 서비스를 정의하는 개념이 기반이며 protobuf(IDL로 사용)를 기본 메시지 형식으로 사용한다.

IDL : Interface Definition Language

protobuf를 사용하여 더 효율적인 직렬화가 가능하고, Type을 명시적으로 체크할 수 있다.

gRPC의 특징

  • 언어 독립성 : gRPC는 다양한 언어를 지원하여 서버와 클라이언트간 언어가 달라도 상호작용이 가능하다.
  • 양방향 스트리밍 : HTTP/2를 기반으로 하여 클라이언트와 서버간에 양방향 스트리밍을 지원한다.
  • 강력한 Type 체크 : 메시지의 형식을 프로토콜 버퍼로 정의 시 gRPC는 타입 체크를 제공한다.
  • 높은 성능 : gRPC는 HTTP/2와 프로토콜 버퍼를 활용하여 높은 성능을 제공한다.
  • Google API 연동 : Google API에는 인터페이스의 gRPC 버전이 제공되므로 애플리케이션에 Google 기능을 쉽게 빌드할 수 있다.

gRPC에서는 클라이언트 애플리케이션이 로컬 객체처럼 외부 서버 애플리케이션의 메서드를 직접 호출할 수 있기 때문에 분산 app과 서비스를 더 만들기 쉽다.
많은 RPC 시스템에서와 마찬가지로 gRPC는 서비스를 정의하고 매개변수와 반환 유형으로 원격으로 호출할 수 있는 메서드를 지정한다.

서버 측에서는 서버가 이 인터페이스를 구현하고 클라이언트 호출을 위해 gRPC서버를 실행한다.
클라이언트 측에서는 클라이언트가 서버와 동일한 메서드를 제공하는 stub을 가지고 있다.

예를 들어, 만약 서버에서 SayHello라는 메서드를 제공하면 클라이언트는 서버와 연결한 뒤 conn.GetUser 호출을 통해 서버가 제공하는 SayHello 메서드를 실행할 수 있다.
이에 대한 명세는 .proto라는 파일을 생성하여 정의한 뒤 protobuf로 빌드하면 생성할 수 있다.


protobuf

protobuf는 구글에서 개발한 언어와 플랫폼에 상관없이 데이터 직렬화를 가능하게 하는 데이터 구조다. 서로 다른 서비스끼리 데이터를 공유/저장하기 위해 사용된다.
protobuf는 XML, JSON과 같이 잘 알려진 데이터 형식보다 더 효율적인 방식으로 데이터를 관리하기 때문에 전송/저장 시 데이터를 더 적게 사용할 수 있다.

protocol buffer로 작업하기 위해서는 우선 데이터의 구조를 정의해야 한다.
확장자가 .proto인 일반 텍스트 파일을 통해서 정의할 수 있으며 protocol buffer 데이터는 메시지로 구조화되고, 각 메시지는 필드라고 하는 일련의 name-value 쌍을 포함한다.

.proto의 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
syntax = "proto3";

option go_package = "grpc/helloworld";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

위와 같이 .proto 파일을 생성한 뒤 버퍼 컴파일러인 protoc를 사용해서 사용하는 언어에 맞는 코드를 생성할 수 있다.


gRPC의 4가지 서비스 정의 방법

  1. 클라이언트가 서버에 단일 요청을 보내고 일반 함수 호출 마찬가지도 단일 응답을 받는 단항 RPC
    1
    
    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  2. 클라이언트가 서버에 요청을 보내고 일련의 메시지를 읽을 수 있는 스트림을 다시 받을 수 있는 서버 스트리밍 RPC
    1
    
    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse); 
    
  3. 클라이언트가 일련의 메시지를 작성하고 제공된 스트림을 사용하여 다시 서버로 보내는 클라이언트 스트리밍 RPC
    1
    
    rpc LotsOfReplies(stram HelloRequest) returns (HelloRequest);
    
  4. 클라이언트-서버 양방향 스트리밍 RPC
    1
    
    rpc LotsOfReplies(stream HelloRequest) returns (stream HelloResponse);
    

환경 구성(Mac M1 기준)

  1. protoc 설치
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

  2. .proto 컴파일
    1
    
    protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto
    
  3. 모듈화 컴파일하여 생성된 pb.go를 프로젝트에서 불러올 수 있도록 모듈화한다.
    내 기준으론 gRPC 프로젝트에 helloworld라는 디렉토리를 담았으므로 .proto의 go package는 gRPC/helloworld 였다. 이 경우 gRPC 프로젝트에 모듈을 생성하면 불러올 수 있다.
    1
    2
    
     go mod init gRPC
     go mod tidy
    
  4. 결과

    protobuffer를 읽어왔으므로 클라이언트에서 서버의 함수와 데이터를 통신으로 사용할 수 있다.

  • 트러블 슈팅
    1
    2
    3
    4
    
      protoc-gen-go: program not found or is not executable
      Please specify a program using absolute path or make sure the program  
      is available in your PATH system variable
      --go_out: protoc-gen-go: Plugin failed with status code 1.
    

    protoc를 못 읽어 오는 것이므로 PATH를 지정해준다.

    1
    2
    3
    
      vi ~/.zshrc
      export PATH=$PATH:$(go env GOPATH)/bin
      source ~./zshrc // 변경사항 적용
    

채팅

gRPC를 이용하여 서버와 클라이언트의 간단한 채팅을 만들어보았다.

  • Server
  • Client

https://github.com/MunProoo/gRPC/tree/master

This post is licensed under CC BY 4.0 by the author.