rpc框架之gRPC 学习 - hello world
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 <?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.grpc</groupId>
8 <artifactId>grpc-contract</artifactId>
9 <version>1.0</version>
10
11
12 <dependencies>
13
14 <dependency>
15 <groupId>junit</groupId>
16 <artifactId>junit</artifactId>
17 <version>4.10</version>
18 </dependency>
19
20 <dependency>
21 <groupId>com.google.protobuf</groupId>
22 <artifactId>protobuf-java</artifactId>
23 <version>3.0.0-beta-1</version>
24 </dependency>
25
26 <dependency>
27 <groupId>io.grpc</groupId>
28 <artifactId>grpc-all</artifactId>
29 <version>0.8.0</version>
30 </dependency>
31
32 </dependencies>
33
34 <!--下面这个节点可选-->
35 <pluginRepositories>
36 <pluginRepository>
37 <releases>
38 <updatePolicy>never</updatePolicy>
39 </releases>
40 <snapshots>
41 <enabled>false</enabled>
42 </snapshots>
43 <id>central</id>
44 <name>Central Repository</name>
45 <url>https://repo.maven.apache.org/maven2</url>
46 </pluginRepository>
47 <pluginRepository>
48 <id>protoc-plugin</id>
49 <url>https://dl.bintray.com/sergei-ivanov/maven/</url>
50 </pluginRepository>
51 </pluginRepositories>
52
53
54 <build>
55 <extensions>
56 <extension>
57 <groupId>kr.motd.maven</groupId>
58 <artifactId>os-maven-plugin</artifactId>
59 <version>1.4.0.Final</version>
60 </extension>
61 </extensions>
62 <plugins>
63 <!--用于根据proto文件生成java类的插件-->
64 <plugin>
65 <groupId>com.google.protobuf.tools</groupId>
66 <artifactId>maven-protoc-plugin</artifactId>
67 <version>0.4.2</version>
68 <configuration>
69 <protocArtifact>com.google.protobuf:protoc:3.0.0-alpha-3.1:exe:${os.detected.classifier}
70 </protocArtifact>
71 <pluginId>grpc-java</pluginId>
72 <pluginArtifact>io.grpc:protoc-gen-grpc-java:0.8.0:exe:${os.detected.classifier}</pluginArtifact>
73 </configuration>
74 <executions>
75 <execution>
76 <goals>
77 <goal>compile</goal>
78 <goal>compile-custom</goal>
79 </goals>
80 </execution>
81 </executions>
82 </plugin>
83
84 <!--生成源代码jar包的插件(可选)-->
85 <plugin>
86 <artifactId>maven-source-plugin</artifactId>
87 <version>2.4</version>
88 <executions>
89 <execution>
90 <phase>package</phase>
91 <goals>
92 <goal>jar-no-fork</goal>
93 </goals>
94 </execution>
95 </executions>
96 </plugin>
97
98 </plugins>
99 </build>
100 </project>
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内容如下:
syntax = "proto3";
import "demo_service_dto.proto";
package yjmyzz.grpc.study.service;
option java_multiple_files = true;
option java_outer_classname = "DemoServiceDto";
service DemoService {
rpc Ping (yjmyzz.grpc.study.dto.PingRequest) returns (yjmyzz.grpc.study.dto.PingResponse) {}
rpc getPersonList (yjmyzz.grpc.study.dto.QueryParameter) returns (yjmyzz.grpc.study.dto.PersonList) {}
}
mvn install 后,会自动在target下生成相应的java class类
二、grpc-server
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.grpc</groupId>
8 <artifactId>grpc-server</artifactId>
9 <version>1.0</version>
10
11
12 <dependencies>
13 <dependency>
14 <groupId>com.google.protobuf</groupId>
15 <artifactId>protobuf-java</artifactId>
16 <version>3.0.0-beta-1</version>
17 </dependency>
18
19 <dependency>
20 <groupId>yjmyzz.grpc</groupId>
21 <artifactId>grpc-contract</artifactId>
22 <version>1.0</version>
23 </dependency>
24
25 <dependency>
26 <groupId>io.grpc</groupId>
27 <artifactId>grpc-all</artifactId>
28 <version>0.8.0</version>
29 </dependency>
30
31 <dependency>
32 <groupId>junit</groupId>
33 <artifactId>junit</artifactId>
34 <version>4.10</version>
35 </dependency>
36
37 </dependencies>
38
39
40 </project>
先对服务接口提供实现:
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<PingResponse> streamObserver) {
PingResponse reply = PingResponse.newBuilder().setOut("pong => " + pingRequest.getIn()).build();
streamObserver.onValue(reply);
streamObserver.onCompleted();
}
public void getPersonList(QueryParameter queryParameter, StreamObserver<PersonList> streamObserver) {
//System.out.println(queryParameter.getAgeStart() + "-" + queryParameter.getAgeEnd());
PersonList.Builder personListBuilder = PersonList.newBuilder();
Person.Builder builder = Person.newBuilder();
List<Person> list = new ArrayList<Person>();
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();
}
}
和前面thrift、avro的helloworld一样,这里的实现只是意思一下,方便测试而已。
grpc的server端是基于Netty的(当然还有OKHttp的实现,详情见github项目主页),下面是server端的代码:
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 <?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.grpc</groupId>
8 <artifactId>grpc-client</artifactId>
9 <version>1.0</version>
10
11 <dependencies>
12
13 <dependency>
14 <groupId>com.google.protobuf</groupId>
15 <artifactId>protobuf-java</artifactId>
16 <version>3.0.0-beta-1</version>
17 </dependency>
18
19 <dependency>
20 <groupId>yjmyzz.grpc</groupId>
21 <artifactId>grpc-contract</artifactId>
22 <version>1.0</version>
23 </dependency>
24
25 <dependency>
26 <groupId>io.grpc</groupId>
27 <artifactId>grpc-all</artifactId>
28 <version>0.8.0</version>
29 </dependency>
30
31 <dependency>
32 <groupId>junit</groupId>
33 <artifactId>junit</artifactId>
34 <version>4.10</version>
35 </dependency>
36
37 </dependencies>
38
39 </project>
Client端代码:
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类似的测试:
@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/
参考文章:
Schema evolution in Avro, Protocol Buffers and Thrift
- 【Go 语言社区】JavaScript Date(日期)对象
- UWP基础教程 - XAML类型转换器
- Oracle 12c Data Guard搭建(一) (r10笔记第57天)
- 【Go 语言社区】Go语言 Cookie的使用
- 【Go 语言社区】HTML5 Geolocation(地理定位)-转
- Oracle 12c PDB迁移(一)(r10笔记第56天)
- 【Go 语言社区】Go worker线程池
- Oracle 12C打补丁的简单尝试(r10笔记第55天)
- 【Go 语言社区】奇妙的go语言(网页下载)-转
- 【Go 语言社区】golang的bufio用于内容解析
- [Go语言]从Docker源码学习Go——指针和Structs - lemon_bar
- Git 项目推荐 | Go 语言读写 INI 文件工具包
- 初识Python (r10笔记第52天)
- 挑战数据结构与算法面试题——统计上排数在下排出现的次数
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- django实现模型字段动态choice的操作
- 详解ASP.NET Core 处理 404 Not Found
- Python AutoCAD 系统设置的实现方法
- Python如何操作office实现自动化及win32com.client的运用
- android Palette调色板使用详解
- python 穷举指定长度的密码例子
- Android 高仿微信朋友圈拍照上传功能
- android的ListView点击item使item展开的做法的实现代码
- Android NavigationView头部设置监听事件
- android如何取得本地通讯录的头像的原图的实现代码
- 取消Android Studio项目与SVN关联的方法
- Android编程实现获取当前系统语言及地区并更改语言的方法
- Android Studio绑定下拉框数据详解
- python中的socket实现ftp客户端和服务器收发文件及md5加密文件
- Android XRecyclerView实现多条目加载