Apache Avro-[1]-序列化

来源:互联网 发布:湖南网络作协 编辑:程序博客网 时间:2024/06/07 19:30


入门

RPC

Avro官网:

http://avro.apache.org/

https://wiki.apache.org/hadoop/Avro/

https://github.com/phunt/avro-rpc-quickstart

jar下载地址:http://mirror.bit.edu.cn/apache/avro/avro-1.7.7/java/

官方实例:http://avro.apache.org/docs/current/gettingstartedjava.html
Apache Avro 与 Thrift 比较:http://www.alidata.org/archives/1307

Avro的三种序列化方法

参考(多谢分享):

http://blog.csdn.net/zhu_tianwei/article/details/44042691http://blog.csdn.net/u013054888/article/details/64444908

一、简介

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编码的方式更实用于系统与系统之间的数据通讯。     Avro支持本地和远程RPC(Ref)调用,RPC远程调用又分为Http和Netty2种,在这里主要介绍基于Http协议的Avro远程调用,首先需要定义一个JSON文件作为双方通信的传输协议规范,便于解析从对方发送过来的数据。在这个协议中可以看做分为3大部分:    1.描述(Protocol Declaration),定义命名空间,协议名称 等。    2.数据类型(types),根据规范中的Primitive和Complex Types数据类型,自己封装一套数据格式。    3.消息(messages),根据自己定义的数据类型,再去定义 a)请求、b)回应、c)异常(可选)  数据格式。特点:1.丰富的数据结构类型2.快速可压缩的二进制数据形式3.存储持久数据的文件容器4.远程过程调用(RPC)5.同动态语言的简单集成。读写数据文件和使用RPC协议都不需要生成代码,而代码生成作为一种可选的优化只值得在静态类型语言中实现。由于性能高、基本代码少和产出数据量精简等特点,Avro周围展开了众多活动——许多NoSQL实现,包括Hadoop、Cssandra等,都把Avro整合到它们的客户端API和储存功能中。Avro有C, C++, C#, Java, PHP, Python, and Ruby等语言的实现,下面我们以一个实例来说明Avro序列化和反序列化数据。Avro官网:http://avro.apache.org/jar下载地址:http://mirror.bit.edu.cn/apache/avro/avro-1.8.2/java/
定义了一个用户的记录,在模式定义中,必须包含它的类型(“type”: “record”)、一个名字(“name”: “User”)以及fields。在本例中fields包括了name, age和phone,上面的模式我们还定义了一个命名空间 (“namespace”: “cn.slimsmart.avro.demo”),namespace可以名字一起使用,从而组成模式的全名(即com.learn.User)
user.avsc如下:
{   "namespace": "com.learn",   "type": "record",   "name": "User",   "fields": [      {         "name": "name",         "type": "string"      },      {         "name": "age",         "type": [            "int",            "null"         ]      },      {         "name": "phone",         "type": [            "string",            "null"         ]      }   ]}

二、编译模式

Avro可以允许我们根据模式的定义而生成相应的类,一旦我们定义好相关的类,我们程序中就不需要直接使用模式了。
可以用avro-tools jar包来生成代码,语法如下:
java -jar ./avro-tools-1.7.7.jar     compile schema     <schema file> <destination>
这里我们用java -jar ./avro-tools-1.8.2.jar compile schema user.avsc . (这里有个.)
这时候,在当前目录下会生成com.learn/User.java类如果你直接用Avro Maven plugin,
那么你就不需要手动的编译模式,因为Avro Maven plugin会自动给你编译好。
生成好了一个User.java类,用avro将它序列化存放到本地文件中,最后再将其反序列化。
package com.learn.Serialization.UseCode;import org.apache.avro.file.DataFileReader;import org.apache.avro.file.DataFileWriter;import org.apache.avro.io.DatumReader;import org.apache.avro.io.DatumWriter;import org.apache.avro.specific.SpecificDatumReader;import org.apache.avro.specific.SpecificDatumWriter;import java.io.File;import java.io.IOException;public class UserTestApp {  public static void main(String[] args) {    // 3种生成user对象的方法    User user1 = new User();    user1.setName("张山");    user1.setAge(23);    user1.setPhone("123456789");    User user2 = new User("李斯", 45, "987654321");    User user3 = User.newBuilder().setName("王二").setAge(57).setPhone("456893256").build();    // 序列化user到文件中    String path = "./avro/src/main/java/com/learn/Serialization/UseCode/output/users.avro";    File file = new File(path);    DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);    DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);    try {      dataFileWriter.create(user1.getSchema(), new File(path));      dataFileWriter.append(user1);      dataFileWriter.append(user2);      dataFileWriter.append(user3);      dataFileWriter.flush();      dataFileWriter.close();    } catch (IOException e) {    }    // 从文件中反序列化对象    DatumReader<User> userDatumReader = new SpecificDatumReader<User>(User.class);    DataFileReader<User> dataFileReader = null;    try {      dataFileReader = new DataFileReader<User>(file, userDatumReader);    } catch (IOException e) {    }    User user = null;    try {      while (dataFileReader.hasNext()) {        user = dataFileReader.next(user);        System.out.println(user);      }    } catch (IOException e) {    }  }}//==输出//  {"name": "张山", "age": 23, "phone": "123456789"}//  {"name": "李斯", "age": 45, "phone": "987654321"}//  {"name": "王二", "age": 57, "phone": "456893256"}

三、直接代码生成模式

除了先用tools生成目标类(User),还可以直接读取schema
package com.learn.Serialization.DirectNoCode;import org.apache.avro.Schema;import org.apache.avro.file.DataFileReader;import org.apache.avro.file.DataFileWriter;import org.apache.avro.generic.GenericData;import org.apache.avro.generic.GenericDatumReader;import org.apache.avro.generic.GenericDatumWriter;import org.apache.avro.generic.GenericRecord;import org.apache.avro.io.DatumReader;import org.apache.avro.io.DatumWriter;import java.io.File;import java.io.IOException;public class DirectUserTest {  public static void main(String[] args) throws IOException {    String path = "./avro/src/main/java/com/learn/Serialization/avrotools/user.avsc";    //Parser 读取我们的 schema 定义并创建一个 Schema 对象    Schema schema = new Schema.Parser().parse(new File(path));    //使用该 schema ,我们来创建一些 Users    GenericRecord user1 = new GenericData.Record(schema);    user1.put("name", "Alyssa");    user1.put("age", 10);    //孩子太小没有电话    GenericRecord user2 = new GenericData.Record(schema);    user2.put("name", "Ben");    user2.put("age", 20);    user2.put("phone", "18301103342");    // Serialize user1 and user2 to disk    File file = new File("./avro/src/main/java/com/learn/Serialization/DirectNoCode/output/users.avro");    DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(schema);    DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<GenericRecord>(datumWriter);    dataFileWriter.create(schema, file);    dataFileWriter.append(user1);    dataFileWriter.append(user2);    dataFileWriter.close();    // Deserialize users from disk    DatumReader<GenericRecord> datumReader = new GenericDatumReader<GenericRecord>(schema);    DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, datumReader);    GenericRecord user = null;    while (dataFileReader.hasNext()) {      // Reuse user object by passing it to next(). This saves us from      // allocating and garbage collecting many objects for files with      // many items.      user = dataFileReader.next(user);      System.out.println(user);    }  }}//输出//{"name": "Alyssa", "age": 10, "phone": null}//{"name": "Ben", "age": 20, "phone": "18301103342"}
代码结构:
pox依赖
  <dependencies>        <dependency>            <groupId>org.apache.avro</groupId>            <artifactId>avro</artifactId>            <version>1.8.2</version>        </dependency>    </dependencies>



原创粉丝点击