概述
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 公眾號 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 等等
- 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
程式碼生成結果如下所示
好了,既然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()過程,並將結果取到客戶端來顯示!
後記
本文實驗程式碼在此 → 需要自取
作者更多的SpringBt實踐文章在此:
- Spring Boot應用監控實戰
- SpringBoot應用部署於外接Tomcat容器
- ElasticSearch搜尋引擎在SpringBt中的實踐
- 初探Kotlin+SpringBoot聯合程式設計
- Spring Boot日誌框架實踐
- SpringBoot優雅編碼之:Lombok加持
如果有興趣,也可以抽點時間看看作者一些關於容器化、微服務化方面的文章:
- 利用K8S技術棧打造個人私有云 連載文章
- 從一份配置清單詳解Nginx伺服器配置
- Docker容器視覺化監控中心搭建
- 利用ELK搭建Docker容器化應用日誌中心
- RPC框架實踐之:Apache Thrift
- RPC框架實踐之:Google gRPC
- 微服務呼叫鏈追蹤中心搭建
- Docker容器跨主機通訊
- Docker Swarm叢集初探
- 高效編寫Dockerfile的幾條準則