05-07 03:51
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Programming] Protocol Buffer + ZeroMQ + Python으로 메시징 전달하기 본문

Programming

[Programming] Protocol Buffer + ZeroMQ + Python으로 메시징 전달하기

cinema4dr12 2016. 4. 9. 19:43

Written by Geol Choi | Apr


이번 글에서는 직렬화 데이터 구조 메커니즘인 Google Protocol Buffer(protobuf)와 고성능 비동기 분산메시징 라이브러리인 ZeroMQ 를 Python으로 구현하는 방법에 대하여 알아 보겠습니다.


각각에 대한 자세한 컨셉은 각각의 웹사이트를 참고하기 바랍니다:


개발환경

본 튜토리얼의 개발환경은 다음과 같습니다:
  • OS : Microsoft Windows 7 Professional 64 bit

  • IDE : Microsoft Visual Studio 2015 Community

  • Python : version 2.7.11

  • Protobuf-Python : version 3.0.0 beta 2 (protobuf-python-3.0.0-beta-2)


Protocol Buffer 솔루션 생성하기

Google Developer 페이지에서 Protocol Buffer 소스코드를 다운받습니다:

https://github.com/google/protobuf/releases


또는 여기를 클릭하면 해당 소스를 다운 받을 수 있습니다.


이제 CMake GUI 도구를 이용하여 Visual Studio Solution을 생성하도록 합니다. 다운받은 압축 파일을 압축 해제하면 cmake 폴더를 볼 수 있습니다. 이 경로를 소스 코드 경로로 하고 적절한 경로를 생성하여 binary build를 합니다.


* 참고로 경로는 다음과 같이 지정하였습니다:

  • Where is the source code(소스코드 경로) : {YOUR_PROTOBUF_PATH}/cmake

  • Where to build the binaries(Build 경로) : ANY_PATH_YOU_WANT




[Configure] 버튼을 클릭하고 generator를 Visual Studio 14 2015(자신의 Visual Studio 버전에 맞게 선택한다)를 선택합니다.




다음과 같이 화면이 나오면 [Configure] 버튼을 한번 더 클릭합니다.




[Generate] 버튼을 클릭하여 Visual Studio Solution 생성을 마무리합니다.



Protocol Buffer 빌드하기

이제 생성한 Visual Studio Solution을 열어 빌드하도록 합니다. (protoc 프로젝트만 빌드하여도 무방합니다.)

VS 2015에서 방금 생성한 binaries 경로 내 solution 파일, "protobuf.sln"을 엽니다.


빌드 모드를 Release로 설정하고 빌드하면 {Build_path}/Release 경로에 실행 파일들이 생성됩니다. 이들 중 특히 protoc.exe 파일이 생성되었는지 확인합니다.




.proto 파일 작성하기

.proto 파일은 데이터의 구조를 정의하는 파일입니다. 다음과 같은 구조로 데이터를 정의하도록 하고, 파일 이름은 people.proto로 합니다.


// [START declaration]
syntax = "proto3";
package tutorial;
// [END declaration]

// [START messages]
message Person {
  string name = 1;
  string email = 2;
  int32 id = 3;
}

// People
message People {
  Person person = 1;
}
// [END messages]
`


.proto 파일로부터 Python Module 생성

protoc.exe 파일을 실행하여 Python Module을 생성합니다. 명령 옵션은 다음과 같습니다:


> protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/people.proto

$SRC_DIR는 Source Directory,

$DST_DIR는 Destination Directory를 의미합니다.


현재 경로라면 "."을 입력합니다. 예를 들어 현재 경로에 proto.exe와 people.proto가 존재할 경우, 현재 경로에서 명령 프롬프트를 실행하고 다음과 같이 입력합니다:


> protoc -I=. --python_out=. ./people.proto


정상으로 실행이 잘 되었다면 지정된 경로에 people_pb2.py 파일이 생성됩니다.


Python ZeroMQ Module 설치

Python용 ZeroMQ Module은 pyzmq이다. Python package manager인 pip를 통해 설치하거나:


> pip install pyzmq


또는 다음 웹사이트를 방문하여 직접 다운로드하여 설치합니다: https://pypi.python.org/pypi/pyzmq


참고로 저는 Windows 64bit 환경에서 "pyzmq-15.3.0+fix-cp27-cp27m-win_amd64.whl (md5)"를 직접 다운받아 설치하였습니다.


> pip install {PYTHON_ZEROMQ_PATH}/pyzmq-15.3.0+fix-cp27-cp27m-win_amd64.whl (md5)


자신의 빌드 환경에 적합한 버전을 받아 설치하기를 권장합니다.


Python Protobuf Module 설치

Python의 protobuf 모듈도 pip를 이용하여 간단하게 설치할 수 있습니다:


> pip install protobuf


만약 설치가 안 되면, 다음 링크에서 직접 모듈을 다운받아 설치합니다:
https://pypi.python.org/pypi/protobuf


참고로 이 글 작성 시 Python protobuf 모듈의 최신 버전은 3.0.0이었으며, 이 버전은

https://pypi.python.org/pypi/protobuf/3.0.0를 통해 다운로드가 가능합니다.


다운로드 한 파일을 설치하려면 Command Line Tool에서 아래와 같이 입력합니다:


> pip install {DOWNLOAD_PATH}/protobuf-3.0.0.tar.gz


Python Code 작성

작성해야 할 Python Code는 Publisher와 Subscriber로 두 개의 코드를 작성합니다. ZeroMQ의 Publisher-Subscriber 모델에 대한 자세한 내용은 여기를 참고하도록 합니다. Publisher는 message sender로, Subscriber는 message receiver로써 간단하게는 Server와 Client 정도로 이해하면 될 것 같습니다. 우선 Publisher Code를 작성해 봅니다.


CODE: people-pub-server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#! /usr/bin/env python
 
import zmq
import random
import time
import people_pb2
 
####################################
# Open Port
####################################
port = 8080
 
####################################
# Socket Binding
####################################
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:%s" % port)
 
####################################
# Get Instance from Protobuf
####################################
people = people_pb2.People()
 
####################################
# Publish Values
####################################
while True:
    people.person.name = "gchoi"
    people.person.email = "cinema4dr12@gmail.com"
    people.person.id = random.randrange(0,100)
 
    socket.send_string("%s" % (people.SerializeToString()))
    print("Name: %s , Email: %s , ID: %d" % (people.person.name, people.person.email, people.person.id))
    time.sleep(1)
cs


코드에 대한 자세한 내용은 생략하겠습니다. 다만, Line 17에서 socket binding 시 zmq 옵션을 Publisher(zmq.PUB)로 하였으며, Line 33에서 people 메시지를 String 형태로 전송하고 있음을 유념하기 바랍니다.


이제 다음과 같이 Subscriber 코드를 작성합니다.


CODE: people-sub-client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#! /usr/bin/env python
import sys
import zmq
import people_pb2
 
####################################
# Open Port
####################################
port = "8080"
if len(sys.argv) > 1:
    port =  sys.argv[1]
    int(port)
 
####################################
# Socket to talk to server
####################################
context = zmq.Context()
socket = context.socket(zmq.SUB)
print ("Collecting updates from server...")
socket.connect ("tcp://localhost:%s" % port)
 
####################################
# Subscribe to temperature
####################################
topicfilter = ""
socket.setsockopt(zmq.SUBSCRIBE, topicfilter)
 
####################################
# Instance for People
####################################
people = people_pb2.People()
 
####################################
# Process
####################################
while True:
    string = socket.recv()
    people.ParseFromString(string)
    print("%s" % people.person)
cs


Subscriber에서는 Line 18과 같이 socket binding 시 zmq 옵션을 Subscriber(zmq.SUB)로 설정하였습니다. Line 37에서 Pubslicher로부터 메시지를 전송받고, Linear 38에서 전송받은 메시지를 string으로 변환하도록 합니다.


실행결과

이제 실행만 남았습니다. 테스트는 1개의 Publisher와 2개의 Subscriber로 한다. 우선 Publisher를 실행합니다:


> python people-pub-server.py


Publisher를 실행하면 1초 마다 Person message를 생성합니다. 특히 ID는 난수로 발생시켰습니다.




다음으로 Subscriber를 실행하여 봅니다:


> python people-sub-client.py



Publisher를 실행할 때와 시간 차이가 있어서 Publisher가 message를 전송한 이미지와 Subscriber가 message를 전송 받은 이미지가 동일하지는 않지만, 각자 두 개를 모두 실행하여 message를 비교하면 전송한 message와 전송받은 message가 동일하게 표시됨을 확인할 수 있을 것입니다. 또다른 Subscriber를 실행하여 동일한 message를 받는지 확인해 보도록 합니다.


그리고, 무엇보다도 ZeroMQ의 장점은 Subscriber가 message를 전송받다가 Publisher가 꺼졌더라도 message를 받는 (대기) 상태를 유지하며, Publisher가 다시 살아나면 계속해서 다시 message를 전송받는다는 것입니다.


이로써 이 글을 마치고자 합니다. 과정이 좀 복잡하기는 하지만, 사용해볼수록 점점 ZeroMQ + Protobuf를 통한 분산 메시징은 꽤나 매력이 있는 조합임을 깨닫게 됩니다.

Comments