지나공 : 지식을 나누는 공간

REST API 에서 왜 gRPC를 택하게 되었는가? gRPC 등장 본문

Tech/gRPC & Protobuf

REST API 에서 왜 gRPC를 택하게 되었는가? gRPC 등장

해리리_ 2021. 7. 7. 11:45

REST API 의 장점

  • 학습과 사용이 매우 쉽다.
  • 자유도가 높아 원하는 대로 사용 가능하다.
  • json이 응답으로 오면 파싱할 필요도 없다.

REST API의 문제점

  • 너무 자주 바뀌는 API (서버에서 자꾸 변경할 때가 많음)
  • 너무 높은 자유도
  • 버저닝(이 가능하긴 하나 손이 너무 많이 감)
  • api 문서를 만들 수는 있으나 코드랑 너무 떨어져 있으니 죽은 문서가 됨

그래서 나온 게 바로 IDL(Interface Description Language) 라고 하는 인터페이스 정의 언어이다.

이것의 큰 장점은 언어에 종속되지 않고 컴포넌트 사이의 통신을 가능하게 한다.

 

그럼 우리는 이 rest api를 어떤 idl을 사용해서 표현할 수 있을까? 라는 고민을 한다.

첫 번째는 open API로, 그 장점은 아래와 같다.

  • 버전을 쓸 수 있어서 버저닝이 가능하다.
  • api 우선 접근이다.
  • Machine Readable Interface
  • IDL 변경 없이는 서버 API를 변경할 수 없음.

보통은 서버 개발이 마친 뒤에 프론트엔드 개발이 시작되거나 서버가 바뀔 때 동시에 많은 것들이 같이 바뀌는데, api우선 접근은 먼저 api의 규격을 먼저 정의한 뒤에 프론트엔드 개발을 하자는 것이다. 이렇게 말하면 문서를 작성한 것과 뭐가 다른가 싶다. 문서도 똑같이 api 규격 정한 다음에 시작하면 되지 않나? 싶은데, open api는 Machine Readable Interface 라서 기계가 이해할 수 있기 때문에 이렇게 정의된 파일을 가지고 서버 스텁을 만들어서 그 안쪽을 서버에서 채우는 것이다. 이렇게 하면 IDL 자체를 바꾸지 않는 이상 api를 변경할 수는 없게 된다.

하지만 그럼에도 단점이 존재한다. Open API 의 단점은,

  • 가독성이 아쉬움. 어떤 파라미터고 어떤 타입인지 파악하려면 코드를 좀 파고 들어가야 함.
  • 버전 관리는 가능하지만 여전히 버전 관리의 규칙이 필요하다.

그 다음에 볼 수 있는게 드디어 grpc이다. 

gRPC란?

구글에서 최초로 개발한 오픈 소스 원격 프로시저 호출 시스템(RPC프레임워크).

grpc 가 사용하는 IDL이 있는데 이게 Protocol Buffers 이다.

gRPC는 http/2를 사용해서 동작하지만 우리는 아직 웹 브라우저가 http/2를 사용하도록 강제할 수 없다.

그러므로 현재 브라우저에서는 http/2의 스펙으로 구현할 수 없다.

이를 해결하기 위해 나온 걸로는 gRPC-web, gRPC <> HTTP/JSON Transcoding 이 있다. 간단히 보자면 아래와 같다.

 

- gRPC-Web

http/1 위에서 올라가는 grpc 라이브러리를 이용해서 그 request를 보내고, 이걸 서버가 바로 받기 전에 그 앞에 프록시가 해당 requet를 실제 grpc request로 변경해서 보낸다.

 

- gRPC <> HTTP/JSON Transcoding

gRPC를 REST API 로 변환한다.

 

위에서 gRPC는 RPC 프레임워크라고 했는데, 사실 이 개념은 원래 있던 개념이다.

RPC란?

  • 원격 컴퓨터나 프로세스에 존재하는 함수를 호출하는 데 사용하는 프로토콜.
  • 물론 이 개념이 존재하기 전부터 소켓 프로그래밍 등 네트워크 상에 존재하는 서비스를 호출할 수 있었지만 네트워크 상의 원격 통신은 느리거나 서버가 응답하지 않는 등의 장애가 발생할 가능성이 있음. 그리고 소켓 프로그래밍으로 직접 구현한다면 네트워크에서 발생할 수 있는 다양한 예외상황을 개발자가 직접 핸들링 해야 함.
  • RPC는 위와 같은 작업들을 대신 해 줌. 그래서 개발자는 원격 컴퓨터나 프로세스에 존재하는 함수를 동일 프로세스에 존재하는 함수를 호출하듯이 쉽게 호출할 수 있음.

gRPC는 IDL로 protocol buffers(이하 protobuf)를 사용한다고 했다. 그럼 이건 또 뭘까?

Protobuf?

  • gRPC는 ProtoBuf를 IDL 및 기본 메시지 교환 포맷으로 사용할 수 있음.
  • 데이터 직렬화 라이브러리로 메시지와 서비스까지도 정의할 수 있음.
  • proto 코드를 protoc 컴파일러를 통해 데이터 접근을 위한 코드로 생성해 낸다.
  • message 타입 하나 만들면 만약 자바 코드로 생성된다고 할 때 setter, getter 등 필요한 메소드가 만들어진다.

이런 gRPC는 http2를 사용한다고 했는데 그럼 그건 또 뭘까..!

http/2?

HTTP/1은 기본적으로 클라이언트가 서버에 요청을 보내고 서버가 요청에 대해 응답을 보내는 구조로, 요청 단위가 클라이언트와 서버를 왕복하고, 또 쿠키를 포함한 헤더 크기도 불필요하게 커서 통신이 느림.
이를 개선하면서 HTTP/2 표준이 만들어 졌고, 아래와 같은 특징이 있다.

  • 헤더 정보를 압축했음.
  • 1에서는 요청마다 새로운 커넥션을 자주 만들었지만 2는 한 개의 커넥션으로 동시에 여러 메시지를 주고 받을 수 있음.
  • 클라이언트 요청 없이도 서버가 리소스를 보낼 수 있음. 이로 인해 클라이언트 요청이 최소화되어서 성능이 향상됨.
  • 요청에 우선순위를 정해서 중요한 리소스를 먼저 전달받을 수 있음.
  • 이런 특성 덕에 gRPC는 통신 속도가 빠르고 on-connection 상태에서 비동기 통신을 구현하기 용이함.

이제 그럼 직접 개발해보려고 한다. 어떻게 gRPC를 쓸 수 있을까. 그 작업 플로우를 알아보자.

gRPC 작업 플로우?

  1. .proto 파일에 서비스 정의하자.
  2. protoc를 사용해서 서버와 클라이언트 코드를 생성시키자.(빌드)
    • ProtoBuf 에 정의한 메시지에 따라서 .java가 생성되고 각 필드에 대한 getter, setter, 직렬화 코드가 생성됨.
    • ProtoBuf 에 정의한 서비스에 따라서 .java가 생성됨.
  3. 생성된 gRPC 서비스 정의에 따른 파일을 상속한 서비스 코드에 비즈니스 코드를 작성하자.
  4. 서비스 메소드를 호출하기 위한 클라이언트 코드들이 생성됨. 이걸 활용해서 서비스의 함수를 호출하자.
  5. 서버를 실행할 서버 코드를 작성하자. (포트 설정하고 작성했던 서비스를 실행하는 부분)
  6. 생성되었던 클라이언트 코드를 사용해서 서비스의 각 메소드를 호출하는 코드를 구현하자.

이런 gRPC 왜 쓰는걸까? 그리고 언제는 안 쓰는게 더 나을까?

gRPC를 왜 쓰는가?

  • ProtoBuf가 지원하는 IDL을 활용한 서비스 및 메시지 정의는 MSA에서 다양한 기술 스택의 공존으로 인해 중복이 발생한다는 단점을 보완하고 수많은 서비스 간의 API 호출로 인한 성능 저하를 개선함.
  • ProtoBuf에 의한 높은 메시지 압축률로 시스템 전체에서의 네트워크 트래픽을 줄여줌.

언제 gRPC를 안 쓸까?

  • 간단한 REST API를 제공하는 서비스 개발에는 적합하지 않음.

 

출처 : 

https://www.youtube.com/watch?v=6C9zyLioTOU

728x90
Comments