블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


구글 프로토콜 버퍼 (Protocol buffer)

프로그래밍 | 2017.06.25 19:30 | Posted by 조대협


구글 프로토콜 버퍼

조대협 (http://bcho.tistory.com)


텐서 플로우로 모델을 개발하다가 학습이 끝난 모델을 저장하여, 예측하는 데 사용하려고 하니, 모델을 저장하는 부분이 꽤나 복잡하여 찾아보니, 텐서플로우는 파일 저장 포맷을 프로토콜 버퍼를 사용한다는 것을 알았다.


그래서, 오래전에 살펴보았던 프로토콜 버퍼를 다시 살펴보았다.

개요 및 특징

프로토토콜 버퍼는 구글에서 개발하고 오픈소스로 공개한, 직렬화 데이타 구조 (Serialized Data Structure)이다. C++,C#, Go, Java, Python, Object C, Javascript, Ruby 등 다양한 언어를 지원하며 특히 직렬화 속도가 빠르고 직렬화된 파일의 크기도 작아서 Apache Avro 파일 포맷과 함께 많이 사용된다.

(직렬화란 데이타를 파일로 저장하거나 또는 네트워크로 전송하기 위하여 바이너리 스트림 형태로 저장하는 행위이다.)


특히 GRPC 라는 네트워크 프로토콜의 경우 HTTP 2.0 을 기반으로 하면서, 메세지를 이 프로토콜 버퍼를 이용하여 직렬화하기 때문에, 프로토콜 버퍼를 이해해놓으면 GRPC를 습득하는 것이 상대적으로 쉽다.


프로토콜 버퍼는 하나의 파일에 최대 64M까지 지원할 수 있으며, 재미있는 기능중 하나는 JSON 파일을 프로토콜 버퍼 파일 포맷으로 전환이 가능하고, 반대로 프로토콜 버퍼 파일도 JSON으로 전환이 가능하다.

설치 및 구성

프로토콜 버퍼 개발툴킷은 크게 두가지 부분이 있다. 데이타 포맷 파일을 컴파일 해주는 protoc 와 각 프로그래밍 언어에서 프로토콜 버퍼를 사용하게 해주는 라이브러리 SDK가 있다.


protoc 컴파일러와, 각 프로그래밍 언어별 SDK는 https://github.com/google/protobuf/releases  에서 다운 받으면 된다.


protoc 는 C++ 소스 코드를 직접 다운 받아서 컴파일하여 설치할 수 도 있고, 아니면 OS 별로 미리 컴파일된 바이너리를 다운받아서 설치할 수 도 있다.  


각 프로그래밍 언어용 프로토콜 버퍼 SDK는 맞는 버전을 다운 받아서 사용하면 된다. 파이썬 버전 설치 방법은  https://github.com/google/protobuf/tree/master/python 를 참고한다.

이 글에서는 파이썬 SDK 버전을 기준으로 설명하도록 한다.

구조 및 사용 방법

프로토콜 버퍼를 사용하기 위해서는 저장하기 위한 데이타형을 proto file 이라는 형태로 정의한다. 프로토콜 버퍼는 하나의 프로그래밍 언어가 아니라 여러 프로그래밍 언어를 지원하기 때문에, 특정 언어에 종속성이 없는 형태로 데이타 타입을 정의하게 되는데, 이 파일을 proto file이라고 한다.

이렇게 정의된 데이타 타입을 프로그래밍 언어에서 사용하려면, 해당 언어에 맞는 형태의 데이타 클래스로 생성을 해야 하는데, protoc 컴파일러로 proto file을 컴파일하면, 각 언어에 맞는 형태의 데이타 클래스 파일을 생성해준다.


다음은 생성된 데이타 파일을 프로그래밍 언어에서 불러서, 데이타 클래스를 사용하면 된다.

예제

간단한 파이썬 예제를 통해서 사용법을 익혀보자. 저장하고자 하는 데이타 포맷은 Person 이라는 클래스형으로, 이름,나이,이메일을 순차적으로 가지고 있는 데이타 포맷을 정의하여, Person 객체를 생성하여 데이타를 저장하고 이 객체를 파일에 저장했다가 읽어 들이는 예제이다.


이름과 이메일은 문자열, 나이는 숫자로 저장된다. 이 데이타형을 proto 형으로 정의하면 다음과 같다.

address.proto

syntax = "proto3";

package com.terry.proto;


message Person{

 string name = 1;

 int32 age=2;

 string email=3;

}


이 파일을 address.proto 라는 이름으로 저장한다. 다음 proto 파일을 파이썬용 코드로 컴파일한다. protoc 명령을 이용하면 되는데,


protoc -I=./ --python_out=./ ./address.proto


  • -I에는 이 protofile이 있는 소스 디렉토리

  • --python_out에는 생성된 파이썬 파일이 저장될 디렉토리

  • 그리고 마지막으로 proto 파일을 정의한다.


이렇게 컴파일을 하면 --python_out으로 지정된 디렉토리에 address_pb2.py 라는 이름으로 파이썬 파일이 생성된다. (pb2는 protocol buffer2를 의미하는 확장자이다.)


다음은 생성된 Person 클래스를 이용하여 객체를 만들고, 값을 지정한 후 이를 파일로 저장하는 예제이다.

write.py

import address_pb2


person = address_pb2.Person()


person.name = 'Terry'

person.age = 42

person.email = 'terry@mycompany.com'


try:

f = open('myaddress','wb')

f.write(person.SerializeToString())

f.close()

print 'file is wriiten'

except IOError:

print 'file creation error'


protoc에 의해 컴파일된 address_pb2 모듈을 import 한후에, address_pb2.Person()으로 person 객체를 생성한다. 다음에 person.name, person.age, person.email에 값을 넣은 후 파일을 열어서 파일에 person 객체의 내용을 넣는데, 이때 SerializeToString() 메서드를 이용하여 문자열로 직렬화 한다.


다음 코드는 이렇게 파일로 저장된 person 객체를 다시 파일로 부터 읽는 코드이다.

read.py

import address_pb2


person = address_pb2.Person()


try:

f = open('myaddress','rb')

person.ParseFromString(f.read())

f.close()

print person.name

print person.age

print person.email

except IOError:

print 'file read error'


앞의 코드와 같이 빈 person 객체를 만든 후에, 파일에서 문자열을 읽어서 ParseFromString() 메서드를 이용하여 문자열을 person 객체로 파싱한후에, 그 내용을 출력한다.

데이타 구조

위의 예제에서는 간단하게 name,age,email 정도의 구조만 간단하게 정의했지만, JSON과 같이 계층을 가지거나 배열형의 데이타 구조도 같이 정의할 수 있고, enum과 같은 타입 정의도 가능하다.

자세한 설명은 https://developers.google.com/protocol-buffers/docs/proto 를 참고하기 바란다.

간단한 팁 - JSON 변환

앞서 설명했듯이, 프로토콜 버퍼의 다른 장점중의 하나는 프로토콜 버퍼로 저장된 데이타 구조를 JSON으로 변환하는 것도 가능하고 역으로 JSON 구조를 프로토콜 버퍼 객체로 만들 수 도 있다.

아래 코드는 프로토콜 버퍼 객체인 person을 JSON으로 변환하여 출력하는 부분이다. MessageToJson 메서드를 사용하면 된다.


print person.name

print person.age

print person.email


from google.protobuf.json_format import MessageToJson

jsonObj = MessageToJson(person)

print jsonObj


다음은 실행 결과이다.


Terry

42

terry@mycompany.com

{

 "age": 42,

 "name": "Terry",

 "email": "terry@mycompany.com"

}



이 기능을 사용하면, 클라이언트(모바일)에서 서버로 HTTP/JSON 과 같은 REST API를 구현할때, 전송전에, JSON을 프로토콜 버퍼 포맷으로 직렬화 해서, 전체적인 패킷양을 줄여서 전송하고, 서버에서는 받은 후에, 다시 JSON으로 풀어서 사용하는 구조를 취할 수 있다. 사실 이게 바로 GRPC 구조이다.

API 게이트웨이를 백앤드 서버 전면에 배치 해놓고, 프로토콜 버퍼로 들어온 메세지 바디를 JSON으로 변환해서 백앤드 API 서버에 넘겨주는 식의 구현이 가능하다.


저작자 표시 비영리
신고