rpc框架之gRPC 学习 - hello world

简介: grpc是google在github于2015年开源的一款RPC框架,虽然protobuf很早google就开源了,但是google一直没推出正式的开源框架,导致github上基于protobuf的rpc五花八门,国内比较著名的有百度的sofa-pbrpc,但是遗憾的是soft-pbrpc没有对应的java实现版本。

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的内容如下:

  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>
View Code

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;
}
View Code

注: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) {}
}
View Code

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>
View Code

先对服务接口提供实现:

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内容:

 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>
View Code

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

 

目录
相关文章
|
2月前
|
自然语言处理 负载均衡 API
gRPC 一种现代、开源、高性能的远程过程调用 (RPC) 可以在任何地方运行的框架
gRPC 是一种现代开源高性能远程过程调用(RPC)框架,支持多种编程语言,可在任何环境中运行。它通过高效的连接方式,支持负载平衡、跟踪、健康检查和身份验证,适用于微服务架构、移动设备和浏览器客户端连接后端服务等场景。gRPC 使用 Protocol Buffers 作为接口定义语言,支持四种服务方法:一元 RPC、服务器流式处理、客户端流式处理和双向流式处理。
|
5月前
|
Dubbo 网络协议 Java
RPC框架:一文带你搞懂RPC
这篇文章全面介绍了RPC(远程过程调用)的概念、原理和应用场景,解释了RPC如何工作以及为什么在分布式系统中广泛使用,并探讨了几种常用的RPC框架如Thrift、gRPC、Dubbo和Spring Cloud,同时详细阐述了RPC调用流程和实现透明化远程服务调用的关键技术,包括动态代理和消息的编码解码过程。
RPC框架:一文带你搞懂RPC
|
5月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
302 1
|
4月前
|
XML 负载均衡 监控
分布式-dubbo-简易版的RPC框架
分布式-dubbo-简易版的RPC框架
|
7月前
|
存储 缓存 Linux
【实战指南】嵌入式RPC框架设计实践:六大核心类构建高效RPC框架
在先前的文章基础上,本文讨论如何通过分层封装提升一个针对嵌入式Linux的RPC框架的易用性。设计包括自动服务注册、高性能通信、泛型序列化和简洁API。框架分为6个关键类:BindingHub、SharedRingBuffer、Parcel、Binder、IBinder和BindInterface。BindingHub负责服务注册,SharedRingBuffer实现高效数据传输,Parcel处理序列化,而Binder和IBinder分别用于服务端和客户端交互。BindInterface提供简单的初始化接口,简化应用集成。测试案例展示了客户端和服务端的交互,验证了RPC功能的有效性。
466 9
|
5月前
|
XML 存储 JSON
(十二)探索高性能通信与RPC框架基石:Json、ProtoBuf、Hessian序列化详解
如今这个分布式风靡的时代,网络通信技术,是每位技术人员必须掌握的技能,因为无论是哪种分布式技术,都离不开心跳、选举、节点感知、数据同步……等机制,而究其根本,这些技术的本质都是网络间的数据交互。正因如此,想要构建一个高性能的分布式组件/系统,不得不思考一个问题:怎么才能让数据传输的速度更快?
130 1
|
5月前
|
网络协议 编译器 Go
揭秘!TCP、RPC、gRPC、HTTP大PK,谁才是网络通信界的超级巨星?一篇文章带你秒懂!
【8月更文挑战第25天】本文以教程形式深入对比了TCP、RPC、gRPC与HTTP这四种关键通信协议,并通过Go语言中的示例代码展示了各自的实现方法。TCP作为一种可靠的传输层协议,确保了数据的完整性和顺序性;RPC与gRPC作为远程过程调用框架,特别适合于分布式系统的函数调用与数据交换,其中gRPC在性能和跨语言支持方面表现出色;HTTP则是广泛应用于Web浏览器与服务器通信的应用层协议。选择合适的协议需根据具体需求综合考量。
351 0
|
6月前
|
分布式计算 负载均衡 数据安全/隐私保护
什么是RPC?有哪些RPC框架?
RPC(Remote Procedure Call,远程过程调用)是一种允许运行在一台计算机上的程序调用另一台计算机上子程序的技术。这种技术屏蔽了底层的网络通信细节,使得程序间的远程通信如同本地调用一样简单。RPC机制使得开发者能够构建分布式计算系统,其中不同的组件可以分布在不同的计算机上,但它们之间可以像在同一台机器上一样相互调用。
176 8
|
6月前
|
网络协议 Dubbo Java
什么是RPC?RPC和HTTP对比?RPC有什么缺点?市面上常用的RPC框架?
选择合适的RPC框架和通信协议,对于构建高效、稳定的分布式系统至关重要。开发者需要根据自己的业务需求和系统架构,综合考虑各种因素,做出适宜的技术选型。
530 1
|
6月前
|
负载均衡 Java
使用Java实现RPC框架
使用Java实现RPC框架