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, PHPC#. grpc最大的特点是基于protobuf + http2 协议,http2协议虽然还未正式定稿,但从目前得知的内容来看,潜力巨大。下面是grpc基本的hello world的示例:

一、grpc-contract

还是按老套路,把服务涉及的对象定义、接口定义抽象出来,下面是项目结构图:

pom.xml的内容如下:

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>yjmyzz.grpc</groupId>
<artifactId>grpc-contract</artifactId>
<version>1.0</version> <dependencies> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency> <dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-beta-1</version>
</dependency> <dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>0.8.0</version>
</dependency> </dependencies> <!--下面这个节点可选-->
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
<pluginRepository>
<id>protoc-plugin</id>
<url>https://dl.bintray.com/sergei-ivanov/maven/</url>
</pluginRepository>
</pluginRepositories> <build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.0.Final</version>
</extension>
</extensions>
<plugins>
<!--用于根据proto文件生成java类的插件-->
<plugin>
<groupId>com.google.protobuf.tools</groupId>
<artifactId>maven-protoc-plugin</artifactId>
<version>0.4.2</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.0.0-alpha-3.1:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:0.8.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin> <!--生成源代码jar包的插件(可选)-->
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin> </plugins>
</build>
</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文件如下:

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>yjmyzz.grpc</groupId>
<artifactId>grpc-server</artifactId>
<version>1.0</version> <dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-beta-1</version>
</dependency> <dependency>
<groupId>yjmyzz.grpc</groupId>
<artifactId>grpc-contract</artifactId>
<version>1.0</version>
</dependency> <dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>0.8.0</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency> </dependencies> </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();
}
}

和前面thriftavro的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内容:

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>yjmyzz.grpc</groupId>
<artifactId>grpc-client</artifactId>
<version>1.0</version> <dependencies> <dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-beta-1</version>
</dependency> <dependency>
<groupId>yjmyzz.grpc</groupId>
<artifactId>grpc-contract</artifactId>
<version>1.0</version>
</dependency> <dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>0.8.0</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency> </dependencies> </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/

参考文章:

RPC框架性能基本比较测试

Schema evolution in Avro, Protocol Buffers and Thrift

jvm-serializers

RPC综述 - PB, Thrift, Avro

rpc框架之gRPC 学习 - hello world的更多相关文章

  1. 基于HTTP/2和protobuf的RPC框架:GRPC

    谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...

  2. 谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC

    Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobuf 本身虽然提供了RPC  的定义语法,但是一直以来,Google 只开 ...

  3. rpc框架之 thrift 学习 1 - 安装 及 hello world

    thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(当然,除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.or ...

  4. rpc框架之 avro 学习 2 - 高效的序列化

    同一类框架,后出现的总会吸收之前框架的优点,然后加以改进,avro在序列化方面相对thrift就是一个很好的例子.借用Apache Avro 与 Thrift 比较 一文中的几张图来说明一下,avro ...

  5. rpc框架之avro 学习 1 - hello world

    avro是hadoop的一个子项目,提供的功能与thrift.Protocol Buffer类似,都支持二进制高效序列化,也自带RPC机制,但是avro使用起来更简单,无需象thrift那样生成目标语 ...

  6. rpc框架之 thrift 学习 2 - 基本概念

    thrift的基本构架: 上图源自:http://jnb.ociweb.com/jnb/jnbJun2009.html 底层Underlying I/O以上的部分,都是由thrift编译器生成的代码, ...

  7. 服务化实战之 dubbo、dubbox、motan、thrift、grpc等RPC框架比较及选型

    转自: http://blog.csdn.net/liubenlong007/article/details/54692241 概述 前段时间项目要做服务化,所以我比较了现在流行的几大RPC框架的优缺 ...

  8. dubbo、dubbox、motan、thrift、grpc等RPC框架比较及选型

    概述 前段时间项目要做服务化,所以我比较了现在流行的几大RPC框架的优缺点以及使用场景,最终结合本身项目的实际情况选择了使用dubbox作为rpc基础服务框架.下面就简单介绍一下RPC框架技术选型的过 ...

  9. Google 高性能 RPC 框架 gRPC 1.0.0 发布(附精彩评论)

    gRPC是一个高性能.开源.通用的RPC框架,面向移动和HTTP/2设计,是由谷歌发布的首款基于Protocol Buffers的RPC框架. gRPC基于HTTP/2标准设计,带来诸如双向流.流控. ...

随机推荐

  1. jQuery实现选项联动轮播

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. 钉钉js依赖库学习

    看别人用的依赖库的好处在于,你知道有什么可以用,什么可以借鉴.(钉钉——协作桌面应用) PS:人最怕是不知道,而不是你不会. 1. jQuery 钉钉使用了1.9.1版本的jQuery,jQuery作 ...

  3. sass初级语法

    github地址:https://github.com/lily1010/sass/tree/master/course01 用到的sass语法是: sass --watch test.scss:te ...

  4. iOS 字号转换问题

    一,ps和pt转换 px:相对长度单位.像素(Pixel).(PS字体) pt:绝对长度单位.点(Point).(iOS字体) 公式如下: pt=(px/96)*72. 二,字体间转换 1in = 2 ...

  5. 元首的愤怒 SharePoint Apps

    柏林数据中心的服务器机架已经插满.CPU 100%.电力基础设施处在崩溃的边缘,但当元首决定迁移到 Office 365 的时候,将军们却告诉他那里没有 Farm Solution,5 年多的投资将付 ...

  6. Google C++单元测试框架GoogleTest---Extending Google Test by Handling Test Events

    Google TestExtending Google Test by Handling Test Events Google测试提供了一个事件侦听器API,让您接收有关测试程序进度和测试失败的通知. ...

  7. [转]Android App整体架构设计的思考

    1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...

  8. iOS 直播-闪光灯的使用

    iOS 直播-闪光灯的使用 应用场景是这样的,最近公司决定做一款直播类的软件. 在开发中就遇到了不曾使用过的硬件功能-闪光灯. 这篇博客将简单介绍一下闪光灯的使用. // // ViewControl ...

  9. Windows 8.1 低功耗蓝牙开发

    1. 概述 在蓝牙4.0发布以前,给大家的直观印象就是蓝牙耳机,它就是用来满足短距离内中等带宽的音频通信需求.然而蓝牙4.0发布之后,用途就大不一样了,特别是现在物联网和可穿戴之风盛行的年代,很多小玩 ...

  10. Python之路:堡垒机实例

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: 1 ...