gRPC

Protocol buffers

Mussyan 2021. 3. 30. 11:55

목차

  1. 개요
  2. 장단점
  3. 사용법

 

 


개요

구글에서 개발하고 사용중인 직렬화 데이터 구조.

파일 하나에 64M까지 지원. 

기타 특징들은 아래 장단점에 서술.

 

 

장단점

장점

이름있는 언어는 대부분 지원

직렬화 속도가 빠름

직렬화된 파일의 크기가 작음 = 통신 효율 증대

데이터를 바이트형태로 직렬화하여 전송하기에 별도의 파싱 과정이 필요 없다.

proto 파일 <-> json 전환 유틸 지원

protobuf 공식 홈페이지 曰 : xml에 비해 3~10배 작고 20~100배 빠르고 더 간결하고 덜 모호하고 더 쉬운 데이터 액세스 클래스를 제공합니다.

 

단점

Protocol buffer에 쓰는 스키마 파일인 proto 파일에 대한 사전 지식이 필요하다.

바이트 형태이기에 사람이 읽기엔 적합하지 않다.

proto 파일을 보면 이해할 수 있으나 스키마 파일을 별도로 관리해야 한다는 뜻이 됨

 

 

사용법

proto 파일

proto 파일을 작성한다. 

protocol buffers는 다양한 프로그래밍 언어를 지원하기 때문에 특정 언어에 종속성이 없는 데이터 타입을 활용한다.

syntax = "proto3";

message Person{
  string name = 1;
  int32 age = 2;
  string team = 3;
}

가장 간단하게는 위와 같은 형태로 작성해볼 수 있으며 확장자명은 .proto이다.

위 예제는 name, age, team 변수를 갖는 Person 객체를 정의한 내용이다.

protocol buffers의 문법은 분량이 방대하여 별도의 문서에서 다룹니다.

별도의 문서 링크

파일을 작성한 후에는 프로토콜 버퍼 컴파일러를 활용하여 원하는 언어에 맞는 클래스를 생성할 수 있다.

 

protocol buffers compiler

프로토콜 버퍼 컴파일러는 'protoc' 으로 주로 불린다.

설치는 맥의 경우

brew install protobuf

으로 손쉽게 설치가 가능하다.

설치 후 .proto 파일을 원하는 언어의 클래스로 컴파일하는 명령어는 다음과 같다.

protoc -I=${.proto 파일이 있는 디렉토리} --${원하는언어}_out=${원하는 결과물 위치} ${컴파일 할 .proto 파일}

ex)
protoc -I=./proto --python_out=./pb_python ./proto/helloworld.proto

예시 명령어를 실행할 경우 './pb_python' 디렉토리에 'helloworld_pb2.py' 파일이 생성된다.

C++이라면 .pb.h 및 .pb.cc

java라면 .java 등 언어별로 생성되는 파일의 형태 및 활용법이 조금씩 다르다.

 

Helloworld with python

간편하게 사용할 수 있어서 POC에 적합한 파이썬으로 위에서 생성한 파일을 활용해보자면 다음과 같이 코딩해볼 수 있다.

import helloworld_pb2

person = helloworld_pb2.Person()

person.name = 'Leo'
person.age = 26
person.team = 'MaaP'
serial = person.SerializeToString()

try:
 f = open('test','wb')
 f.write(test)
 f.close()
 print ('file is written')
 print ('file size : ' + str(len(serial)) + ' Byte(s)')
except IOError:
 print ('file creation error')

protoc 명령어로 생성한 모듈을 활용해 객체를 생성하고 값을 입력한 후 직렬화하여 파일로 저장하는 코드.

저장된 파일을 ls 명령어로 열어보면 키에 대한 내용은 없고 값에 대한 내용만 직렬화되어 저장되어 있음을 확인할 수 있다.

파일을 다시 아래 코드로 읽어보면 proto 파일을 활용하여 키와 값이 매칭됨을 알 수 있다.

import helloworld_pb2

person = helloworld_pb2.Person()

try:
 f = open('serial','rb')
 person.ParseFromString(f.read())
 f.close()
 print ('name : ' + person.name)
 print ('age : ' + str(person.age))
 print ('team : ' + person.team)
except IOError:
 print ('file read error')

파일을 읽고 파싱을 통해 객체처럼 사용할 수 있다!

 

단순히 객체의 내용을 파일로 쓰고, 읽어서 사용하는건 특별한 기능은 아닌 듯 하다.

Protocol buffers에서 제공하는 json 변환 기능을 활용하면 장점을 편하게 확인할 수 있다.

import helloworld_pb2
from google.protobuf.json_format import MessageToJson

person = helloworld_pb2.Person()

try:
 f = open('serial','rb')
 person.ParseFromString(f.read())
 f.close()
 jsonObj = MessageToJson(person)
 print (jsonObj)
 print ('size : ' + str(len(jsonObj)) + ' Byte(s)')
except IOError:
 print ('file read error')

위 코드를 실행하면 직렬화하여 저장한 파일을 읽고 이를 json 형태로 출력하게 되며 추가로 json 객체의 길이를 출력한다.

이 글의 예제를 따라왔다면 파일을 저장할 때에는 13바이트의 파일크기를 가지며 이를 json 형태로 변환하면 무려 50바이트의 크기를 가짐을 알 수 있다.

파일이 아닌 전송이라고 생각하면 거의 4배에 가까운 통신효율을 보인다고 볼 수 있다.(물론 실제로는 오버헤드로 인해 4배까진..)

 

 

0426 수정