`

(转)Apache Avro 与 Thrift 比较

阅读更多

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<T> list<T>
N/A set<T>
map<string,T> map<T1,T2> 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<string> props;

}

int publish(string context,array<Message> messages);

}

Thrift.idl:

struct Message {

1: string topic

2: binary content

3: i64    createdTime

4: string id

5: string ipAddress

6: map<string,string> props

}

service SimpleService {

i32 publish(1:string context,2:list<Message> 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<string,string > 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<String,String>();

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<Message> publish(string context, array<Message> 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的优势在于更多的语言支持和相对成熟。

 

分享到:
评论

相关推荐

    BaijiSerializer4J:受 Apache Avro 和 Thrift 启发的用于 Java 的 Baiji 序列化器

    BaijiSerializer4J 是一个专为 Java 平台设计的序列化库,其设计理念受到了 Apache Avro 和 Apache Thrift 的启发。这两个开源项目都是为了解决跨语言数据交换的问题,提供了高效的序列化和反序列化机制。...

    protobuf/thrift/avro-序列化性能测试工程

    与protobuf类似,thrift也需要定义接口描述文件(IDL),然后使用thrift编译器生成客户端和服务端代码。 avro是Apache Hadoop项目的一部分,设计用于大数据处理。avro提供了一种紧凑、高效的二进制数据格式,同时...

    Thrift和Avro实例

    与Thrift类似,Avro也使用JSON格式定义数据模式(Schema),然后生成各种编程语言的API。Avro的一个显著特点是它支持动态Schema,允许在不兼容的Schema之间进行数据交换。此外,Avro还提供了数据版本控制机制,确保...

    thrift和avro研究资料1

    Thrift和Avro是两种广泛使用的数据序列化和远程过程调用(RPC)框架,它们在分布式系统中扮演着重要角色。本文将详细介绍这两种技术及其关键特性。 首先,让我们了解Thrift。Thrift是由Facebook开发的一种跨语言的...

    java序列化源码-share-generate-sources:Java源码生成以及序列化和反序列化技术:avro|thrift|proto

    源码生成通过指定格式的文本文件进行解析生成以及序列化和反序列化技术:avro|thrift|protobuf 一、avro技术 1.maven配置 &lt;avro&gt;1.8.2&lt;/avro&gt; &lt;groupId&gt;org.apache.avro &lt;artifactId&gt;avro-tools ${avro.version}...

    avro-thrift-1.10.1.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.10.1/java

    avro-thrift-1.9.2.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.9.2/java

    avro-thrift-1.9.2-javadoc.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.9.2/java

    avro-thrift-1.9.2-sources.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.9.2/java

    avro-thrift-1.10.1-sources.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.10.1/java

    avro-thrift-1.10.1-javadoc.jar

    Apache Avro是一个数据序列化系统。avro/avro-1.10.1/java

    Apache Hadoop---Avro.docx

    在序列化系统的选择上,Avro 与 Google 的 Protocol Buffers 和 Facebook 的 Thrift 等系统有所不同。虽然这些系统在某些场景下表现出色,但它们各自存在一定的局限性。例如,Protocol Buffers 需要预先定义数据结构...

    Apache RPC调用实例

    Apache提供了多种RPC实现,如Apache Thrift、Apache Avro和Hadoop的RPC等。 **Apache Thrift** Apache Thrift是一种软件框架,用于构建可伸缩的、跨语言的服务。它将服务定义为接口定义语言(IDL),允许开发者...

    avro-doc-1.7.7

    Avro与Protobuf、Thrift等序列化工具相比,更强调Schema,这使得其在数据交换和数据持久化方面有优势。而与JSON相比,Avro的数据文件通常更小,读写速度更快。 7. **集成与使用** Avro可以方便地集成到各种Hadoop...

    apache-flume-1.8.0-bin.tar.gz

    在 Flume 1.8.0 中,可能包含的源类型有 Avro、Thrift、HTTP、Taildir 和 JMS 等。 通道则作为一个临时存储,用于在源和接收器之间安全地传输数据。Flume 提供了内存通道(Memory Channel)和文件通道(File ...

    RPC调用框架比较分析

    本篇文章将对几种常见的RPC框架进行比较分析,包括Protobuf RPC、Avro和Thrift,探讨它们的特点、优缺点以及适用场景。 1. Protobuf RPC(Protocol Buffers Remote Procedure Call) - **Protobuf** 是Google开发...

    Flume核心思想与解密

    Apache flume是一个分布式、可靠...因为数据源是可定制的(内置Avro,Thrift Syslog,Netcat),Flume可以用于传输大量事件数据,包括但不限于网络流量数据、社交媒体生成的数据、电子邮件消息和几乎所有可能的数据源。

    apache-flume1.8

    1. **多种数据源支持**:Flume 支持多种类型的数据源,包括 HTTP、Avro、Thrift、Kafka 和 Syslog,这使得它能够从不同类型的系统中收集数据。 2. **高可用性**:通过复制通道(Replicating Channel)和故障切换...

    Kafka-MySQL-Avro:Kafka Consumer将avro记录插入mysql

    Kafka-MySQL-Avro Kafka Consumer将avro记录插入mysql ... 在包括Thrift,协议缓冲区和Avro在内的串行化框架的新兴需求中,既需要一种解决方案来满足我们作为需求方平台的需求,又需要一种协议框架也可用于OpenRTB市

Global site tag (gtag.js) - Google Analytics