RPC框架實踐之:Google gRPC

My Desktop

概述

gRPC是Google開源的通用高性能RPC框架,它支持的是使用Protocol Buffers來編寫Service定義,支持較多語言擴平臺并且擁有強大的二進制序列化工具集。與文章《RPC框架實踐之:Apache Thrift》 一文中實踐的另一種通用RPC框架 Thrift 能通過Generator自動生成對應語言的Service接口類似,gRPC也能 自動地生成 Server和Client的 Service存根(Stub),我們只需要 一個命令 就能快速搭建起RPC運行環境。

下面實踐一下gRPC框架,做的事情就是:Client端通過遠程RPC調用Server的獲取時間的接口,從而將服務器時間獲取到本地并顯示。

類似于之前對于 RPC框架: Thrift 的實踐步驟,下面一一闡述。

注: 本文原載于 My Personal Blog:CodeSheep · 程序羊


開發gRPC-API

  • 首先創建一個基于Maven的項目: GrpcAPI

  • pom中加入grpc相關的依賴

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-all</artifactId>
            <version>1.12.0</version>
        </dependency>

這個grpc-all包含了很多grpc相關的組件:grpc-netty 、 grpc-protobuf 、grpc-stub 等等

與grpc相關的包
  • pom中加入grpc相關的 build插件

這里添加兩個Maven插件,目的是后面需要用這些插件來執行Protocol Buffers命令,從而自動生成相關的Stub代碼:

os-maven-plugin:生成平臺無關的屬性
protobuf-maven-plugin:執行Protocol Buffers命令并生成Stub代碼庫

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.4.1.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.0</version>
                <configuration>
                    <pluginId>grpc-java</pluginId>
                    <protocArtifact>com.google.protobuf:protoc:3.0.2:exe:${os.detected.classifier}</protocArtifact>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.2.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  • 編寫.proto的服務定義文件

這里.proto文件的作用和寫法就和我的前一篇文章《RPC框架實踐之:Apache Thrift》 一文中Thrift所要求的.thrift文件編寫一樣,是有其自己的語法要求的!

syntax = "proto3”;   // 語法版本

// stub選項
option java_package = "com.hansonwang99.grpc.api”;
option java_outer_classname = “RPCDateServiceApi”;
option java_multiple_files = true;

// 定義包名,類似于我的文章《RPC框架實踐之:Apache Thrift》中的Thrift的namespace
package com.hansonwang99.grpc.api;

// 服務接口定義,服務端和客戶端都要遵守該接口進行通信
service RPCDateService {
  rpc getDate (RPCDateRequest) returns (RPCDateResponse) {}
}

// 定義消息(請求)
message RPCDateRequest {
  string userName = 1;
}

// 定義消息(響應)
message RPCDateResponse {
  string serverDate = 1;
}
  • 執行mvn compile命令來自動生成代碼Stub

mvn編譯完成以后,在target/generated-sources目錄下就能看到根據上面.proto文件自動轉化生成的Java代碼Stub

mvn編譯

代碼生成結果如下所示

代碼生成結果

好了,既然gRPC-API已經有了,下面可以分別編寫服務端和客戶端


開發gRPC服務端

  • 創建基于Maven的項目:Server

  • pom中添加 GrpcAPI 依賴

        <dependency>
            <groupId>com.hansonwang99</groupId>
            <artifactId>GrpcAPI</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

接下來一步比較關鍵

  • 實現gRPC服務接口
public class RPCDateServiceImpl extends RPCDateServiceGrpc.RPCDateServiceImplBase{
    @Override
    public void getDate(RPCDateRequest request, StreamObserver<RPCDateResponse> responseObserver) {
        RPCDateResponse rpcDateResponse = null;
        Date now=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("今天是"+"yyyy年MM月dd日 E kk點mm分”);
        String nowTime = simpleDateFormat.format( now );
        try {
            rpcDateResponse = RPCDateResponse
                    .newBuilder()
                    .setServerDate( "Welcome " + request.getUserName()  + ", " + nowTime )
                    .build();
        } catch (Exception e) {
            responseObserver.onError(e);
        } finally {
            responseObserver.onNext( rpcDateResponse );
        }
        responseObserver.onCompleted();
    }
}

我想此處重寫的getDate()方法并不陌生吧,這正是上文 .proto 文件中定義的Service接口。
此處邏輯比較簡單:獲取當前時間,并且將其與請求RPCDateRequest中提取出的userName字段進行拼接,然后返回給調用端!形成一個閉環

  • 創建gRPC服務端啟動類
public class GRPCServer {
    private static final int port = 9999;
    public static void main( String[] args ) throws Exception {
        Server server = ServerBuilder.
                forPort(port)
                .addService( new RPCDateServiceImpl() )
                .build().start();
        System.out.println( "grpc服務端啟動成功, 端口=" + port );
        server.awaitTermination();
    }
}

端口自定義的9999,也就是在該端口監聽。現在可以立即運行GRPCServer,來啟動服務端

啟動服務端

開發gRPC客戶端

  • 創建基于Maven的項目:Client

  • pom中依然需要添加 GrpcAPI 依賴

        <dependency>
            <groupId>com.hansonwang99</groupId>
            <artifactId>GrpcAPI</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
  • 創建gRPC客戶端啟動類
public class GRPCClient {
    private static final String host = “localhost”;
    private static final int serverPort = 9999;

    public static void main( String[] args ) throws Exception {
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress( host, serverPort ).usePlaintext().build();
        try {
            RPCDateServiceGrpc.RPCDateServiceBlockingStub rpcDateService = RPCDateServiceGrpc.newBlockingStub( managedChannel );
            RPCDateRequest  rpcDateRequest = RPCDateRequest
                    .newBuilder()
                    .setUserName(“hansonwang99”)
                    .build();
            RPCDateResponse rpcDateResponse = rpcDateService.getDate( rpcDateRequest );
            System.out.println( rpcDateResponse.getServerDate() );
        } finally {
            managedChannel.shutdown();
        }
    }
}

現在立即啟動 GRPCClient!


C-S通信實驗

還記得我們的目標嗎?

RPC完成的即是遠程的過程調用,在本實驗中那就是客戶端可以遠程調用服務端的getDate()過程,并將結果取到客戶端來顯示!

RPC調用成功

后記

本文實驗代碼在此 → 需要自取

由于能力有限,若有錯誤或者不當之處,還請大家批評指正,一起學習交流!



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容