什麼是gRPC "官方" 的定義: gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in ...
什麼是gRPC
官方的定義:
gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.
gRPC是一種現代化開源的高性能RPC框架,能夠運行於任意環境之中。它可以高效地在服務和數據中心內部與其間建立連接,並且可支持負載均衡,追蹤,健康檢測與認證功能。同時它也可用於分散式計算的“最後一公裡”,連接設備,移動應用和瀏覽器到後端服務。
維基的定義:
gRPC (gRPC Remote Procedure Calls) is an open source remote procedure call (RPC) system initially developed at Google. It uses HTTP/2 for transport, Protocol Buffers as the interface description language, and provides features such as authentication, bidirectional streaming and flow control, blocking or nonblocking bindings, and cancellation and timeouts. It generates cross-platform client and server bindings for many languages. Most common usage scenarios include connecting services in microservices style architecture and connect mobile devices, browser clients to backend services.
gRPC(gRPC遠程過程調用)是一種開源的遠程過程調用系統,最初由谷歌進行開發。它使用HTTP/2作為傳輸協議。Protocol Buffer被用於介面描述語言,提供了諸如認證,雙向流控制,阻塞或非阻塞綁定,取消與超時功能。它為多種語言生成跨平臺的客戶端與服務端綁定。最通用的使用場景包括在微服務樣式架構中連接服務,以及連接移動設備,瀏覽器客戶端到後端服務。
什麼是RPC
從上面的解釋里不難看出,要對gRPC有更直觀的理解,首先需要明白RPC的定義。
繼續看下維基上的內容:
In distributed computing, a remote procedure call (RPC) is when a computer program causes a procedure (subroutine) to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction. That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. This is a form of client–server interaction (caller is client, executor is server), typically implemented via a request–response message-passing system. In the object-oriented programming paradigm, RPC calls are represented by remote method invocation (RMI). The RPC model implies a level of location transparency, namely that calling procedures is largely the same whether it is local or remote, but usually they are not identical, so local calls can be distinguished from remote calls. Remote calls are usually orders of magnitude slower and less reliable than local calls, so distinguishing them is important.
在分散式計算里,當電腦程式要運行一段代碼,遠程過程調用(RPC)會在不同的記憶體地址(一般是在網路里的不同電腦)上執行它。其無需程式員顯示地對它的遠程交互進行具體編碼,編寫代碼的方式就如同一段普通的本地過程調用一般。即是,程式員所需寫的代碼是相同的,無論其調用的過程是在本地還是遠程。這是一種客戶端-服務端交互的形式(調用方是客戶端,執行方是服務端),典型的實現方式是通過一種請求-響應的傳遞消息系統。在面向對象程式範式里,RPC調用被表示為遠程方式調用(RMI)。RPC模型意味著一定程度的本地透明性,本地或是遠程的調用過程大致而言是等同的,但又不是完全一樣。遠程調用通常比本地調用慢上幾個數量級,同時也更加不可靠。
Remoting,Web Service,WCF
如果對RPC的概念還是理解不了的話,卻曾使用過或者瞭解過諸如Remoting,Web Service或者WCF等技術的話,那麼其實在這方面已經入門了。
Protocol buffers
Protocol buffers是谷歌開發的一套無關開發語言,無關平臺的用於序列化結構數據的可擴展機制。它的用途與XML,JSON相同,但比它們更小,更快,更簡潔。
作為gRPC中預設的介面定義語言,其既可以用於定義服務介面,也可以定義所必要的數據結構。
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string greeting = 1;
}
message HelloResponse {
string reply = 1;
}
Protocol buffers的代碼需要保存在擴展名為.proto
的文件之中。
服務類型
gRPC支持四種服務類型:
- 一元式RPC
- 服務端流式RPC
- 客戶端流式RPC
- 雙向流式RPC
一元式RPC,如同普通的方法調用一般,客戶端的單一請求,至服務端後,返回唯一的響應。
rpc SayHello(HelloRequest) returns (HelloResponse){
}
服務端流式RPC,客戶端發送一請求至服務端後,服務端返回一串消息數據流,客戶端持續讀取直到沒有更多的消息。gRPC會確保消息的傳輸順序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
客戶端流式RPC,客戶端對一數據流寫入一串信息後發送到服務端,並等待服務端返迴響應。gRPC會確保消息的傳輸順序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
雙向流式RPC,客戶端與服務端使用兩個數據流,其間互無影響,可以同時進行數據傳遞。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
gRPC API
光有proto文件,並不能直接使用,還需gRPC中所提供的API將這些文件編譯成不同程式語言的服務端與客戶端代碼。
在服務端,實現服務所定義的方法,並運行gRPC服務程式以處理客戶端調用。gRPC架構負責解碼傳入的請求,執行服務的方法,最後對服務的響應進行編碼。
在客戶端,會有一個名為存根(stub)的本地對象,實現與服務端相同的方法。這樣只需調用這個本地對象的方法,傳入合適的protocol buffers消息類型的參數,gRPC負責將請求發送至服務端,再返回相應的結果。
如果使用過諸如WCF這樣的PRC技術,對這一過程應該是十分熟悉了。
感到陌生的大概是gRPC中將proto文件編譯成代碼的插件工具,例如Grpc.Tools
。
所以還是舉個具體的例子以便理解。
.NET中的gPRC
首先建立兩個Console工程。
dotnet new console -o gRPCServer
dotnet new console -o gRPCClient
接著,在此兩個工程同級目錄下新建一個名為protos的文件夾。
如此,目錄下的文件夾應該有如下幾個:
- gRPCServer
- gRPCClient
- protos
protos文件夾下新加一個greet.proto文件。
syntax = "proto3";
option csharp_namespace = "GrpcGreeter";
package Greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
然後,進入gRPCServer文件夾,添加相關的類庫包。
dotnet add package Grpc
dotnet add package Grpc.Tools
dotnet add package Google.Protobuf
併在csproj文件中加入下列配置:
<ItemGroup>
<Protobuf Include="../protos/*.proto" OutputDir="protos" CompileOutputs="false" GrpcServices="Service" />
</ItemGroup>
運行dotnet build
,可以看到在gRPCServer工程下新生成一個protos文件夾,以及Greet.cs與GreetGrpc.cs文件。
在Program類中加入Greeter的實現類和相關介面方法,並創建服務端啟動程式。
class Program
{
const int Port = 51234;
static void Main(string[] args)
{
var server = new Server
{
Services = { Greeter.BindService(new GreeterImpl()) },
Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
};
server.Start();
Console.WriteLine("Greeter server listening on port " + Port);
Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();
server.ShutdownAsync().Wait();
}
}
class GreeterImpl : Greeter.GreeterBase
{
// Server side handler of the SayHello RPC
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
通過dotnet run
命令啟動此服務端。
之後再進入gRPCClient文件夾,加入同樣的類庫包。
在csproj文件中加入類似的配置,註意GrpcServices屬性改為了Client:
<ItemGroup>
<Protobuf Include="../protos/*.proto" OutputDir="protos" CompileOutputs="false" GrpcServices="Client" />
</ItemGroup>
運行dotnet build
,同樣生成protos文件夾及兩個proto文件。
Program類中加入客戶端調用代碼。
static void Main(string[] args)
{
var channel = new Channel("127.0.0.1:51234", ChannelCredentials.Insecure);
var client = new Greeter.GreeterClient(channel);
var reply = client.SayHello(new HelloRequest { Name = "Ken" });
Console.WriteLine(reply.Message);
channel.ShutdownAsync().Wait();
Console.ReadKey();
}
運行客戶端後,應該就可以看到調用服務端方法後返回的結果。
.NET Core 3.0
在最新的.NET Core 3.0中,加入了對gRPC更多的支持。當創建一個Web項目時,選擇ASP.NET Core 3.0,可以發現新增了gRPC Service項目模板。
從建立的項目代碼中可以看出其不再是普通的Web應用,而是完全變成了gRPC的服務端。
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// Communication with gRPC endpoints must be made through a gRPC client.
// To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909
endpoints.MapGrpcService<GreeterService>();
});
}