Avro官网:
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
参考(多谢分享):
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>