Apache Avro 与 Thrift 比较
http://www.tbdata.org/archives/1307
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的优势在于更多的语言支持和相对成熟
Apache Avro 与 Thrift 比较的更多相关文章
- Apache Avro:一个新的数据交换格式
原文: http://blog.cloudera.com/blog/2009/11/avro-a-new-format-for-data-interchange/ 注:由于个人英语能力有限,翻译不准确 ...
- java.lang.NoClassDefFoundError: org/apache/avro/ipc/Responder
文章发自:http://www.cnblogs.com/hark0623/p/4170174.html 转发请注明 java.lang.NoClassDefFoundError: org/a ...
- Apache Avro# 1.8.2 Specification (Avro 1.8.2规范)二
h5 { text-indent: 0.71cm; margin-top: 0.49cm; margin-bottom: 0.51cm; direction: ltr; color: #000000; ...
- Apache Avro# 1.8.2 Specification (Avro 1.8.2规范)一
h4 { text-indent: 0.71cm; margin-top: 0.49cm; margin-bottom: 0.51cm; direction: ltr; color: #000000; ...
- 异常-CDH的service无法启动并抛出异常-org.apache.avro.AvroRemoteException: java.net.ConnectException: Connection refused (Connection refused)
1 详细异常 org.apache.avro.AvroRemoteException: java.net.ConnectException: Connection refused (Connectio ...
- Hadoop基础-Apache Avro串行化的与反串行化
Hadoop基础-Apache Avro串行化的与反串行化 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Apache Avro简介 1>.Apache Avro的来源 ...
- 使用Zeppelin时出现at org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService$Client.recv_getFormType(RemoteInterpreterService.java:288)错误的解决办法(图文详解)
不多说,直接上干货! 问题详解 org.apache.thrift.TApplicationException: Internal error processing getFormType at or ...
- Hadoop-异常-Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/avro/io/DatumReader
//maven org.apache.avr 下载不完全 ,去maven If you are using maven to build your jar, you need to add the ...
- Apache Avro总结
参考 Apache Avro™ 1.9.0 Specification Avro介绍 小而巧的数字压缩算法:zigzag 原始类型(Primitive Types) 类型名 描述 描述 二进制编码 ...
随机推荐
- 采用软件nginx实现web服务器集群
nginx:软件负载均衡器 是高并发量http/反向代理服务器.实现windows下IIS的负载均衡 条件:2台服务器 1.cpu:Inter(R) 酷睿 i5 cpu 2.26GHz 内存:2G ...
- Web.config配置文件详解(新手必看)
花了点时间整理了一下ASP.NET Web.config配置文件的基本使用方法.很适合新手参看,由于Web.config在使用很灵活,可以自定义一些节点.所以这里只介绍一些比较常用的节点. <? ...
- [c#美味] Guid ToString 格式知多少?
在日常编程中,Guid是比较常用的,最常见的使用就是如下所示: string id = Guid.NewGuid().ToString(); 这条语句会生成一个新的Guid并转成字符串,如下: // ...
- js获取本月第几周和本年第几周
var getMonthWeek = function (a, b, c) { /* a = d = 当前日期 b = 6 - w = 当前周的还有几天过完(不算今天) a + b 的和在除以7 就是 ...
- 【译】Selenium 2.0 WebDriver
Selenium WebDriver 注意:我们正致力于完善帮助指南的每一个章节,虽然这个章节仍然存在需要完善的地方,不过我们坚信当前你看到的帮助信息是精确无误的,后续我们会提供更多的指导信息来完 ...
- Bootstrap基本使用[转]
Bootstrap是Twitter推出的一个由动态CSS语言Less写成的开源CSS/HTML框架(同时提供Sass 移植版代码).Bootstrap提供了全面的基本及组件样式并自带了13个jQuer ...
- 通过DeveloperApi获取spark程序执行进度及异常
在应用spark时,经常要获取任务的执行进度,可以参照jobProgressListener的设计来完成该功能. 以下代码仅供参考,欢迎交流. 效果显示: 代码: package org.apache ...
- Tsinsen A1517. 动态树 树链剖分,线段树,子树操作
题目 : http://www.tsinsen.com/A1517 A1517. 动态树 时间限制:3.0s 内存限制:1.0GB 总提交次数:227 AC次数:67 平均分:49. ...
- WordPress模版结构
一套完整的WordPress模版应至少包括如下文件: style.css : 样式表文件 index.php : 首页模板 archive.php : 文章归档/分类目录模板 404.php : 40 ...
- Storm系列(五)架构分析之Nimbus启动过程
启动流程图 mk-assignments 功能:对当前集群中所有Topology进行新一轮的任务调度. 实现源码路径: \apache-storm-0.9.4\storm-core\src\clj ...