avro是hadoop的一个子项目,提供的功能与thrift、Protocol Buffer类似,都支持二进制高效序列化,也自带RPC机制,但是avro使用起来更简单,无需象thrift那样生成目标语言源代码,目前支持的语言有java、c#、php、c++等(详情见:https://cwiki.apache.org/confluence/display/AVRO/Supported+Languages),hadoop生态圈中的hive、pig已经在使用avro
avro-client模块中的pom.xml参考以下内容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>yjmyzz.avro</groupId> 8 <artifactId>avro-client</artifactId> 9 <version>1.0</version> 10 11 <properties> 12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 13 <compiler-plugin.version>2.3.2</compiler-plugin.version> 14 <avro.version>1.7.5</avro.version> 15 </properties> 16 17 <dependencies> 18 <dependency> 19 <groupId>junit</groupId> 20 <artifactId>junit</artifactId> 21 <version>4.10</version> 22 <scope>test</scope> 23 </dependency> 24 <dependency> 25 <groupId>org.slf4j</groupId> 26 <artifactId>slf4j-simple</artifactId> 27 <version>1.6.4</version> 28 <scope>compile</scope> 29 </dependency> 30 <dependency> 31 <groupId>org.apache.avro</groupId> 32 <artifactId>avro</artifactId> 33 <version>${avro.version}</version> 34 </dependency> 35 <dependency> 36 <groupId>org.apache.avro</groupId> 37 <artifactId>avro-ipc</artifactId> 38 <version>${avro.version}</version> 39 </dependency> 40 41 <dependency> 42 <groupId>yjmyzz.avro</groupId> 43 <artifactId>avro-contract</artifactId> 44 <version>1.0</version> 45 </dependency> 46 </dependencies> 47 48 <build> 49 <plugins> 50 <plugin> 51 <groupId>org.apache.maven.plugins</groupId> 52 <artifactId>maven-compiler-plugin</artifactId> 53 <version>${compiler-plugin.version}</version> 54 </plugin> 55 <plugin> 56 <groupId>org.apache.avro</groupId> 57 <artifactId>avro-maven-plugin</artifactId> 58 <version>${avro.version}</version> 59 <executions> 60 <execution> 61 <id>schemas</id> 62 <phase>generate-sources</phase> 63 64 <goals> 65 <goal>schema</goal> 66 <goal>protocol</goal> 67 <goal>idl-protocol</goal> 68 </goals> 69 </execution> 70 </executions> 71 </plugin> 72 </plugins> 73 </build> 74 75 76 </project>
一、定义文件示例
Person.avsc
{ "namespace": "yjmyzz.avro.study.dto", "type": "record", "name": "Person", "fields": [ { "name": "age", "type": "int" }, { "name": "name", "type": "string" }, { "name": "sex", "type": "boolean" }, { "name": "salary", "type": "double" }, { "name": "childrenCount", "type": "int" } ] }
QueryParameter.avsc
{ "namespace": "yjmyzz.avro.study.dto", "type": "record", "name": "QueryParameter", "fields": [ { "name": "ageStart", "type": "int" }, { "name": "ageEnd", "type": "int" } ] }
DemoService.avdl
@namespace ("yjmyzz.avro.study.service") protocol DemoService { import schema "Person.avsc"; import schema "QueryParameter.avsc"; string ping(); array<yjmyzz.avro.study.dto.Person> getPersonList(yjmyzz.avro.study.dto.QueryParameter queryParameter); }
二、服务端
DemoServiceImpl.java
package yjmyzz.avro.study; import yjmyzz.avro.study.dto.Person; import yjmyzz.avro.study.dto.QueryParameter; import yjmyzz.avro.study.service.DemoService; import java.util.ArrayList; import java.util.List; public class DemoServiceImpl implements DemoService { public String ping() { System.out.println("ping()"); return "pong"; } public List<Person> getPersonList(QueryParameter parameter) { //System.out.println(parameter.getAgeStart() + " - " + parameter.getAgeEnd()); List<Person> list = new ArrayList<Person>(10); for (int i = 0; i < 10; i++) { Person p = new Person(); p.setAge(i); p.setChildrenCount(i); p.setName("test" + i); p.setSalary(10000D); p.setSex(true); list.add(p); } return list; } }
AvroServer.java
package yjmyzz.avro.study; import org.apache.avro.ipc.NettyServer; import org.apache.avro.ipc.Server; import org.apache.avro.ipc.specific.SpecificResponder; import yjmyzz.avro.study.service.DemoService; import java.net.InetSocketAddress; public class AvroServer { public static void main(String[] args) { System.out.println("Starting avro server..."); Server server = new NettyServer(new SpecificResponder(DemoService.class, new DemoServiceImpl()), new InetSocketAddress(65111)); System.out.println("Avro erver started."); } }
三、客户端
AvroClient.java
package yjmyzz.avro.study; import org.apache.avro.AvroRemoteException; import org.apache.avro.ipc.NettyTransceiver; import org.apache.avro.ipc.specific.SpecificRequestor; import yjmyzz.avro.study.dto.QueryParameter; import yjmyzz.avro.study.service.DemoService; import java.net.InetSocketAddress; public class AvroClient { public static void main(String[] args) throws Exception { NettyTransceiver client = new NettyTransceiver(new InetSocketAddress(65111)); DemoService proxy = (DemoService) SpecificRequestor.getClient(DemoService.class, client); System.out.println(proxy.ping()); int max = 100000; Long start = System.currentTimeMillis(); for (int i = 0; i < max; i++) { call(proxy); } Long end = System.currentTimeMillis(); Long elapse = end - start; int perform = Double.valueOf(max / (elapse / 1000d)).intValue(); System.out.print("avro " + max + " 次RPC调用,耗时:" + elapse + "毫秒,平均" + perform + "次/秒"); // cleanup client.close(); } private static void call(DemoService proxy) throws AvroRemoteException { //client.ping(); //System.out.println("ping()=>" + client.ping()); QueryParameter parameter = new QueryParameter(); parameter.setAgeStart(5); parameter.setAgeEnd(50); proxy.getPersonList(parameter); //System.out.println(client.getPersonList(parameter)); } }
avro 100000 次RPC调用,耗时:18617毫秒,平均5371次/秒
注:虽然很多关于thrift、avro的性能评测文章提到avro性能不输于thrift,但就本文的示例而言,在同一台笔记本上,avro的性能只有thrift的约1/2.
附:文中示例代码下载 http://code.taobao.org/svn/avro-rpc-demo/trunk/
参考文章:
https://github.com/phunt/avro-rpc-quickstart
http://avro.apache.org/docs/current/spec.html#Protocol+Declaration
http://avro.apache.org/docs/current/idl.html