관리 메뉴

HAMA 블로그

쓰리프트 (Apache Thrift) 의 모든것 (1) - (번역) 본문

오픈소스, 미들웨어

쓰리프트 (Apache Thrift) 의 모든것 (1) - (번역)

[하마] 이승현 (wowlsh93@gmail.com) 2015. 7. 8. 11:13

https://thrift.apache.org/


아파치 쓰리프트 프레임워크는 다양한 언어로 서비스되며 , 효율적인 코드생성엔진을 갖고 소프트웨어 스택을 묶으며 다음과 같은 다양한 언어들을 지원한다  C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and 기타등등.


시작하기 

  • Apache Thrift 다운로드 

    To get started, download a copy of Thrift.

  • Apache Thrift compiler 빌드/인스톨

    You will then need to build the Apache Thrift compiler and install it. See the installing Thrift guide for any help with this step.

  •  .thrift 파일 작성 

    After the Thrift compiler is installed you will need to create a thrift file. This file is an interface definitionmade up of thrift types and Services. The services you define in this file are implemented by the server and are called by any clients. The Thrift compiler is used to generate your Thrift File into source code which is used by the different client libraries and the server you write. To generate the source from a thrift file run

                thrift --gen <language> <Thrift filename>
              

    The sample tutorial.thrift file used for all the client and server tutorials can be found here.


To learn more about Apache Thrift Read the Whitepaper



예제 


아파치 쓰리프트는 데이타타입 및 서비스 인터페이스를  간단한 정의파일안에 제공한다.파일을 통해 입력하면 

컴파일러는 교차언어간에 자연스럽게 통신할수있는  RPC 클라이언트/서버로  쉽게 사용되는 코드를 생성해준다. 

당신이 만든 객체를 이동하거나 직렬화 하기위해 행사코드를 쓰는 수고를 덜어주며, 원격메소드를 호출하여 당신이 

비지니스로직에만 집중할수있게한다.

다음 예제는 웹프런트엔드에 대해  유저객체를 저장하기위한 간단한 서비스를 보여준다.


쓰리프트 정의 파일 

service Calculator extends shared.SharedService { /** * 메소드 정의는 C 코드같다. 리턴타입 과 매개변수 , 예외를 가지고있다. * Note that argument * lists and exception lists are specified using the exact same syntax as * field lists in struct or exception definitions. */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * 단방향 콜로써 요청한후에 리턴받는걸 무시한다. */ oneway void zip()


파이썬 클라이언트 

 # 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 = Calculator.Client(protocol)

  # Connect!
  transport.open()

  client.ping()
  print 'ping()'

  sum = client.add(1,1)
  print '1+1=%d' % (sum)



자바 서버 


Initialize the Server:

    try {
      TServerTransport serverTransport = new TServerSocket(9090);
      TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

      // Use this for a multithreaded server
      // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));

      System.out.println("Starting the simple server...");
      server.serve();
    } catch (Exception e) {
      e.printStackTrace();
    }


The CalculatorHandler:

public class CalculatorHandler implements Calculator.Iface {

  private HashMap<Integer,SharedStruct> log;

  public CalculatorHandler() {
    log = new HashMap<Integer, SharedStruct>();
  }

  public void ping() {
    System.out.println("ping()");
  }

  public int add(int n1, int n2) {
    System.out.println("add(" + n1 + "," + n2 + ")");
    return n1 + n2;
  }

  public int calculate(int logid, Work work) throws InvalidOperation {
    System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})");
    int val = 0;
    switch (work.op) {
    case ADD:
      val = work.num1 + work.num2;
      break;
    case SUBTRACT:
      val = work.num1 - work.num2;
      break;
    case MULTIPLY:
      val = work.num1 * work.num2;
      break;
    case DIVIDE:
      if (work.num2 == 0) {
        InvalidOperation io = new InvalidOperation();
        io.what = work.op.getValue();
        io.why = "Cannot divide by 0";
        throw io;
      }
      val = work.num1 / work.num2;
      break;
    default:
      InvalidOperation io = new InvalidOperation();
      io.what = work.op.getValue();
      io.why = "Unknown operation";
      throw io;
    }

    SharedStruct entry = new SharedStruct();
    entry.key = logid;
    entry.value = Integer.toString(val);
    log.put(logid, entry);

    return val;
  }

  public SharedStruct getStruct(int key) {
    System.out.println("getStruct(" + key + ")");
    return log.get(key);
  }

  public void zip() {
    System.out.println("zip()");
  }

}

<장점>

- 버전닝 지원
- 여러 언어에서 사용 가능하며 언어에 맞도록 소스가 생성되고, 언어간의 Serialization 가능
- Sync, Async Server API 제공
- XML 설정이 필요 없음
- Layer에 맞는 Interface를 사용 및 Customizing 구축 가능
- RPC 기능 제공 (Google Protocol Buffer에는 없는 기능)
- 서버 기능 좋음
   -- 서블릿 제공(org.apache.thrift.server.TServlet)
   -- 멀티쓰레드 지원 (org.apache.thrift.server.ThreadPoolServer : worker thread 지정)
   -- Async 지원 (org.apache.thrift.server. TNonblockingServer : single threaded)
   -- Multi-thread Half-Sync/Half-Async지원 : org.apache.thrift.server. THsHaServer
   -- Exception을 제공 (Google Protocol Buffer에는 없는 기능)
   -- Set, Map 지원 (Google Protocol Buffer에는 없는 기능)

 


 <단점>

- 자바로 코드가 생성될 때, Slf4j를 기본적으로 가지고 가며, 내부 코드는 모두 thrift lib가 필요함
- C++의 Server threading part는 Boost에 의존을 가짐
- 자바 쪽 이클립스 플러그인 없음
- Thrift lib의 api가 자주 바뀌어서, 버전 업마다 소스를 좀 보고 코딩해야 함. (인터넷 예제가 거의 없음)
   인터넷 예제랑 달라서, 컴파일 에러 안나게 하는게 귀찮음...
- XML Serialization/Deserialization 기능 없음
- 문서가 확실히 적음 (허허~)
- 생성된 코드가 Google Protocol Buffer에 비해서 보기는 편하지는 않음 (특히 C++)


http://knight76.tistory.com/1426  펌 



Comments