欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

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

程序员文章站 2024-02-02 20:14:04
...

Avro是Hadoop中的一个子项目,也是Apache中一个独立的项目,Avro是一个基于二进制数据传输高性能的中间件。在Hadoop的其他项目中例如HBase(Ref)和Hive(Ref)的Client端与服务端的数据传输也采用了这个工具,Avro可以做到将数据进行序列化,适用于远程或本地大

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入门1–序列化与远程通信

图示说明:
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–