Avro入门1–序列化与远程通信

来源:互联网 发布:java定义长整型变量a 编辑:程序博客网 时间:2024/06/05 06:42

转载自:http://www.javabloger.com/article/hadoop-avro-rpc-java.html


Avro是Hadoop中的一个子项目,也是Apache中一个独立的项目,Avro是一个基于二进制数据传输高性能的中间件。在Hadoop的其他项目中例如HBase(Ref)和Hive(Ref)的Client端与服务端的数据传输也采用了这个工具,Avro可以做到将数据进行序列化,适用于远程或本地大批量数据交互。
在传输的过程中Avro对数据二进制序列化后 节约数据存储空间 和 网络传输带宽。做个比方:有一个100平方的房子,本来能放100件东西,现在期望借助某种手段能让原有面积的房子能存放比原来多150件以上或者更多的东西,就好比数据存放在缓存中,缓存是精贵的,需要充分的利用缓存有限的空间,存放更多的数据。再例如网络带宽的资源是有限的,希望原有的带宽范围能传输比原来高大的数据量流量,特别是针对结构化的数据传输和存储,这就是Avro存在的意义和价值。

Avro还可以做到在同一系统中支持多种不同语言,也有点类似Apache的另一个产品:Thrift(Ref),对于Thrift不同的是Avro更加具有灵活性,Avro可以支持对定义的数据结构(Schema)动态加载,利于系统扩展。

使用Avro可以通过2中方式来实现:
1.二进制编码,Avro-specific方式依赖代码(文件)生成特定类,并内嵌JSON Schema;
2.JSON编码,Avro-generic方式通过JSON文件动态加载Schema,不需要编译加载直接就可以处理新的数据源。
我肤浅的认为,两者的区别在于同样的数据大小,在二进制编码下所产生的Avro数据的大小为100个字节,而在JSON编码下产生了450个字节。虽然看起来第1种二进制编码的方式占据一定优势,但是二进制传输最大的问题就是出了 bug 不方便追查,而JSON编码的方式更实用于系统与系统之间的数据通讯。

我的废话:
   1.从XML到JSON,再从JSON到Avro/Google PBs,技术不断的在发展,中间经历的时间跨度也越来越短。
   2.我个人认为Avro是比使用压缩(Gzip/z7)对结构化数据处理(JSON/XML)更好的手段。
   3.还可以借用Avro对以下产品进行序列化存储或者传输通信:
    a)HBase、Hive、MySQL
    b)Redis、MemCached
    c)本地文件存储 、Solr远程调用
    d)MapReduce分布式计算
参考资料:https://github.com/spullara/havrobase
4.别拿Avro的Socket当炮使,那玩意儿经不起折腾,在这个api的 ref里面已经明确的说明了。
参考资料:http://avro.apache.org/docs/1.5.0/api/java/org/apache/avro/ipc/SocketServer.html
5.如果specific方式需要用avro-tools.jar包进行编译,而generic方式直接调用JSON文件。

Avro支持本地和远程RPC(Ref)调用,RPC远程调用又分为Http和Netty2种,在这里主要介绍基于Http协议的Avro远程调用,首先需要定义一个JSON文件作为双方通信的传输协议规范,便于解析从对方发送过来的数据。
在这个协议中可以看做分为3大部分:
    1.描述(Protocol Declaration),定义命名空间,协议名称 等。
    2.数据类型(types),根据规范中的Primitive和Complex Types数据类型,自己封装一套数据格式。
    3.消息(messages),根据自己定义的数据类型,再去定义 a)请求、b)回应、c)异常(可选)  数据格式。
以上内容可以详见下面代码示例中的user.avpr文件。

消息从客户端发送到服务器端需要经过传输层(Transport Layer),它发送消息并接收服务器端的响应。到达传输层的数据就是二进制数据。通常以HTTP作为传输模型,客户端数据以POST方式发送到服务器端。消息被封装成为一组缓冲区(Buffer),Avro规定一个标准的序列化的格式,即无论是文件存储还是网络传输,数据的Schema都出现在数据的前面。数据本身并不包含任何Metadata(Tag). 在文件储存的时候,schema出现在文件头中。在网络传输的时候Schema出现在初始的握手阶段,客户端和服务器端需要维护一个可见的协议缓存,因此,简单来说一个握手完成后,在进行网络交 换的时候不需要再传输协议的全部文本。
这是我在程序运行的过程中抓包的截图:
avro-java

图示说明:
192.168.1.2是服务器端,192.168.1.106是客户端,可以看出第一次传输的时候服务器端返回的数据包大小为891,第二次和第三次返回的数据库包大小为77。而且返回的内容明显能看出是经过序列化的(上图的左下方),也就是服务器端组装好的回应数据。

Avro 的消息被分为多个帧,形成一个缓冲列表。分帧是位于消息和传输层中的一层。它可以优化一些操作。分帧消息的格式为:
    * 一系列的缓存,每个缓冲包括:
          o 一个4字节,大端的缓存长度
          o 缓冲数据
    * 消息以一个零长度的缓存结束。
分帧对于请求和响应消息格式来说是透明的。任何消息都可能被分为一个或者多个缓存。

再来说说,这个代码例子,我大致分了3个包和一个user.avpr文件:
    1.client,我就直接放在最外面了,ClientHandler用来组装根据协议请求的数据,并且得到返回的结果。
    2.server,利用自带的Jetty作服务器,AvroFactory判断不同的请求的message类型,我定义了search、update 2种,也就是说在同一份user.avpr协议中经过处理和判断可以传输不同的协议内容。
    AvroHandler组装经过业务逻辑处理后返回结果,我在updateRespond/searchRespond2个方法中造了一些数据,模拟获取数据的结果
    3.tools,协议解析工具(AvroUtils.java)。
    4.user.avpr  传输协议文件。
将代码导入IDE环境后,运行AvroServer.java启动服务器,再运行ClientHandler.java执行客户端调用。

代码示例下载:
http://javabloger-mini-books.googlecode.com/files/avro-http-json.rar

以上代码示例采用的是Avro的1.4.1版本,如果需要Avro依赖的jar可以从这里下载:
http://javabloger-mini-books.googlecode.com/files/avro-lib-1.4.rar

通过阅读Avro的部分源码,按照其中的设计思路去实现,还可以将Avro集成到Tomcat,GlassFish,Resin 等 其他服务器中去,不见得非要使用Avro自带的Jetty作为服务器,只需要自己实现一个Servlet即可。这样就不受Avro中嵌入式Jetty服务器的限制,可以使用一些技术特性,例如:长连接、长轮询、Servlet监听器和过滤器,并且可以对Web容器进行更深入的性能优化。
在这里提供一个简单代码示例,大家可以参考一下,下载后直接将war工程部署到tomcat 等web容器中,客户端的代码也在这里war工程中(Client.java)。

代码示例下载:
http://javabloger-mini-books.googlecode.com/files/avroweb.war

暂时先说到这里,有空再聊一聊Avro中的MapReduce以及Avro中的内部结构。

–end–



原创粉丝点击