태그 : ProtocolBuffers와Thrift비교
2010/03/30   직렬화 방법, Facebook의 Thrift와 Protocol Buffers의 비교. [3]
직렬화 방법, Facebook의 Thrift와 Protocol Buffers의 비교.

Thrift는 Facebook의 직렬화 방법이다. 2010년 3월 현재 apache의 인큐베이팅 프로젝트로 등록되어 있다. 전 구굴의 개발자가 만들었다고 하고 Protocol Buffers와 무척 유사하다. 하며, 다음과 같은 차이점이 있다.

- java API가 좀더 깔끔하다.
    - 별도의 setter, getter없이 필드에 직접 접근
    - 별도의 read only의 Message와 read & write의 Builder의 구분이 없다.
- c++의 경우 생성된 코드는 정의한 필드의 소대문자가 전부 소문자로 변하는데 반해 Thrift는 소대문자가 보존된다.
    - Protocol Buffers : message->set_myname(2);
    - Thrift : message->myName = 2;
- Protocol Buffers는 필드의 List만 지원하는데 반해 Thrift는 Set, Map, List를 지원한다.
- RPC 인터페이스 정의에 의한 구현코드가 자동생성된다. 서버, 클라이언트 코드의 작성이 쉽다.


이외의 것은 Protocol Buffers와 거의 똑같다.

장단점을 비교하면 다음과 같다.

Protocol Buffers
    - 장점
        - Thrfit에 비해 빠르다.(3배정도)
    - 단점
        - java의 경우 Message, Builder로 분리되어 있고, Builder를 사용한 코드가 다소 지저분하다.
        - List만 처리 가능(과연 단점일까?)

Thrift        
    - 장점
        - List, Set, Map 지원
    - 단점
        - c++의 경우 메시지가 다른 메시지 필드의 타입일 경우 손수 생성, 파괴하여야 한다.
        - 문서가 거의 없다. 샘플도 거의 없다.
        - 윈도우에서는 컴파일러를 컴파일하기 까다롭다.
        - 자동 생성된 c++코드는 windows에서는 사용하지 못한다.


기타 특징은 다음과 같다.

    - c++, c#, cocoa, java, perl, php, python, ruby를 지원한다.

    - Apache License 2.0

    - 상수와 enum을 지원

    - 하위 호환

    - 서비스의 상속 가능

    - 비동기시 서비스 지원

    - 예외 지원

성능 테스트

두가지 사이즈의 데이타에 대하여 테스트 하였다.
인코딩된 사이즈의 크기는 Protocol Buffers가 34, 1234 byte였으며 Thrift는 174, 1504 byte 였다.
c++의 경우 처리 건수는 Protocol Buffers가 초당 130만회, 11만회였으며, Thrift는 초당 36만회, 8만회였다.
java의 경우 처리 건수는 Protocol Buffers가 초당 87만회, 6만회 였으며, Thrift는 초당 14만회, 4만회였다.


코드 샘플

- c structure

 typedef struct Css {
  int srcCSID;
  int newCSID;
 } Css;
 
 typedef struct Leg{
  int srcCSID;
  int newCSID;
  int srcLegID;
  int newLegID;
 } Leg;
 
 typedef struct StringValue {
  int length;
  char* str;
 } StringValue;

 typedef struct Messsage {
  int result;
  int vcID;
  int srcCSAID;
  int targetCSAID;
  Css[] csses;
  Leg[] legs;
  StringValue serviceID;
 } Message;

 

- Protocol Buffers definition

 message Css {
  optional uint32 srcCSID = 1;
  optional uint32 newCSID = 2;
 }

 message Leg {
  optional uint32 srcCSID = 1;
  optional uint32 newCSID = 2;
  optional uint32 srcLegID = 3;
  optional uint32 newLegID = 4;
 }
 
 message StringValue {
  optional uint32 length = 1;
  optional string str = 2;
 }

 message Message {
  optional uint32 result = 1;
  optional uint32 vcID = 2;
  optional uint32 srcCSAID = 3;
  optional uint32 targetCSAID = 4;
  repeated Css css = 5;
  repeated Leg leg = 6;
  optional StringValue serviceID = 7;
 }

 

- Thrift definition

 struct Css {
  1: i64 srcCSID,
  2: i64 newCSID
 }

 struct Leg {
  1: i64 srcCSID,
  2: i64 newCSID
  3: i64 srcLegID,
  4: i64 newLegID
 }

 struct StringValue {
  1: i64 length,
  2: string str
 }
 
 struct Message {
  1: i64 result,
  2: i64 vcID,
  3: i64 srcCSAID,
  4: i64 targetCSAID,
  5: list<Css> csses,
  6: list<Leg> legs
  7: StringValue serviceID
 } 



 - c++ - Protocol Buffers

 ShortTasMessage::Message* message = new ShortTasMessage::Message();

 message->set_result(100);
 message->set_vcid(9);
 message->set_srccsaid(1);
 message->set_targetcsaid(2);

 ShortTasMessage::Css* css = message->add_css();
 css->set_srccsid(1);
 css->set_newcsid(2);

 ShortTasMessage::Leg* leg0 = message->add_leg();
 leg0->set_srccsid(1);
 leg0->set_newcsid(2);
 leg0->set_srclegid(1);
 leg0->set_newlegid(3);

 ShortTasMessage::Leg* leg1 = message->add_leg();
 leg1->set_srccsid(1);
 leg1->set_newcsid(2);
 leg1->set_srclegid(2);
 leg1->set_newlegid(4);
 
 LongTasMessage::StringValue* serviceID = message->mutable_serviceid();
 serviceID->set_length(3); 
 serviceID->set_str("CHD");


  
c++ - Thrift

 ShortTasMessage::Message* message = new ShortTasMessage::Message();

 message->result = 100;
 message->vcID = 9;
 message->srcCSAID = 1;
 message->targetCSAID = 2;

 ShortTasMessage::Css* css = new ShortTasMessage::Css();
 css->srcCSID = 1;
 css->newCSID = 2;
 message->csses.push_back(*css);  // csses is List
 delete css; css = NULL;

 ShortTasMessage::Leg* leg0  = new ShortTasMessage::Leg();
 leg0->srcCSID = 1;
 leg0->newCSID = 2;
 leg0->srcLegID = 1;
 leg0->newLegID = 3;
 message->legs.push_back(*leg0);
 delete leg0; leg0 = NULL;

 ShortTasMessage::Leg* leg1  = new ShortTasMessage::Leg();
 leg1->srcCSID = 1;
 leg1->newCSID = 2;
 leg1->srcLegID = 2;
 leg1->newLegID = 4;
 message->legs.push_back(*leg1);
 delete leg1; leg1 = NULL;
 
 message->serviceID.length = 3;
 message->serviceID.str = "CHD"; 



java - protocol buffers

 ShortTasMessage.Message.Builder message = ShortTasMessage.Message.newBuilder();

 message.setResult(100);
 message.setVcID(9);
 message.setSrcCSAID(1);
 message.setTargetCSAID(2);
 
 ShortTasMessage.Css.Builder css = ShortTasMessage.Css.newBuilder();
 css.setSrcCSID(1);
 css.setNewCSID(2);
 message.addCss(css);

 ShortTasMessage.Leg.Builder leg0 = ShortTasMessage.Leg.newBuilder();
 leg0.setSrcCSID(1);
 leg0.setNewCSID(2);
 leg0.setSrcLegID(1);
 leg0.setNewLegID(3);
 message.addLeg(leg0);

 ShortTasMessage.Leg.Builder leg1 = ShortTasMessage.Leg.newBuilder();
 leg1.setSrcCSID(1);
 leg1.setNewCSID(2);
 leg1.setSrcLegID(2);
 leg1.setNewLegID(4);
 message.addLeg(leg1);
 
 LongTasMessage.StringValue.Builder serviceID = LongTasMessage.StringValue.newBuilder();
 serviceID.setLength(3);
 serviceID.setStr("CHD");
 message.setServiceID(serviceID);


  

java - Thrift  

 ShortTasMessage.Message message = new ShortTasMessage.Message();

 message.setResult(100);
 message.setVcID(9);
 message.setSrcCSAID(1);
 message.setTargetCSAID(2);

 ShortTasMessage.Css css = new ShortTasMessage.Css();
 css.setSrcCSID(1);
 css.setNewCSID(2);
 message.addToCsses(css);

 ShortTasMessage.Leg leg0 = new ShortTasMessage.Leg();
 leg0.setSrcCSID(1);
 leg0.setNewCSID(2);
 leg0.setSrcLegID(1);
 leg0.setNewLegID(3);
 message.addToLegs(leg0);

 ShortTasMessage.Leg leg1 = new ShortTasMessage.Leg();
 leg1.setSrcCSID(1);
 leg1.setNewCSID(2);
 leg1.setSrcLegID(2);
 leg1.setNewLegID(4);
 message.addToLegs(leg1);
 
 LongTasMessage.StringValue serviceID = new LongTasMessage.StringValue();
 serviceID.setLength(3);
 serviceID.setStr("CHD");
 message.setServiceID(serviceID); 




Reference

demo client code
     http://www.google.co.kr/codesearch/p?hl=ko#W9kbJs3X16M/trunk/src/examples/thrift/DemoClient.cpp&q=TBinaryProtocol&d=4 
benchmark of thrift
    http://www.google.co.kr/codesearch/p?hl=ko#NPWGicy0Ryg/trunk/test/Benchmark.cpp&q=TBinaryProtocol%20lang:c%2B%2B&sa=N&cd=9&ct=rc
Simple tutorial
    http://skorage.org/2009/03/08/simple-thrift-tutorial/
  

by 어플로잇 | 2010/03/30 12:19 | IT | 트랙백(3) | 덧글(3)
< 이전페이지 다음페이지 >