原文在本人公眾號中,,歡迎關(guān)注我,,時(shí)不時(shí)的會分享一些心得
HTTP和RPC是現(xiàn)代微服務(wù)架構(gòu)中很常用的數(shù)據(jù)傳輸方式,兩者有很多相似之處,但是又有很大的不同,。HTTP是一種規(guī)范性,、通用性、非常標(biāo)準(zhǔn)的傳輸協(xié)議,,幾乎所有的語言都支持,,如果要確保各平臺無縫銜接,可以考慮使用HTTP協(xié)議,,例如現(xiàn)在常規(guī)的RestFUL,,整個傳輸過程通常使用Json數(shù)據(jù)格式。以至于不管是前端還是后端都可以很好的對接,。 RPC協(xié)議不僅僅是服務(wù)間通信協(xié)議,,甚至是進(jìn)程間也存在??梢越档椭T多微服務(wù)之間調(diào)用成本,,屏蔽了通訊細(xì)節(jié),調(diào)用遠(yuǎn)程方法處理數(shù)據(jù)時(shí)像調(diào)用本地方法一樣絲滑順暢,。但是對前端和瀏覽器不是特別友好,。 GRPC是google制定實(shí)現(xiàn)的一種Rpc形式,官網(wǎng)解釋是: gRPC是可以在任何環(huán)境中運(yùn)行的現(xiàn)代開源高性能RPC框架,。它可以通過可插拔的支持來有效地連接數(shù)據(jù)中心內(nèi)和跨數(shù)據(jù)中心的服務(wù),以實(shí)現(xiàn)負(fù)載平衡,,跟蹤,,運(yùn)行狀況檢查和身份驗(yàn)證。它也適用于分布式計(jì)算的最后一英里,,以將設(shè)備,,移動應(yīng)用程序和瀏覽器連接到后端服務(wù)。
gRPC主要包括四個特點(diǎn):簡單的服務(wù)定義且不局限于語言:gRPC基于ProtoBuf協(xié)議構(gòu)建,,該協(xié)議提供了強(qiáng)大的系列化工具和語言定義服務(wù),。 跨語言和平臺:可自動為多語言或平臺生成客戶端和服務(wù)端內(nèi)容。 快速啟動和擴(kuò)展性:只需極少代碼就可以生成整個通訊環(huán)境,,可以擴(kuò)展數(shù)百萬rpc請求,。 雙向流和集成身份驗(yàn)證:基于HTTP/2的傳輸機(jī)制以及雙向流和而完全可集成的插入式身份驗(yàn)證機(jī)制。 ProtoBuf協(xié)議: 該協(xié)議是一種序列化結(jié)構(gòu)化數(shù)據(jù)的靈活,,高效,,自動化的機(jī)制,比xml更小,,更快,,更簡單。您定義要一次構(gòu)造數(shù)據(jù)的方式,然后可以使用生成的特殊源代碼輕松地使用各種語言在各種數(shù)據(jù)流中寫入和讀取結(jié)構(gòu)化數(shù)據(jù),。您甚至可以更新數(shù)據(jù)結(jié)構(gòu),,而不會破壞已針對“舊”格式編譯的已部署程序。 協(xié)議文件定義方式:
這是一個簡單的定義,,此文件在.proto文件中定義,,與語言無關(guān)。每個消息類型都有一個或多個唯一編號的字段,。每個字段都有一個名稱和一個值類型,,其中值類型可以是數(shù)字(整數(shù)或浮點(diǎn)數(shù)),布爾值,,字符串等,。定義好后可以使用編譯器生成對應(yīng)語言的操作對象。 更多協(xié)議內(nèi)容請參閱:https://developers.google.com/protocol-buffers/docs/overview,。
.net Core3.0 中的Grpc使用Visual Stduio 2019 創(chuàng)建一個gRPC服務(wù)
請注意:此處創(chuàng)建的是使用ASP.NET Core的Grpc服務(wù),。也就是說,有WebHost去托管服務(wù)的,。
后面,,我們使用Host通用主機(jī)進(jìn)行托管。 先來看看Startup類
圖中這兩行代碼是關(guān)鍵,,services.AddGrpc();將rpc注入到應(yīng)用程序服務(wù)中,, endpoints.MapGrpcService ();則是在中間件啟用監(jiān)聽rpc請求。 默認(rèn)情況下此時(shí)生成項(xiàng)目后,,proto文件只會生成Serve的代碼,。客戶端代碼生成需要單獨(dú)做配置,。 微軟文檔中是將proto文件拷貝到client中,,去生成client代碼。此時(shí)服務(wù)和客戶端生成配置就不一樣了:
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
我本人習(xí)慣將生成的server和client放在一起,,打包后供client端和server端使用,,只需要這樣設(shè)置: <ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server;Client" />
</ItemGroup>
配置好后重新生成項(xiàng)目,grpctool會自動生成服務(wù)端,,客戶端代碼,。 client調(diào)用方式(asp.net core gRPC): var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHello(
new HelloRequest { Name = "World" });
Console.WriteLine(response.Message);
接下來,我們創(chuàng)建一個簡單的示例創(chuàng)建兩個個Core控制臺項(xiàng)目并添加文件夾Protos和Services,,分別新增一個demo.proto文件和DemoService.cs文件 引入nuget包:
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
<PackageReference Include="Grpc" Version="2.24.0" />
<PackageReference Include="Grpc.Tools" Version="2.24.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
編輯csproj文件:使得支持同時(shí)生成client和server代碼(作為demo,,server端 應(yīng)該只作為server。生成client和server的代碼的應(yīng)該單獨(dú)抽出來) 服務(wù)端:重寫GrpcExampleService.GrpcExampleServiceBase中的rpc方法(也就是.proto文件生成的代碼內(nèi)容中的rpc服務(wù)方法)
public class DemoService: GrpcExampleService.GrpcExampleServiceBase
{
public override Task<AskResponse> Ask(AskRequest request, ServerCallContext context)
{
return Task.FromResult(new AskResponse {Content = "Hello from Ask"});
}
public override Task<ResponseModel> GetName(RequestModel request, ServerCallContext context)
{
return Task.FromResult(new ResponseModel { Name = "Hello Pluto" });
}
}
接下來就是創(chuàng)建啟動項(xiàng)(HOST)了(GrpcServer): 這次使用通用主機(jī),,不適用asp.net core webhost,。
public class GrpcServer:IHostedService
{
private readonly GrpcExampleService.GrpcExampleServiceBase _sampleServiceBase;
public GrpcServer(GrpcExampleService.GrpcExampleServiceBase sampleServiceBase)
{
_sampleServiceBase = sampleServiceBase;
}
/// <summary>
/// 啟動自己定義的rpc服務(wù)
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
GrpcServiceManager.Start(GrpcExampleService.BindService(_sampleServiceBase));
}, cancellationToken);
}
/// <summary>
/// 停止
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
GrpcServiceManager.Stop();
}, cancellationToken);
}
}
GrpcServiceManager中就是真正的啟動和停止grpc服務(wù): public class GrpcServiceManager
{
static Server server;
public static void Start(ServerServiceDefinition bindService)
{
if (bindService == null)
throw new ArgumentNullException("bindService");
var services = new List<ServerServiceDefinition>() { bindService };
Start(services); //todo 添加配置,,攔截器等等
}
private static void Start(List<ServerServiceDefinition> services)
{
try
{
server = new Server()
{
Ports = { new ServerPort("0.0.0.0", 8890, ServerCredentials.Insecure) }
};
foreach (var service in services)
{
server.Services.Add(service);
}
server.Start();
//todo consul 注冊
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public static void Stop()
{
try
{
server?.ShutdownAsync().Wait();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
注意:這里應(yīng)該將proto協(xié)議 服務(wù)端客戶端端進(jìn)行分離,協(xié)議生成的代碼打包后 被客戶端項(xiàng)目和服務(wù)端項(xiàng)目引用,,這里只是為了簡便客戶端直接會引用服務(wù),,因?yàn)橐玫紾rpcExampleService.GrpcExampleServiceClient
上邊的todo 后再后續(xù)增加對應(yīng)的功能。 這樣服務(wù)端就創(chuàng)建完了,。接下來就是創(chuàng)建客戶端進(jìn)行調(diào)用: 控制臺客戶端: main中實(shí)現(xiàn)調(diào)用邏輯 static void Main(string[] args)
{
var channel=new Grpc.Core.Channel("127.0.0.1",8890,ChannelCredentials.Insecure);
var democlient=new GrpcExampleService.GrpcExampleServiceClient(channel);
var res= democlient.Ask(new AskRequest
{
Cate = 0,
Key = "1312"
});
var res2 = democlient.GetName(new RequestModel
{
Key = "1313"
});
Console.WriteLine($"Ask={res}.GetName={res2}");
}
然后就可以了,,啟動服務(wù)端,然后再啟動客戶端,,就可以看到調(diào)用結(jié)果了,。
|