技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> Apache --> Apache Avro 与 Thrift 比较

Apache Avro 与 Thrift 比较

浏览:4362次  出处信息

    Avro和Thrift都是跨语言,基于二进制的高性能的通讯中间件. 它们都提供了数据序列化的功能和RPC服务. 总体功能上类似,但是哲学不一样. Thrift出自Facebook用于后台各个服务间的通讯,Thrift的设计强调统一的编程接口的多语言通讯框架. Avro出自Hadoop之父Doug Cutting, 在Thrift已经相当流行的情况下Avro的推出,其目标不仅是提供一套类似Thrift的通讯中间件更是要建立一个新的,标准性的云计算的数据交换和存储的Protocol。 这个和Thrift的理念不同,Thrift认为没有一个完美的方案可以解决所有问题,因此尽量保持一个Neutral框架,插入不同的实现并互相交互。而Avro偏向实用,排斥多种方案带来的 可能的混乱,主张建立一个统一的标准,并不介意采用特定的优化。Avro的创新之处在于融合了显式,declarative的Schema和高效二进制的数据表达,强调数据的自我描述,克服了以往单纯XML或二进制系统的缺陷。Avro对Schema动态加载功能,是Thrift编程接口所不具备的,符合了Hadoop上的Hive/Pig及NOSQL 等既属于ad hoc,又追求性能的应用需求.

语言绑定

    目前阶段Thrift比Avro支持的语言更丰富.

    Thrift: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk.

    Avro: C, C++, Java, Python, Ruby, PHP.

数据类型

    从常见的数据类型的角度来说, Avro和Thrift非常接近,功能上并没有什么区别。

Avro Thrift
基本类型

    true or false

N/A 8-bit signed integer
N/A I16 16-bit signed integer
int I32 32-bit signed integer
long I64 64-bit signed integer
float N/A 32-bit floating point
double double 64-bit floating point
bytes binary Byte sequence
string string Character sequence
复杂类型
record struct 用户自定义类型
enum enum
array list
N/A set
map map Avro map的key

    必须是string

union union
fixed N/A 固定大小的byte array

e.g. md5(16);
RPC服务
protocol service RPC服务类型
error exception RPC异常类型
namespace namespace 域名

开发流程

    从开发者角度来说,Avro和Thrift也相当类似,

    1) 同一个服务分别用Avro和Thrift来描述

    Avro.idl:

    protocol SimpleService {

    record Message {

    string topic;

    bytes content;

    long createdTime;

    string id;

    string ipAddress;

    map props;

    }

    int publish(string context,array messages);

    }

    Thrift.idl:

    struct Message {

    1: string topic

    2: binary content

    3: i64 createdTime

    4: string id

    5: string ipAddress

    6: map props

    }

    service SimpleService {

    i32 publish(1:string context,2:list messages);

    }

    2) Avro和Thrift都支持IDL代码生成功能

    java idl avro.idl idl.avro

    java org.apache.avro.specific.SpecificCompiler idl.avro avro-gen

    目标目录生成Message.java和SimpleService.java

    thrift -gen java thrift.idl

    同样的,目标目录生成Message.java和SimpleService.java

    3) 客户端代码

    Avro client :

    URL url = new URL ( “http”, HOST, PORT, “/”);

    Transceiver trans = new HttpTransceiver(url);

    SimpleService proxy=

    = (SimpleService)SpecificRequestor.getClient(SimpleService.class, transceiver);

    …

    Thrift client :

    TTransport transport = new TFramedTransport(new TSocket(HOST,PORT));

    TProtocol protocol = new TCompactProtocol(transport);

    transport.open();

    SimpleService.Client client = new SimpleService.Client(protocol);

    …

    4) 服务器端 Avro和Thrift都生成接口需要实现:

    Avro server:

    public static class ServiceImpl implements SimpleService {

    ..

    }

    Responder responder = new SpecificResponder(SimpleService.class, new ServiceImpl());

    Server server = new HttpServer(responder, PORT);

    Thrift server:

    public static class ServerImpl implements SimpleService.Iface {

    ..

    }

    TServerTransport serverTransport=new TServerSocket(PORT);

    TServer server=new TSimpleServer(processor,serverTransport,new TFramedTransport.Factory(), new TCompactProtocol.Factory());

    server.serve();

Schema处理

    Avro和Thrift处理Schema方法截然不同。

    Thrift是一个面向编程的系统, 完全依赖于IDL->Binding Language的代码生成。 Schema也“隐藏”在生成的代码中了,完全静态。为了让系统识别处理一个新的数据源,必须走编辑IDL,代码生成,编译载入的流程。

    

    与此对照,虽然Avro也支持基于IDL的Schema描述,但Avro内部Schema还是显式的,存在于JSON格式的文件当中,Avro可以把IDL格式的Schema转化成JSON格式的。

    Avro支持2种方式。Avro-specific方式和Thrift的方式相似,依赖代码生成产生特定的类,并内嵌JSON Schema. Avro-generic方式支持Schema的动态加载,用通用的结构(map)代表数据对象,不需要编译加载直接就可以处理新的数据源。

    

Serialization

    对于序列化Avro制定了一个协议,而Thrift的设计目标是一个框架,它没有强制规定序列化的格式。

    Avro规定一个标准的序列化的格式,即无论是文件存储还是网络传输,数据的Schema(in JASON)都出现在数据的前面。数据本身并不包含任何Metadata(Tag). 在文件储存的时候,schema出现在文件头中。在网络传输的时候Schema出现在初始的握手阶段.这样的好处一是使数据self describe,提高了数据的透明度和可操作性,二是减少了数据本身的信息量提高存储效率,可谓一举二得了

    

    Avro的这种协议提供了很多优化的机会:

对数据作Projection,通过扫描schema只对感兴趣的部分作反序列化。支持schema的versioning和mapping ,不同的版本的Reader和Writer可以通过查询schema相互交换数据(schema的aliases支持mapping),这比thrift采用的给每个域编号的方法优越多了

    Avro的Schema允许定义数据的排序Order并在序列化的时候遵循这个顺序。这样话不需要反序列化就可以直接对数据进行排序,在Hadoop里很管用.

    另外一个Avro的特性是采用block链表结构,突破了用单一整型表示大小的限制。比如Array或Map由一系列Block组成,每个Block包含计数器和对应的元素,计数器为0标识结束。

    

    Thrift提供了多种序列化的实现:

    TCompactProtocol: 最高效的二进制序列化协议,但并不是所有的绑定语言都支持。

    TBinaryProtocol: 缺省简单二进制序列化协议.

    与Avro不同,Thrift的数据存储的时候是每个Field前面都是带Tag的,这个Tag用于标识这个域的类型和顺序ID(IDL中定义,用于Versioning)。在同一批数据里面,这些Tag的信息是完全相同的,当数据条数大的时候这显然就浪费了。

    

RPC服务

    Avro提供了

    HttpServer : 缺省,基于Jetty内核的服务.

    NettyServer: 新的基于Netty的服务.

    Thrift提供了:

    TThreadPolServer: 多线程服务

    TNonBlockingServer: 单线程 non blocking的服务

    THsHaServer: 多线程 non blocking的服务

Benchmarking

    测试环境:2台4核 Intel Xeon 2.66GHz, 8G memory, Linux, 分别做客户端,服务器。

    Object definition:

    record Message {

    string topic;

    bytes payload;

    long createdTime;

    string id;

    string ipAddress;

    map props;

    }

    Actual instance:

    msg.createdTime : System.nanoTime();

    msg.ipAddress : “127.0.0.1″;

    msg.topic : “pv”;

    msg.payload : byte[100]

    msg.id : UUID.randomUUID().toString();

    msg.props : new HashMap();

    msg.props.put(“author”, “tjerry”);

    msg.props.put(“date”, new Date().toString());

    msg.props.put(“status”, “new”);

    Serialization size

    

    Avro的序列化产生的结果最小

    Serialization speed

    

    Thrift-binary因为序列化方式简单反而看上去速度最快.

    Deserialization speed

    

    这里 Thrift的速度很快, 因与它内部实现采用zero-copy的改进有关.不过在RPC综合测试里这一优势

    似乎并未体现出来.

    序列化测试数据采集利用了http://code.google.com/p/thrift-protobuf-compare/所提供的框架,

    原始输出:

    Starting

    , Object create, Serialize, /w Same Object, Deserialize, and Check Media, and Check All, Total Time, Serialized Size

    avro-generic , 8751.30500, 10938.00000, 1696.50000, 16825.00000, 16825.00000, 16825.00000, 27763.00000, 221

    avro-specific , 8566.88000, 10534.50000, 1242.50000, 18157.00000, 18157.00000, 18157.00000, 28691.50000, 221

    thrift-compact , 6784.61500, 11665.00000, 4214.00000, 1799.00000, 1799.00000, 1799.00000, 13464.00000, 227

    thrift-binary , 6721.19500, 12386.50000, 4478.00000, 1692.00000, 1692.00000, 1692.00000, 14078.50000, 273

    RPC测试用例:

    客户端向服务器发送一组固定长度的message,为了能够同时测试序列和反序列,服务器收到后将原message返回给客户端.

    array publish(string context, array messages);

    测试使用了Avro Netty Server和 Thrift HaHa Server因为他们都是基于异步IO的并且适用于高并发的环境。

    结果

    

    

    从这个测试来看,再未到达网络瓶颈前,Avro Netty比Thrift HsHa服务提供了更高的吞吐率和更快的响应,另外 avro占用的内存高些。

    通过进一步实验,发现不存在绝对的Avro和Thrift服务哪一个更快,决定于给出的test case,或者说与程序的用法有关,比如当前测试用例是Batch模式,大量发送fine grained的对象(接近后台tt,hadoop的用法),这个情况下Avro有优势. 但是对于每次只传一个对象的chatty客户端,情况就出现逆转变成Thrift更高效了.还有当数据结构里blob比例变大的情况下,Avro和Thrift的差别也在减小.

Conclusion

Thrift适用于程序对程序静态的数据交换,要求schema预知并相对固定。 Avro在Thrift基础上增加了对schema动态的支持且性能上不输于Thrift。 Avro显式schema设计使它更适用于搭建数据交换及存储的通用工具和平台,特别是在后台。 目前Thrift的优势在于更多的语言支持和相对成熟。

建议继续学习:

  1. Linux大棚版Thrift入门教程    (阅读:23409)
  2. HBase Thrift 接口使用注意事项    (阅读:5278)
  3. 中间件和稳定性平台    (阅读:5229)
  4. hadoop rpc机制 && 将avro引入hadoop rpc机制初探    (阅读:5053)
  5. Thrift简析    (阅读:4804)
  6. php实现的thrift socket server    (阅读:3519)
  7. 2012年数据库技术大会 百度和淘宝介绍的中间件对比    (阅读:3013)
  8. 国内互联网公司数据库访问层调查    (阅读:3013)
  9. Thrift Message deserialize 方法的一个缺点及改进    (阅读:2762)
  10. 在你的应用中添加 JSONP 的支持    (阅读:2142)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1