Protocol buffers
목차
- 개요
- 장단점
- 사용법
개요
구글에서 개발하고 사용중인 직렬화 데이터 구조.
파일 하나에 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 수정