RPC框架之Apache Avro 简介

leegh 2016-04-19

 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.7.7/java/
一、在pom.xml中添加依赖jar包
二、定义模式(Schema)

在avro中,它是用Json格式来定义模式的。模式可以由基础类型(null, boolean, int, long, float, double, bytes, and string)和复制类型(record, enum, array, map, union, and fixed)的数据组成。本文只是定义了一个简单的模式user.avsc

package cn.slimsmart.avro.demo;  
  
import java.io.File;  
import java.io.IOException;  
  
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;  
  
public class Test {  
  
    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到文件中  
        File file = new File("users.avro");  
        DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);  
        DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);  
        try {  
            dataFileWriter.create(user1.getSchema(), new File("src/main/avro/users.avro"));  
            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) {  
        }  
    }  
}  

参考:
官方实例:http://avro.apache.org/docs/current/gettingstartedjava.html
http://blog.csdn.net/zhu_tianwei/article/details/44042691

相关推荐