Apache Avro-[1]-序列化


入门

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/44042691
http://blog.csdn.net/u013054888/article/details/64444908

一、简介

Avro是Hadoop子项目,Avro是一个基于二进制数据传输高性能的中间件。
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>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值