##开始javascript
Avro是Apache的Hadoop家族的项目之一。具备性能高、基本代码少和产出数据量精简等特色。不过这是他们宣传广告,我最近也分别研究了Avro和Protobuf。基本的测试代码,不吐不快。html
##安装java
###Javapython
Avro是应运Hadoop而生的,所以主要也是以Java写就。 Java的安装比较简单,往项目中放入Avro及Avro-rpc的jar包即可。我喜欢使用Maven,所以Maven坐标以下:程序员
<dependency> <groupId>org.apache.avro</groupId> <artifactId>avro</artifactId> <version>1.7.2</version> </dependency> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro-ipc</artifactId> <version>1.7.2</version> </dependency>
###Pythonweb
熟悉Python模块安装应该很简单。avro的Python模块能够在 [https://pypi.python.org/pypi Python][https://pypi.python.org/pypi] 下载。下载<code>tar.gz</code>或者<code>zip</code>解压到硬盘任意目录。apache
打开终端,并用cd切换到avro解压的目录,执行:json
python setup.py install
Ubuntu系统须要Root权限:服务器
sudo python setup.py install
若是没有看到特殊的错误,通常都能顺利安装上。编辑器
##协议[Protocol]
Avro协议是以JSON结构性描述文本。协议定义了基本的通讯的数据类型,名称。而且还包含可调用的方法等。以下个人示例是一个实现简单的HelloWord程序。
<pre class="prettyprint lang-javascript"> { "namespace":"avro", "doc":"This is a message.", "protocol":"messageProtocol", "name":"HelloWorld", "types":[ { "name":"nameMessage", "type":"record", "fields":[ {"name":"name", "type":"string"} ] } ], "messages":{ "sayHello":{ "doc":"say Hello to manbers", "request":[ { "name":"name", "type":"string" } ], "response":"nameMessage" } } } </pre>
我把它命名为helloward.json。之因此我命名为json后缀的文件是由于不少编辑器都能认识,而且还能格式化。<<Hadoop权威指南>>中命名为avro后缀的文件,这点在编辑器中支持不是很好。而且Avro协议是不论协议文件的,它只认内容。
上面的协议至关于我新定义了一种复杂数据类型,名字为nameMessage,而且包含一个属性name,类型为string。 用Java语言通俗的说,我新定义了一个Bean, 这个Bean中只有一个<code>String name</code>的属性。所以她也是包涵在types下面的,至关与新定义了数据类型。
record是复杂类型,也就是能够经过简单类型合成的组装类型。关于支持的简单数据类型见:
http://avro.apache.org/docs/current/spec.html
messages在协议中包含特殊的含义。至关于曝露给外部能够调用的接口。如上面的协议,至关与包含了sayHello的方法,方法入口参数为String name,返回值为一个自定义的类型nameMessage, 其实也是一个String类型的键值对。
##服务端[Java]
<pre class="prettyprint lang-java"> public class AvroHttpServer extends GenericResponder { private static Log log = LogFactory.getLog(AvroHttpServer.class); public AvroHttpServer(Protocol protocol) { super(protocol); } public Object respond(Message message, Object request) throws Exception { GenericRecord req = (GenericRecord) request; GenericRecord reMessage = null; if (message.getName().equals("sayHello")) { Object name = req.get("name"); // do something... //取得返回值的类型 reMessage = new GenericData.Record(super.getLocal().getType("nameMessage")); //直接构造回复 reMessage.put("name", "Hello, " + name.toString()); log.info(reMessage); } return reMessage; } public static void main(String[] args) throws Exception { int port = 8088; try { Server server = new HttpServer( new AvroHttpServer(Protocol.parse( new File("helloword.json"))), port); server.start(); server.join(); } catch (Exception e) { e.printStackTrace(); } } } </pre>
如上边的Java代码,Avro默承认以支持的Server有不少,如NettyServer,SocketServer等。目前为止我之发现了Avro Python客户端只支持的Http的方式的。
上面的代码能正常运行,而且运行后进程不会退出,一直等待客户端连接。
##客户端
###Java
我是Java程序员, 所以每一个例子我都会用Java首先实现一遍。
<pre class="prettyprint lang-java"> private Protocol protocol; private GenericRequestor requestor = null; @Before public void setUp() throws Exception { protocol = Protocol.parse(new File("src/main/resources/helloword.json")); Transceiver t = new HttpTransceiver(new URL("http://localhost:8088")); requestor = new GenericRequestor(protocol, t); } @Test public void testSendMessage() throws Exception { GenericRecord requestData = new GenericData.Record(protocol.getType("nameMessage")); // initiate the request data requestData.put("name", "zhenqin"); System.out.println(requestData); Object result = requestor.request("sayHello", requestData); if (result instanceof GenericData.Record) { GenericData.Record record = (GenericData.Record) result; System.out.println(record.get("name")); } System.out.println(result); } </pre>
上面的是一个JUnit的测试用例,能够直接用来测试。
###Python
<pre class="prettyprint lang-python"> #!/usr/bin/env python #!encoding:utf-8 import json import avro.protocol as proto import avro.ipc as ipc import avro.io as avroio import avro.schema as schema __author__ = 'zhenqin' PROTOCOL = proto.parse(open("helloword.json", "r").read()) def testPro(): client = ipc.HTTPTransceiver("zhenqin-k45vm", 8088) requestor = ipc.Requestor(PROTOCOL, client) message = dict() message["name"] = "ZhenQin" v = requestor.request('sayHello', message) print("Result: " + str(v)) # cleanup client.close() if __name__ == '__main__': testPro() </pre>
Python如上边的代码,helloword.json是HelloWord的协议。运行不管是Java或者Python,都会成功的输出:
Result: {u'name': u'Hello, ZhenQin'}
上面提到,Python目前仅仅支持Http的方式调用,由于avro python只提供了一个HTTPTransceiver, 我查看HTTPTransceiver的代码, 都很简单,可是以个人Python造诣还不可以给写一个SocketTransceiver。我相信Python高人能轻易实现一个支持Socket通讯的SocketTransceiver不是难事。
在说一遍,Python目前只有一个HTTPTransceiver实现, 所以服务端Java还必须使用HttpServer,它是一个嵌入的Jetty的Http服务器。
##写在后边的话
测试了Avro, 我怎么以为它更像是以json的webservice呢? 开发是如此的罗嗦? 而且丝毫体现不了便捷。难道多语言跨平台的RPC调用真的有这么难麽?固然也有简单的方式是把服务端的Responder换成ReflectResponder就能够直接注册接口和实现类的对象,可是这样会失去对多语言的支持。
但愿广大同行能给以指正。
Protobuf, Next。