java 构建avro rpc_RPC框架系列——Avro

1.下载与安装

官方网站:http://avro.apache.org/

下载地址:http://labs.renren.com/apache-mirror//avro/avro-1.5.1/avro-src-1.5.1.tar.gz

安装之前确保已经装了maven

cd /usr/local/src

wget http://labs.renren.com/apache-mirror//avro/avro-1.5.1/avro-src-1.5.1.tar.gz

tar zxvf avro-src-1.5.1.tar.gz

cd avro-src-1.5.1/lang/java

mvn clean install -DskipTests

安装后,avro-1.5.1.jar位于avro-src-1.5.1/lang/java/avro/target

2.消息结构与服务接口

Avro的模式主要由JSON对象来表示,Avro支持8种基本类型(Primitive Type)和6种复杂类型(Complex Type:records、enums、arrays、maps、unions 和fixed),基本类型可以由JSON字符串来表示。

Avro支持两种序列化编码方式:二进制编码和JSON编码,使用二进制编码会高效序列化,并且序列化后得到的结果会比较小。

基本类型:

null: no value

boolean: a binary value

int: 32-bit signed integer

long: 64-bit signed integer

float: single precision (32-bit) IEEE 754 floating-point number

double: double precision (64-bit) IEEE 754 floating-point number

bytes: sequence of 8-bit unsigned bytes

string: unicode character sequence

首先编写一个message.avpr文件,定义一个消息结构。

{

"namespace": "avro",

"protocol": "messageProtocol",

"doc": "This is a message.",

"name": "Message",

"types": [

{"name":"message", "type":"record",

"fields":[

{"name":"name", "type":"string"},

{"name":"type", "type":"int"},

{"name":"price", "type":"double"},

{"name":"valid", "type":"boolean"},

{"name":"content", "type":"bytes"}

]}

],

"messages":    {

"sendMessage":{

"doc" : "test",

"request" :[{"name":"message","type":"message" }],

"response" :"message"

}

}

}

其中定义了1种类型叫做message,有5个成员name、type、price、valid、content。还定义了1个消息服务叫做sendMessage,输入有一个参数,类型是message,返回message。

3.序列化

Avro有两种序列化编码:binary和JSON。

3.1.Binary Encoding

基本类型:

null:0字节

boolean:1个字节——0(false)或1(true)

int和long使用变长的zig-zag编码

float:4个字节

double:8个字节

bytes:1个long,后边跟着字节序列

string:1个long,后边跟着UTF-8编码的字符

3.2.records

按字段声明的顺序编码值,如下面一个record schema:

{

"type": "record",

"name": "test",

"fields" : [

{"name": "a", "type": "long"},

{"name": "b", "type": "string"}]

}

实例化这个record,a字段的值是27(编码为0×36),b字段的值是“foo”(编码为06 66 6f 6f),那么这个record编码结果是:

36 06 66 6f 6f

3.3.enums

一个enum被编码为一个int,比如,考虑这个enum。

{"type": "enum", "name": "Foo", "symbols": ["A", "B", "C", "D"] }

这将被编码为一个取值范围为[0,3]的int,0表示“A”,3表示“D”。

3.4.arrays

arrays编码为block序列,每个block包含一个long的count值,紧跟着的是array items,一个block的count为0表示该block是array的结尾。

3.5.maps

mapss编码为block序列,每个block包含一个long的count值,紧跟着的是key/value对,一个block的count为0表示该block是map的结尾。

3.6.union

union编码以一个long值开始,表示后边的数据是union中的哪种数据类型。

3.7.fixed

编码为指定数目的字节。

4.rpc通信实现

Avro的RPC实现不需要定义服务接口,但需要从.avpr文件中解析协议,协议中定义了消息结构和消息服务。message.avpr中定义了一个类型叫message,定义了一个服务叫sendMessage。

工具类Utils.java:

packageavro;

importjava.io.File;

importjava.io.IOException;

importjava.net.URL;

importorg.apache.avro.Protocol;

publicclassUtils{

publicstaticProtocolgetProtocol(){

Protocolprotocol=null;

try{

URLurl=Utils.class.getClassLoader().getResource("message.avpr");

protocol=Protocol.parse(newFile(url.getPath()));

}catch(IOExceptione){

e.printStackTrace();

}

returnprotocol;

}

}

服务端实现Server.java:

packageavro;

importorg.apache.avro.Protocol;

importorg.apache.avro.Protocol.Message;

importorg.apache.avro.generic.GenericRecord;

importorg.apache.avro.ipc.HttpServer;

importorg.apache.avro.ipc.generic.GenericResponder;

publicclassServerextendsGenericResponder

{

privateProtocolprotocol=

null;

privateintport;

publicServer(Protocolprotocol,

intport){

super(protocol);

this.protocol=protocol;

this.port=port;

}

publicObjectrespond(Messagemessage,Objectrequest)throwsException{

GenericRecordreq=(GenericRecord)request;

GenericRecordmsg=(GenericRecord)(req.get("message"));

// process the request

returnmsg;

}

publicvoidrun(){

try{

HttpServerserver=newHttpServer(this,port);

server.start();

}catch(Exceptione){

e.printStackTrace();

}

}

publicstaticvoidmain(String[]args){

if(args.length!=1){

System.out.println("Usage:

Server port");

System.exit(0);

}

intport=Integer.parseInt(args[0]);

newServer(Utils.getProtocol(),port).run();

}

}

客户端实现Client.java:

packageavro;

importjava.net.URL;

importjava.nio.ByteBuffer;

importjava.util.Arrays;

importorg.apache.avro.util.Utf8;

importorg.apache.avro.Protocol;

importorg.apache.avro.generic.GenericData;

importorg.apache.avro.generic.GenericRecord;

importorg.apache.avro.ipc.HttpTransceiver;

importorg.apache.avro.ipc.Transceiver;

importorg.apache.avro.ipc.generic.GenericRequestor;

publicclassClient{

privateProtocolprotocol=

null;

privateStringhost=null;

privateintport=0;

privateintsize=0;

privateintcount=0;

publicClient(Protocolprotocol,

Stringhost,intport,intsize,intcount){

this.protocol=protocol;

this.host=host;

this.port=port;

this.size=size;

this.count=count;

}

publiclongsendMessage()throwsException{

GenericRecordrequestData=newGenericData.Record(

protocol.getType("message"));

// initiate the request data

GenericRecordrequest=newGenericData.Record(protocol.getMessages()

.get("sendMessage").getRequest());

request.put("message",requestData);

Transceivert=newHttpTransceiver(newURL("http://"+host+":"

+port));

GenericRequestorrequestor=newGenericRequestor(protocol,t);

longstart=System.currentTimeMillis();

for(inti=0;i

requestor.request("sendMessage",request);

}

longend=System.currentTimeMillis();

System.out.println(end-start);

returnend-start;

}

publiclongrun(){

longres=0;

try{

res=sendMessage();

}catch(Exceptione){

e.printStackTrace();

}

returnres;

}

publicstaticvoidmain(String[]args)throwsException{

if(args.length!=4){

System.out.println("Usage:

Client host port dataSize count");

System.exit(0);

}

Stringhost=args[0];

intport=Integer.parseInt(args[1]);

intsize=Integer.parseInt(args[2]);

intcount=Integer.parseInt(args[3]);

newClient(Utils.getProtocol(),host,port,size,count).run();

}

}

5.参考资料

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值