데이터 엔지니어 기술 블로그

[Apache Thrift] 아파치 쓰리프트 간단하게 이해하기 본문

데이터 엔지니어링

[Apache Thrift] 아파치 쓰리프트 간단하게 이해하기

jun_yeong_park 2022. 1. 20. 00:04
반응형

개요

아파치 쓰리프트는 페이스북에서 서로 다른 언어간의 통신을 위하여 개발되었다.

원격 프로시저 호출(Remote Procedure Call)로 언어에 상관 없이 서로 통신할 수 있도록 도와준다. 예를 들면 PHP에서 작성한 기능을 파이썬과 Go언어에서 자유롭게 호출해서 사용할 수 있다. 단순히 하나의 함수 호출이 아니라, REST API 서버처럼 자유롭게 개발을 할 수 있다.

 

thrift와 호환되는 언어들은 모두 비슷하지만 각자 다른 인터페이스 정의 규칙을 가지고 있다. 아파치 쓰리프트에서는 .thrift 파일에 변수의 타입과 이름 그리고 함수의 매개변수, 반환값과 예외 등의 정의를 하고, thrift를 사용하여 옵션으로 변환하려는 언어를 적어주면 .thrift 파일에 입력된 정의로 각 언어에 맞게 코드를 생성해준다.

thrift -r --gen py sample.thrift

 

현재 지원되는 대표적인 언어는 다음과 같은 것들이 있다.

  • C++, C#, D, Dart, Delphi, Go, Java, Javascript, .NET, Node.js, Perl, PHP, Python, Ruby

 

이 글에서는 Docker로 직접 thrift를 이해하기 위해 간단하게 실행해보려고 한다.

 

 

 

Thrift 도커로 간단하게 실행하기

 

Dockerfile 작성하기

OS 마다 설치하는 방법이 다르기 때문에 복잡하게 설치하지 않기 위해서 도커를 사용하려고 한다. apt-get install 부분은 thrift를 빌드하고 사용하기 위해 필요한 것들을 설치하는 부분이고 wget 이후 부분은 실제 thrift를 가져와서 설치하는 부분이다. 파일명으로 Dockerfile을 만들어서 붙여넣으면 된다.

FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Seoul

RUN apt-get update -y
RUN apt-get install wget -y

RUN apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config -y

RUN apt-get install python3 -y
RUN apt-get install python3-pip -y
RUN pip3 install six

WORKDIR /
RUN wget https://dlcdn.apache.org/thrift/0.15.0/thrift-0.15.0.tar.gz
RUN tar -xvf thrift-0.15.0.tar.gz
WORKDIR /thrift-0.15.0

RUN ./bootstrap.sh
RUN ./configure
RUN make install

 

Docker 빌드하기

아래의 명령어로 작성한 도커파일를 빌드한다.

docker build --tag sample-thrift .

 

 

Docker 실행하기

도커 컨테이너를 실행해서 들어간다. thrift -help 명령어로 잘 동작하는지 확인해본다. 그리고 아래에 작성해야하는 코드를 도커 안에서 작성하기 어렵다면 -v 로 볼륨을 공유하도록 한다.

docker run -it --rm --name sample-thrift sample-thrift bash

thrift --help

 

.thrift 파일 작성하기

공식 튜토리얼에서 핵심적인 부분만 가져와서 작성했다. 도커 컨테이너 내부에서 sample.thrift라는 파일명으로 작성한다.

const i32 LUCKYSEVEN = 7


service Sample {
    list<i32> add_random_number(1: list<i32> nums),

    i32 get_lucky_number(),

    i32 get_id(),

    oneway void set_id(1: i32 new_id)
}

용어설명

  • cosnt: 상수 정의
  • i32: 32bit integer
  • service: 서비스
  • list<i32>: i32 타입으로 이루어진 배열
  • oneway: 클라이언트에서 실행은 되지만 반환은 되지 않음
  • void: 빈 값

thrift types

bool: Boolean, one byte
i8: (byte) Signed 8-bit integer
i16: Signed 16-bit integer
i32: Signed 32-bit integer
i64: Signed 64-bit integer
double: 64-bit floating point value
string: String
binary: Blob (byte array)
map<t1,t2>: Map from one type to another
list<t1>: Ordered list of one type
set<t1>: Set of unique elements of one type

 

.thrift 파일로 파이썬 코드 생성하기

아까 실행했던 도커 컨테이너에서 아래의 명령어를 이용해 쓰리프트 파일을 실행한다.

thrift -r --gen py sample.thrift

 

 

server.py 파일 작성

.thrift 파일을 이용해 코드를 생성하면 아래와 같이 코드들이 생성된다. 이 코드들을 이용해서 서버 개발을 하면 된다.

thrift로 생성된 파이썬 코드

from glob import glob
import sys
import glob
import random
sys.path.append('gen-py')
sys.path.insert(0, glob.glob('/thrift-0.15.0/lib/py/build/lib*')[0])

from sample import Sample
from sample import constants
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

class SampleHandler():
    def __init__(self):
        self.id = 0
        
    def add_random_number(self, nums):
        return [random.randint(0, 100) + num for num in nums]
        
    def get_lucky_number(self):
        return constants.LUCKYSEVEN

    def get_id(self):
        self.id += 1
        return self.id

    def set_id(self, new_id):
        self.id = new_id


if __name__ == '__main__':
    handler = SampleHandler()
    processor = Sample.Processor(handler)
    transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()

    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

    print('Starting the server...')
    server.serve()
    print('done.')

 

 

 

client.py 파일 작성

이것도 마찬가지로 도커 컨테이너 내부에서 작성한다. 위에서 작성했던 서버에 요청을 보내서 결과값을 받는 코드이다.

import sys
import glob
sys.path.append('gen-py')
sys.path.insert(0, glob.glob('/thrift-0.15.0/lib/py/build/lib*')[0])

from sample import Sample

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol


def main():
    # Make socket
    transport = TSocket.TSocket('localhost', 9090)

    # Buffering is critical. Raw sockets are very slow
    transport = TTransport.TBufferedTransport(transport)

    # Wrap in a protocol
    protocol = TBinaryProtocol.TBinaryProtocol(transport)

    # Create a client to use the protocol encoder
    client = Sample.Client(protocol)

    # Connect!
    transport.open()

    
    print(client.add_random_number([1,2,3]))
    print(client.get_lucky_number())
    print(client.get_id())
    print(client.get_id())
    print(client.set_id(300))
    print(client.get_id())

    transport.close()


if __name__ == '__main__':
    main()

 

 

서버 실행하기

아래의 명령어로 서버를 실행한다.

python3 server.py

Starting the server... 라는 문구가 나오면 실행이 된 것이다.

root@472d8398301c:/share/sample# python3 server.py
Starting the server...

 

 

클라이언트에서 요청하기

아래의 명령어로 서버에 요청한다.

 python3 client.py

원하던 대로 결과값을 받을 수 있다.

[5, 18, 28]
7
302
303
None
301

 

반응형
Comments