grpc.logo.png

 

gRPC는 Google에서 다년간 내부적으로 사용해 온 쉽고 효율적인 RPC (Remote Procedure Call) 입니다. 이번 글에서는 gRPC 를 소개하고, gRPC 로 간단한 API를 설계하고, 쉽게 서버로 만들어 사용해 보겠습니다.

RPC (Remote Procedure Call) 라는 개념은 상당히 역사가 오래된 개념이죠. 간단히 말하자면, 내 컴퓨터가 아닌 다른 컴퓨터의 자원을 사용하여 원하는 결과를 얻기 위한 방식입니다.

 RPC.concepts.png

RPC 역사에 대한 내용은 그냥 다음 그림 한장으로 생략하고, 재밌는(?) gRPC 사용법에 대해서만 적어보도록 해요.

rpc.history.pnggRPC 사용법은 간단히 3단계로 적어볼 수 있습니다. 

  • 프로토콜 설계
  • 컴파일
  • 실행

적어 놓고 나니 너무 단순하네요. 하나씩 짚어 나가 보죠.

 

1. 프로토콜 설계 

두 컴퓨터가 어떤 형식으로 메세지를 주고 받을지 정의하는 과정입니다. 가령, 공공 도서관의 도서 정보를 제공하는 API를 설계한다고 해요. 도서에 해당하는 정보에는 책의 제목, 저자, 종류, 보유 수량, 가격, 바코드 등의 정보가 있겠네요. 이걸 다음과 같이 정의할 수 있겠죠.

enum Category {
  None = 0;
  Fiction = 1;
  Essay = 2;
  Magazine = 3;
  Comic = 4;
  Science = 5;
  Computer = 6;
}

message Book {
    string code = 1;
    string title = 2;
    string author = 3;
    Category category = 4;
    double price = 5;
    string shelf = 6;
    int32 count = 7;
}

책의 정보에 대해 정의했으니, 그 다음은 책의 정보를 주고 받을 두 종류의 Library API를 정의해 보죠.

service Library {
  rpc BookByCode (BookCode) returns (Book);
  rpc BooksByAuthor (BookAuthor) returns (BookList);
}

message BookList {
  repeated Book books = 1;
}

message BookCode {
  string code = 1;
}

message BookAuthor {
  string author = 1;
}

첫번째 API를 예로 들면 GetBookByCode 는 책의 코드를 보내면, 책의 정보를 제공해 주는 서비스 입니다. 두번째 API GetBooksByAuthor 도 이름 자체로 설명이 될 것 같군요. 자, 프로토콜 설계 끝났습니다. 여기에서 사용한 구문 형식은 protocol buffer 구문이라고 합니다. 이 파일은 *.proto 라는 이름으로 저장하게 됩니다. (전체 파일은 마지막에 GitHub 링크를 참조) 

 

2. 컴파일 

두 번째 단계를 정의해 놓은 프로토콜 버퍼를 컴파일해서 다양한 프로그래밍 언어로 소스 코드를 생성해 줍니다. 지원하는 언어들은 다음과 같습니다 (실제로는 더 많지만, 너무 많아 생략).

gRPC.supported.language.png

생성된 소스코드를 내 프로젝트에 추가하여 완성하고 컴파일하면 됩니다. 이렇게 컴파일된 프로토콜 버퍼는 사용한 프로그래밍 언어에 무관하게 메세지를 주고 받을 수 있습니다. 서로 다른 컴퓨터 간에 더 효율적인 통신을 위해 이진 형식 (binary format)을 사용합니다. *.proto 파일의 컴파일러는 원래 C언어로 제작되었으나 지금은 거의 모든 언어로 포팅되어 있습니다.

가령, 애플이 지원하는 프로토콜 컴파일러 라이브러리는 여기서 (https://github.com/apple/swift-protobuf) 다운로드 받아 사용할 수 있습니다. 설치한 다음, 위에서 작성한 프로토파일을 컴파일 하면, 

apple.protobuf.library.png다음과 같은 스위프트 소스코드가 생성됩니다.

struct Book {
  var code: String = String()
  var title: String = String()
  var author: String = String()
  var category: Category = .none
  var price: Double = 0
  var shelf: String = String()
  var count: Int32 = 0
  var unknownFields = SwiftProtobuf.UnknownStorage()
  init() {}
}

 

다음은 C#을 사용해서 서버와 클라이언트를 동시에 구현하여 실행한 예제입니다 (Visual Studio Code).

gRPC.sample.csharp.server.client.png

물론 Java나 Kotlin으로 Spring Boot를 사용한 예제도 있습니다.

 

3. 실행 

컴파일된 서비스와 클라이언트를 실행하면 원하는 API 백엔드와 프론트엔드가 동시에 개발이 완료되는거죠.

사용한 서비스와 클라이언트 예제 (C#, Java, Swift, Spring Boot, Kotlin)들은 GitHub 링크를 참조하세요.

 

4. Protodot : Visualization

한 가지 더 유용한 프로그램도 소개합니다. 프로토콜 버퍼의 구문 형식은 JSON 처럼 서술적이지 않아서, 그 자체로도 가독성이 좋습니다만, 다소 복잡한 시스템에서 전체 API 구조를 청사진처럼 다이어그램으로 보여줄 수 있는 유틸리티도 오픈소스 프로젝트로 있더군요.(Protodot https://github.com/seamia/protodot). 가령 이글에서 정의한 도서관 API를 시각화해서 표현하면 아래와 같이 됩니다.

gRPC.protodot.visualization.png

 

5. JSON API 와 함께 사용 가능

참고로, 기존에 JSON으로 작성된 API를 버리고 gRPC로 갈아 탈 필요는 없습니다. gRPC의 HTTP Content-Type 은 application/protobuf 이라서, application/json 인 JSON type API와 구분해서 병용할 수도 있습니다.

grpc.uses.with.json.png 

6. 결론

gRPC 는 보다 단순한 API 설계와 버전관리에 용이한 Protocol Buffer 를 사용하여, 간단하게 API backend와 클라이언트를 제작하는데 편리하며, HTTP/2를 기본으로 제공, 그 성능면에서도 기존 JSON+HTTP와 비교하여 10분의 1의 CPU 용량을 사용하는 성능을 내는 고성능 API 서비스 제작에 적합한 라이브러리입니다. 

 

이글에서 다른 전체 소스 코드는 GitHub을 참조하세요 (https://github.com/cavecafe/grpc-demo)

 

Comments


Comments are closed