近期研究RPC框架,第一个研究的是GRPC,虽然GRPC应用远远没有Dubbo\Dubbox广泛,但作为google发布的支持Http2协议的RPC还是有很高关注度的,分析来自于外网:http://www.cnblogs.com/yjmyzz/p/grpc-hello-world.html ,由于外部的代码不易获取,为了测试,自己适当调整,下载后可跑通。
本例子采用了protobuf的maven插件来实现.proto文件的生成,插件配置:
org.apache.maven.plugins maven-clean-plugin 2.5 org.xolstice.maven.plugins protobuf-maven-plugin 0.5.0 com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:0.8.0:exe:${os.detected.classifier} compile compile-custom
工程protbuffer就是协议定义工程,grpcserver是server端,grpc-client是client端。
默认先注释掉上面的插件代码,只有第一次需要根据。proto文件生成对应java文件类时放开,执行mvn install生成后再Target目录下有source包,把对应包copy到src/java下面,执行mvn install发布protbuffer工程.
一、grpc-contract
还是按老套路,把服务涉及的对象定义、接口定义抽象出来,下面是项目结构图:
pom.xml的内容如下:
4.0.0 protobuf.test protbuffer-contract 1.0-SNAPSHOT com.google.protobuf protobuf-java 3.0.0 junit junit 4.10 io.grpc grpc-all 0.8.0 kr.motd.maven os-maven-plugin 1.4.0.Final org.apache.maven.plugins maven-clean-plugin 2.5 org.xolstice.maven.plugins protobuf-maven-plugin 0.5.0 com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:0.8.0:exe:${os.detected.classifier} compile compile-custom maven-source-plugin 2.4 package jar-no-fork org.apache.maven.plugins maven-compiler-plugin 1.6
demo_service.proto内容如下:
syntax = "proto3"; import "demo_service_dto.proto"; package com.protobuf.test.grpc.demo.service; option java_multiple_files = true; option java_outer_classname = "DemoServiceDto"; service DemoService { rpc Ping (com.protobuf.test.grpc.demo.dto.PingRequest) returns (com.protobuf.test.grpc.demo.dto.PingResponse) {} rpc getPersonList (com.protobuf.test.grpc.demo.dto.QueryParameter) returns (com.protobuf.test.grpc.demo.dto.PersonList) {} }
demo_service_dto.proto内容:
syntax = "proto3"; package com.protobuf.test.grpc.demo.dto; option java_multiple_files = true; option java_outer_classname = "DemoServiceDto"; message PingRequest { string in=1; } message PingResponse { string out=1; } message QueryParameter { int32 ageStart = 1; int32 ageEnd = 2; } message Person { int32 age = 1; string name = 2; bool sex=3; double salary=4; int32 childrenCount=5; } message PersonList{ repeated Person items=1; }
mvn install 后,会自动在target下生成相应的java class类再把类copy到src/main/java下面
二、grpc-server
pom.xml如下
4.0.0 protobuffer.test grpc-server 1.0-SNAPSHOT com.google.protobuf protobuf-java 3.0.0 junit junit 4.10 io.grpc grpc-all 0.8.0 protobuf.test protbuffer-contract 1.0-SNAPSHOT
先对服务接口提供实现:
package com.protobuf.test.grpc.demo.service; import com.protobuf.test.grpc.demo.service.DemoServiceGrpc; import com.protobuf.test.grpc.demo.dto.*; import io.grpc.stub.StreamObserver; import java.util.ArrayList; import java.util.List; public class DemoServiceImpl implements DemoServiceGrpc.DemoService{ public void ping(PingRequest pingRequest, StreamObserverstreamObserver) { PingResponse reply = PingResponse.newBuilder().setOut("pong => " + pingRequest.getIn()).build(); streamObserver.onValue(reply); streamObserver.onCompleted(); } public void getPersonList(QueryParameter queryParameter, StreamObserver streamObserver) { System.out.println("AgeStarton-AgeEnd:"+queryParameter.getAgeStart() + "-" + queryParameter.getAgeEnd()); PersonList.Builder personListBuilder = PersonList.newBuilder(); Person.Builder builder = Person.newBuilder(); List list = new ArrayList (); int start=queryParameter.getAgeStart(); int end=queryParameter.getAgeEnd(); for (int i = start; i < end; i++) { list.add(builder.setAge(i).setChildrenCount(i).setName("test" + i).setSex(true).build()); } personListBuilder.addAllItems(list); streamObserver.onValue(personListBuilder.build()); streamObserver.onCompleted(); } }
server端实现:
package com.protobuf.test.grpc.demo.server; import com.protobuf.test.grpc.demo.service.DemoServiceGrpc; import com.protobuf.test.grpc.demo.service.DemoServiceImpl; import io.grpc.ServerImpl; import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.netty.NettyServerBuilder; /** * Created by liuzhimeng on 2017/10/31. */ public class DemoServiceServer { private int port = 50051; private ServerImpl server; private void start() throws Exception { server = NettyServerBuilder.forPort(port) .addService(DemoServiceGrpc.bindService(new DemoServiceImpl())) .build().start(); server = InProcessServerBuilder.forName("testServer") .addService(DemoServiceGrpc.bindService(new DemoServiceImpl())) .build().start(); System.out.println("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.out.println("*** shutting down gRPC server since JVM is shutting down"); DemoServiceServer.this.stop(); System.out.println("*** server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } public static void main(String[] args) throws Exception { final DemoServiceServer server = new DemoServiceServer(); server.start(); } }
三、grpc-client
pom.xml
4.0.0 protobuffer.test grpc-client 1.0-SNAPSHOT com.google.protobuf protobuf-java 3.0.0 junit junit 4.10 io.grpc grpc-all 0.8.0 protobuf.test protbuffer-contract 1.0-SNAPSHOT
client端实现:
package com.protobuf.test.grpc.client; import com.protobuf.test.grpc.demo.dto.*; import com.protobuf.test.grpc.demo.service.DemoServiceGrpc; import io.grpc.ChannelImpl; import io.grpc.netty.NegotiationType; import io.grpc.netty.NettyChannelBuilder; import java.util.concurrent.TimeUnit; /** * Created by liuzhimeng on 2017/10/31. */ public class DemoServiceClient { private final ChannelImpl channel; private final DemoServiceGrpc.DemoServiceBlockingStub blockingStub; public DemoServiceClient(String host, int port) { channel = NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT) .build(); blockingStub = DemoServiceGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } public void ping(String name) { try { System.out.println("Will try to ping " + name + " ..."); PingRequest request = PingRequest.newBuilder().setIn(name).build(); PingResponse response = blockingStub.ping(request); System.out.println("ping: " + response.getOut()); } catch (RuntimeException e) { System.out.println("RPC failed:" + e.getMessage()); return; } } public void getPersonList(QueryParameter parameter) { try { System.out.println("Will try to getPersonList " + parameter + " ..."); PersonList response = blockingStub.getPersonList(parameter); System.out.println("items count: " + response.getItemsCount()); for (Person p : response.getItemsList()) { System.out.println(p); } } catch (RuntimeException e) { System.out.println("RPC failed:" + e.getMessage()); return; } } public static void main(String[] args) throws Exception { DemoServiceClient client = new DemoServiceClient("localhost", 50051); try { client.ping("a"); int max =1; Long start = System.currentTimeMillis(); for (int i = 0; i < max; i++) { client.getPersonList(getParameter()); } Long end = System.currentTimeMillis(); Long elapse = end - start; int perform = Double.valueOf(max / (elapse / 1000d)).intValue(); System.out.print("rgpc " + max + " 次NettyServer调用,耗时:" + elapse + "毫秒,平均" + perform + "次/秒"); } finally { client.shutdown(); } } private static QueryParameter getParameter() { return QueryParameter.newBuilder().setAgeStart(5).setAgeEnd(6).build(); } }
启动server端后测试:
Will try to ping a ...
ping: pong => a
Will try to getPersonList ageStart: 5
ageEnd: 6
...
items count: 1
age: 5
name: "test5"
sex: true
childrenCount: 5
rgpc 1 次NettyServer调用,耗时:80毫秒,平均12次/秒