grpc是google在github于2015年开源的一款RPC框架,虽然protobuf很早google就开源了,但是google一直没推出正式的开源框架,导致github上基于protobuf的rpc五花八门,国内比较著名的有百度的sofa-pbrpc,但是遗憾的是soft-pbrpc没有对应的java实现版本。rgpc还有一个独立的官网:http://www.grpc.io/,目前已经支持的语言有 C, C++, Java, Go, Node.js, Python, Ruby, Objective-C, PHP 、 C#. grpc最大的特点是基于protobuf + http2 协议,http2协议虽然还未正式定稿,但从目前得知的内容来看,潜力巨大。下面是grpc基本的hello world的示例:
一、grpc-contract
还是按老套路,把服务涉及的对象定义、接口定义抽象出来,下面是项目结构图:
文章图片
pom.xml的内容如下:
文章图片
文章图片
1 2 54.0.0 6 7yjmyzz.grpc 8grpc-contract 91.0 10 11 1213 14 33 34 35 36 3715 19 20junit 16junit 174.10 1821 25 26com.google.protobuf 22protobuf-java 233.0.0-beta-1 2427 31 32io.grpc 28grpc-all 290.8.0 3038 40 41never 39false 42 43central 44Central Repository 45https://repo.maven.apache.org/maven2 46 47 48protoc-plugin 49https://dl.bintray.com/sergei-ivanov/maven/ 50 51 52 53 5455 10056 62 63 64 6557 61kr.motd.maven 58os-maven-plugin 591.4.0.Final 60com.google.protobuf.tools 66maven-protoc-plugin 670.4.2 6869com.google.protobuf:protoc:3.0.0-alpha-3.1:exe:${os.detected.classifier} 70 71grpc-java 72io.grpc:protoc-gen-grpc-java:0.8.0:exe:${os.detected.classifier} 73 7475 82 83 84 85 86maven-source-plugin 8776 8177 80compile 78compile-custom 792.4 8889 96 97 98 9990package 91 9592 94jar-no-fork 93
文章图片
demo_service_dto.proto内容如下:
文章图片
文章图片
syntax = "proto3"; package yjmyzz.grpc.study.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; }
文章图片
注:grpc要求protobuf必须使用3.0以上版本
demo_service.proto内容如下:
文章图片
View Code mvn install 后,会自动在target下生成相应的java class类
文章图片
二、grpc-server
pom.xml文件如下:
文章图片
文章图片
1 2 54.0.0 6 7yjmyzz.grpc 8grpc-server 91.0 10 11 1213 38 39 4014 18 19com.google.protobuf 15protobuf-java 163.0.0-beta-1 1720 24 25yjmyzz.grpc 21grpc-contract 221.0 2326 30 31io.grpc 27grpc-all 280.8.0 2932 36 37junit 33junit 344.10 35
文章图片
先对服务接口提供实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package
yjmyzz.grpc.study.service.impl;
import
io.grpc.stub.StreamObserver;
import
yjmyzz.grpc.study.dto.*;
import
yjmyzz.grpc.study.service.DemoServiceGrpc;
import
java.util.ArrayList;
import
java.util.List;
public
class
DemoServiceImpl
implements
DemoServiceGrpc.DemoService {
public
void
ping(PingRequest pingRequest, StreamObserver streamObserver) {
PingResponse reply = PingResponse.newBuilder().setOut(
"pong => "
+ pingRequest.getIn()).build();
streamObserver.onValue(reply);
streamObserver.onCompleted();
}
public
void
getPersonList(QueryParameter queryParameter, StreamObserver streamObserver) {
//System.out.println(queryParameter.getAgeStart() + "-" + queryParameter.getAgeEnd());
PersonList.Builder personListBuilder = PersonList.newBuilder();
Person.Builder builder = Person.newBuilder();
List list =
new
ArrayList();
for
(
short
i =
0
;
i <
10
;
i++) {
list.add(builder.setAge(i).setChildrenCount(i).setName(
"test"
+ i).setSex(
true
).build());
}
personListBuilder.addAllItems(list);
streamObserver.onValue(personListBuilder.build());
streamObserver.onCompleted();
} } |
grpc的server端是基于Netty的(当然还有OKHttp的实现,详情见github项目主页),下面是server端的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | package
yjmyzz.grpc.study.server;
import
io.grpc.ServerImpl;
import
io.grpc.inprocess.InProcessServerBuilder;
import
io.grpc.netty.NettyServerBuilder;
import
yjmyzz.grpc.study.service.DemoServiceGrpc;
import
yjmyzz.grpc.study.service.impl.DemoServiceImpl;
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内容:
文章图片
文章图片
1 2 54.0.0 6 7yjmyzz.grpc 8grpc-client 91.0 10 1112 13 38 3914 18 19com.google.protobuf 15protobuf-java 163.0.0-beta-1 1720 24 25yjmyzz.grpc 21grpc-contract 221.0 2326 30 31io.grpc 27grpc-all 280.8.0 2932 36 37junit 33junit 344.10 35
文章图片
Client端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | package
yjmyzz.grpc.study.client;
import
io.grpc.ChannelImpl;
import
io.grpc.netty.NegotiationType;
import
io.grpc.netty.NettyChannelBuilder;
import
yjmyzz.grpc.study.dto.PersonList;
import
yjmyzz.grpc.study.dto.PingRequest;
import
yjmyzz.grpc.study.dto.PingResponse;
import
yjmyzz.grpc.study.dto.QueryParameter;
import
yjmyzz.grpc.study.service.DemoServiceGrpc;
import
java.util.concurrent.TimeUnit;
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 =
100000
;
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(
50
).build();
} } |
Will try to ping a ...
ping: pong => a
rgpc 100000 次NettyServer调用,耗时:36409毫秒,平均2746次/秒
基本上在每秒3k次的数量级,相对thrift(1w+)、avro(5k+)来讲,目前的差距还是很明显的,但是新事物成长总是需要时间,再给google一段时间,相信以后会让大家感到惊艳的。
在序列化方面,也做了一个跟之前thrift、avro类似的测试:
1 2 3 4 5 6 7 8 9 10 11 | @Test public
void
test()
throws
InvalidProtocolBufferException {
QueryParameter queryParameter = QueryParameter.newBuilder().setAgeStart(
1
).setAgeEnd(
5
).build();
byte
[] bytes1 = queryParameter.toByteArray();
System.out.println(
"Protobuf 3.0 二进制序列后的byte数组长度:"
+ bytes1.length);
QueryParameter result = QueryParameter.parseFrom(bytes1);
System.out.println(queryParameter.getAgeStart() +
" - "
+ result.getAgeStart());
} |
Protobuf 3.0 二进制序列后的byte数组长度:4
1 - 1
在2进制序列化后的大小方面,protobuf 3大体跟thrift的TCompactProtocal(大小5)接近,比avro(大小2)略差。
文中示例源码下载:http://code.taobao.org/svn/grpc-demo/
【grpc例子】转载于:https://www.cnblogs.com/hujihon/p/6023660.html