原文在本人公衆號中,歡迎關注我,時不時的會分享一些心得前端
HTTP和RPC是現代微服務架構中很經常使用的數據傳輸方式,二者有不少類似之處,可是又有很大的不一樣。HTTP是一種規範性、通用性、很是標準的傳輸協議,幾乎全部的語言都支持,若是要確保各平臺無縫銜接,能夠考慮使用HTTP協議,例如如今常規的RestFUL,整個傳輸過程一般使用Json數據格式。以致於不論是前端仍是後端均可以很好的對接。
RPC協議不只僅是服務間通訊協議,甚至是進程間也存在。能夠下降諸多微服務之間調用成本,屏蔽了通信細節,調用遠程方法處理數據時像調用本地方法同樣絲滑順暢。可是對前端和瀏覽器不是特別友好。
GRPC是google制定實現的一種Rpc形式,官網解釋是:web
gRPC是能夠在任何環境中運行的現代開源高性能RPC框架。它能夠經過可插拔的支持來有效地鏈接數據中心內和跨數據中心的服務,以實現負載平衡,跟蹤,運行情況檢查和身份驗證。它也適用於分佈式計算的最後一英里,以將設備,移動應用程序和瀏覽器鏈接到後端服務。後端
<ItemGroup> <Protobuf Include="Protos\greet.proto" GrpcServices="Client" /> </ItemGroup>
我本人習慣將生成的server和client放在一塊兒,打包後供client端和server端使用,只須要這樣設置:瀏覽器
<ItemGroup> <Protobuf Include="Protos\greet.proto" GrpcServices="Server;Client" /> </ItemGroup>
配置好後從新生成項目,grpctool會自動生成服務端,客戶端代碼。數據結構
client調用方式(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);
<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" />
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" }); } }
public class GrpcServer:IHostedService { private readonly GrpcExampleService.GrpcExampleServiceBase _sampleServiceBase; public GrpcServer(GrpcExampleService.GrpcExampleServiceBase sampleServiceBase) { _sampleServiceBase = sampleServiceBase; } /// <summary> /// 啓動本身定義的rpc服務 /// </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服務:框架
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; } } }
注意:這裏應該將proto協議 服務端客戶端端進行分離,協議生成的代碼打包後 被客戶端項目和服務端項目引用,這裏只是爲了簡便客戶端直接會引用服務,由於要用到GrpcExampleService.GrpcExampleServiceClientasp.net
上邊的todo 後再後續增長對應的功能。
這樣服務端就建立完了。接下來就是建立客戶端進行調用:分佈式
控制檯客戶端:
main中實現調用邏輯ide
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}"); }
而後就能夠了,啓動服務端,而後再啓動客戶端,就能夠看到調用結果了。