Go언어 RESTfull gRPC 서버 만들기 (브라우저로 접속가능한 gRPC 서버)
1. 개요: RPC 및 gRPC 의미, 직렬화 (Serialize) 개념, 구현 목표
2. gRPC 서비스 만들기
3. gRPC micro service 만들기 (서비스 서버 간 통신)
4. RESTfull gRPC 서비스 서버 만들기 (gRPC gateway)
1. 개요
1.1. RPC 란?
RPC란 Remote Procedure Call의 약어로 서로 다른 곳에 있는 함수 또는 프로시저를 사용할 수 있게 해주는 통신 방식이다. RPC가 등장한 배경은 "분산 네트워크 환경에서 컴퓨터 간 통신을 어떻게 쉽게 프로그래밍할 수 있을까?"으로부터 나왔다. RPC는 전통적인 Client-Server 패턴을 사용하며, 단지 멀리 떨어진 프로그램의 기능을 마치 내 프로그램의 함수를 호출하듯이 쉽게 도와주는 역할을 한다. 그림 1과 같이 RPC 서버와 RPC 클라이언트가 있을 때, RPC 클라이언트가 함수를 호출하면 RPC 서버는 요청받은 함수를 처리하고 클라이언트에게 결과를 반환해준다.
그냥 함수 정의하고 함수 호출하는 거랑 뭐가 다르냐? 라는 질문을 할 수 있다. 물론 단일 서버에서 동작하거나 내가 (우리팀이) 오로지 관리하는 프로그램은 굳이 RPC를 이용할 필요 없다. RPC의 가장 큰 장점은 분산 컴퓨팅 환경에서 1) 서로 다른 언어로 구현 된, 2) 멀리 떨어진 (네트워크를 통해야 하는) 프로그램의 기능을 쉽게 사용 가능하다는데 있다. RPC 형식으로 정의된 규약 (인터페이스)만 잘 맞추면 친구가 Python으로 만든 프로그램을 내가 Golang으로 만든 프로그램에서 함수를 호출 하듯이 사용할 수 있다. 즉, 쉬운 협업 및 효과적인 프로그램 간 연동이 가능해진다. 그림 2는 JSON을 이용한 RPC 방식의 예시를 나타낸다. subtract라는 함수의 호출이 RPC 라이브러리를 통해 JSON 메시지로 변경되어 Remote 서버에서 전송 된다. 그림 2에 나타나는 JSON 메시지의 의미는 다음과 같다. jsonrpc는 JSON 프로토콜 버전, method는 호출 함수이름, params는 매개변수 (파라미터), result는 반환 값, id는 송신 메시지/수신 메시지 짝(pair)을 맞추기 위한 메시지 ID이다.
RPC의 대표적인 구현은 구글에서 만든 gRPC, 페이스북에서 만든 Thrift, 트위터에서 만든 Finagle이 있으며, 그 외JSON 기반 RPC, XML-기반 RPC 구현들도 존재한다. 이 글에서는 구글에서 만든 gRPC에 대해 다룬다.
1.2. gRPC
구글에서 만든 gRPC는 RPC 자체의 장점과 더불어 또 하나의 장점이 존재한다. 바로 gRPC가 구글에서 만든 protobuf (프로토콜 버퍼)를 기반으로 만들어졌다는 것이다.
protobuf는 구조화된 데이터 (struct)를 직렬화 (serialize 또는 marshall)해주는 라이브러리 (포맷)이다. 이 역할은 하는 다른 포맷은 JSON, XML 등이 있다. protobuf, JSON, XML과 같은 데이터 포맷의 역할은 프로그램 상에서 구조화된 데이터에서 1) 구조에 대한 메타 데이터를 제거하고, 2) 데이터 압축과 같은 기법을 통해 직렬화된 데이터로 만들어 네트워크 상으로 데이터를 전송하기 용이하도록 1) 데이터 형식을 변경하고, 2) 데이터의 용량을 줄이는 것이다. 송신자 측에서 데이터를 직렬화하여 약속된 형태로 데이터를 전송하면, 수신자 측은 받은 데이터를 자신의 프로그램에 맞는 형태의 구조화된 데이터로 변경하여 사용한다 (deserialize 또는 unmarshall). 그림 3은 직렬화의 개념을 간단히 보여준다. my_struct라는 구조체의 변수 이름, 값, 메모리 크기, 메모리 위치 등의 구조화된 데이터가 직렬화를 통해 다른 형식으로 변환된다. 수신 측에서는 이를 다시 자신의 프로그램에 환경에 맞게 역직렬화한다. 구조화된 데이터의 메타데이터, 형식 등은 언어에 따라 다르고, 직렬화된 데이터 형식도 역시 사용하는 데이터 포맷에 따라 다르다.
다른 데이터 포맷들과 비교해서 protobuf의 가장 큰 장점은 직렬화된 데이터의 사이즈가 매우 작다는 것이다. 즉, 대용량 데이터 통신에 매우 용이하다. JSON과 비교하자면, JSON은 사람이 읽을 수 있는 형식인 반면 protobuf은 사람이 읽을 수 없는 형태로 데이터를 직렬화하기 때문에 데이터의 용량을 매우 작게 줄일 수 있다.
이 글에서 같은 의미로 사용한 직렬화(Serialization)와 마샬링(Marshalling)가 차이가 있다고는 하는데 이 글의 맥락에서 구별해야할 정도로 큰 차이는 없는 듯하다.
1.3. 구현 목표
이 글에서 목표하는 프로그램 형태는 그림 4와 같다. 크게 보면 온라인 커뮤니티 서비스에서 특정 사용자를 검색하고 그 사용자가 작성한 게시글을 조회하는 유즈케이스이다. 사용자는 1) RPC 방식 (프로그램을 통한 방식)과 2) HTTP 방식 (웹 브라우저를 이용하는 방식)으로 2가지 통신 방식으로 서비스에게 데이터를 요청할 수 있다.
첫 번째 방식은 gRPC 기본 제공 방식으로 다음과 같은 순서로 실행된다. (a--> b--> c --> b --> a)
1) 사용자 클라이언트(a)는 사용자 조회서버(b)에게 RPC 함수 호출로 사용자 정보를 요청
2) 사용자 조회 서버(b)는 자신의 서버에서 사용자 정보를 검색한 후
3) 게시글 조회 서버(c)에게 RPC 호출로 특정 사용자에 게시글 조회를 요청
4) c --> b --> a 순으로 결과값 반환
5) 사용자 클라이언트(a)는 특정 사용자의 정보와 사용자가 작성한 게시글에 대한 정보를 얻음
두 번째 방식은 사용자가 웹 브라우저를 사용할 수 있도록 RESTfull을 지원하는 gRPC Gateway 서버를 추가한 방식이다. (d --> e --> b --> c --> b --> e --> d)
1) 사용자 클라이언트(d)는 RPC Gateway 서버(e)에게 HTTP 방식으로 사용자 정보를 요청
2) RPC Gateway 서버(e)는 HTTP 요청을 protobuf 형식으로 변환한 후 사용자 조회 서버(b)에게 RPC 호출
3) 사용자 조회 서버(b)는 자신의 서버에서 사용자 정보를 검색한 후
3) 게시글 조회 서버(c)에게 RPC 호출로 특정 사용자에 게시글 조회를 요청
4) c --> b --> e --> d순으로 결과값 반환
5) 사용자 웹 브라우저(a)는 특정 사용자의 정보와 사용자가 작성한 게시글에 대한 정보를 얻음
이후 글에서 만들 부분은 아래와 같다.
1. gRPC 서비스 만들기 --> a, b
2 gRPC micro service 만들기 (서비스 서버 간 통신) --> a, b, c
3. RESTfull gRPC 서비스 서버 만들기 (gRPC gateway) --> e, b, c
참고
이 글은 아래 블로그를 참고하여 작성하였습니다
devjin-blog.com/golang-grpc-server-1/
틀린 내용, 조언, 질문은 언제든지 댓글로 남겨주시면 감사하겠습니다.
댓글