gRPC와 Protocol Buffers

업데이트:


gRPC와 ProtoBuf

gRPC와 ProtoBuf 개념에 대해 학습하고 간단한 실습을 통해 이해한다.

공식문서

  • https://grpc.io/docs/what-is-grpc/core-concepts/
  • https://grpc.io/docs/languages/java/quickstart/

# gRPC

핵심정리

  • IDL

    • 표준 인터페이스 명세(클라이언트, 서버 모두 필요)

    • *.ptoto의 모음

    • *.proto 파일은 build 하면 protoc 컴파일러에 의해 지정한 경로에 자동으로 각 언어에 맞는 코드가 생성된다.

      idl/gen/java/com/github/banksalad/idl/daas/v1/collect/
      
      syntax = "proto3";
          
      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;
      }
      
      • Greeter - service 타입의 class
      • SayHello - Method, Procedure
      • HelloRequest, HelloReply - message 타입의 class
        • 필드값으로 string 타입의 name, message를 갖는다.
      • rpc - 일종의 Endpoint(@GetMapping)
      • message - 일종의 DTO, VO
        • 직렬화, 역직렬화
  • Server

    • IDL에서 정의한 메서드를 구체화한다. 일종의 구현체라고 할 수 있다.

    • IDL에 의해 자동 생성된 추상클래스를 상속받아 메서드를 구현한다.

    • proto에서 정의한 Request를 매개변수로 받아 Response를 정의한다.

    • 우리의 경우는 build 후 자동 생성까지 된 repo를 depenency로 주입받아 사용한다. (.jar)

      static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
          
        @Override
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
          HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
          responseObserver.onNext(reply);
          responseObserver.onCompleted();
        }
      }
      
  • Client

    • proto에서 정의한 Request의 필드값을 설정하여(여기서는 name) 서버에 메서드 단위로(여기서는 SayHello) 요청한다.

    • 서버로부터 받은 Response의 필드값을 사용할 수 있다.

      public class HelloWorldClient {
        private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());
          
        private final GreeterGrpc.GreeterBlockingStub blockingStub;
          
        /** Construct client for accessing HelloWorld server using the existing channel. */
        public HelloWorldClient(Channel channel) {
          blockingStub = GreeterGrpc.newBlockingStub(channel);
        }
          
        /** Say hello to server. */
        public void greet(String name) {
          HelloRequest request = HelloRequest.newBuilder().setName(name).build();
          HelloReply response = blockingStub.sayHello(request);
          logger.info("Greeting: " + response.getMessage());
        }
      }
      

정의

  • 언어 제약이 없는 오픈소스
  • 고성능 RPC(Remote Procedure Calls, 원격 프로시저 호출)
  • 인터페이스(Contract, 계약) 기반 RPC 서비스
    • 서버에 인터페이스를 구현 후 클라이언트에 동일한 인터페이스 구현 후 통신

왜 쓰는가?

  • 성능이 빠르다.
  • 네트워크에 전송되는 양이 적다.
    • 프로토콜 버퍼를 사용하여 네트워크 트래픽을 XML, JSON에 비해 적게 소모한다.
  • 기존 RPC 프레임워크에 비해 빠르고 사용하기 편하다.

특징

  • 일반적인 모든 언어를 사용하여 서버, 클라이언트를 구현할 수 있어 언어의 제약이 없다.
    • 다중언어 환경에 대한 광범위한 상호 운용성
  • 최신 기술 기반이다.
    • HTTP/2
    • 데이터를 주고 받을 때 프로토콜 버퍼(Protocol Buffers, protobuf)를 사용

구조

gRPC

gRPC vs. REST

  • REST 서비스는 서버가 어떤 언어로 되어있던 XML 또는 JSON 파일로 데이터를 주고받는다.
  • gRPC는 protobuf를 사용해서 binary 파일로 데이터를 전송하는 차이점이 있다.

키워드

  • gRPC
  • ProtoBuf
    • 구글에서 만든 데이터 전송 구조
  • Stub
    • 클라이언트
  • IDL

ProtoBuf (Protocol Buffers)

개념

  • CSV, XML, JSON과 같은 데이터 구조의 일종
    • 텍스트 형식 - JSON, XML
    • 바이너리 형식 - Protocol Buffers
  • IDL(Interface Definition Language)
    • 인터페이스를 한번 정의하여 여러 언어에서 상속해 구현
    • IDL 자체가 Swagger나 API 문서가 된다.

특징

  • 한번 작성 후 여러 언어에서 재사용한다.
    • 크로스 플랫폼을 지원
  • 텍스트 형식이 아니고 바이너리 형식이기 떄문에 가볍고 빠르다.
  • ProtoBuf는 내부적으로 protoc라는 컴파일러가 있다.
    • protoc는 .proto 파일을 컴파일 해서 원하는 언어(Java, Go, Python 등)의 코드를 자동으로 생성해준다.

서비스 모델

  • Service
    • 서비스 메서드 정의
  • Message
    • 요청과 응답에 대한 구조 정의
  • 일반적으로 서비스 하나에 메세지 두개를 갖는다.
  • 클래스 타입으로 요청과 응답을 주고받기 때문에 strong typed 하다고 말한다.

프로토콜 버퍼 정의하기

  • 하나의 *.proto 텍스트 파일에 정의한다.
  • 정의된 코드는 어렵지 않게 이해 가능하다.
    • 1개의 서비스 클래스 정의
    • 2개의 메세지 클래스 정의
  • 컴파일러(protoc)에 의해 원하는 언어 코드를 자동으로 생성한다.

데이터 형식

  • string, bool, bytes, int32, int64, float, double, uint32, uint64, sint32, sint64
  • datetime은 별도의 데이터 형식을 지원하지 않고 string으로 사용하면 된다.

의문점

  • 직렬화에 대한 구체적인 이해
    • 별도로 학습하여 정리
  • 텍스트 형식이던 바이너리 형식이던 결국엔 0101로 넘어갈텐데 가볍다는게 어떤 의미인지?
    • 압축하여 전송
  • 서버에서 IDL 인터페이스 구성하고 구현체까지 작성?
    • IDL 인터페이스를 구성 후 빌드하여 해당 의존성을 추가해서 사용
    • 서버에서는 구현체 작성까지

실습

참고 링크

  • https://grpc.io/docs/languages/java/quickstart/#update-the-grpc-service
  • https://lelecoder.com/146?category=793314

실습 팁

  • *.proto 파일의 service에 메서드를 정의하고 build하면 해당 언어에 맞게 자동으로 코드가 생성된다.

    ./examples/build/generated/source/proto/main/grpc/io/grpc/examples/helloworld/GreeterGrpc.java
    
  • Android dependency 관련 에러는 해당 실습해서는 필요하지 않으니 주석처리했다.

References

댓글남기기