.NET Core微服务开发服务间调用篇-GRPC
在單體應用中,相互調用都是在一個進程內部調用,也就是說調用發生在本機內部,因此也被叫做本地方法調用;在微服務中,服務之間調用就變得比較復雜,需要跨網絡調用,他們之間的調用相對于與本地方法調用,可稱為遠程過程調用,簡稱RPC(Remote procedure call)。
看過上篇API網關篇,知道案例中包含商品、訂單兩個微服務,本文將會演示如何采用開源的,高性能rpc框架(grpc),通過訂單微服務調用產品微服務內的接口。沒有看過上篇文章不影響,我先提供下項目代碼結構圖,方便你閱讀。下面將會一步一步分享如何使用Grpc進行服務之間調用。
步驟1:首先定義服務鍥約-proto文件
1.創建類庫(.NET Standard),作為服務契約項目,命名為-AAStore.ProductCatalog.DataContracts如圖:
2.安裝三個nuget包
Google.Protobuf Grpc Grpc.Tools3.開始定義proto文件:product.api.proto
syntax = <span data-raw-text="" "="" data-textnode-index="11" data-index="445" class="character">"proto3<span data-raw-text="" "="" data-textnode-index="11" data-index="452" class="character">";optioncsharp_namespace = <span data-raw-text="" "="" data-textnode-index="15" data-index="480" class="character">"AAStore.ProductCatalog.Api.V1<span data-raw-text="" "="" data-textnode-index="15" data-index="510" class="character">"; packageAAStore;serviceProductApi{rpcGetProduct(GetProductRequest) returns(GetProductResponse); }//請求消息體 messageGetProductRequest{ int32Id=1; } //返回消息體 messageGetProductResponse{ stringproductName=1; }Grpc協議使用Protobuf簡稱proto文件來定義接口名、調用參數以及返回值類型。比如product.api.proto文件,定義一個接口GetProduct方法,它的請求結構體是GetProductRequest,包含一個int類型的id屬性,它的返回結構體GetProductResponse包含一個輸出string類型的產品名稱屬性。
4.添加product.api.proto文件到項目中,雙擊項目或者右鍵-》編輯項目文件,添加一下代碼
<ItemGroup> <Protobuf Include=<span data-raw-text="" "="" data-textnode-index="58" data-index="972" class="character">"..\Schema\grpc\v1\product.api.proto<span data-raw-text="" "="" data-textnode-index="58" data-index="1008" class="character">"GrpcServices=<span data-raw-text="" "="" data-textnode-index="60" data-index="1023" class="character">"Both<span data-raw-text="" "="" data-textnode-index="60" data-index="1028" class="character">"Link=<span data-raw-text="" "="" data-textnode-index="62" data-index="1035" class="character">"product.api.proto<span data-raw-text="" "="" data-textnode-index="62" data-index="1053" class="character">"/> </ItemGroup>然后build項目,此時gprc代碼已經生成了,在obj文件項目,如圖
步驟2:Grpc服務端實現
選擇項目AAStore.ProductCatalog(詳情見項目代碼結構圖)安裝包Grpc.AspNetCore,同時添加引用項目AAStore.ProductCatalog.DataContracts
<ItemGroup> <PackageReference Include=<span data-raw-text="" "="" data-textnode-index="74" data-index="1262" class="character">"Grpc.AspNetCore<span data-raw-text="" "="" data-textnode-index="74" data-index="1278" class="character">"Version=<span data-raw-text="" "="" data-textnode-index="76" data-index="1288" class="character">"2.29.0<span data-raw-text="" "="" data-textnode-index="76" data-index="1295" class="character">"/> </ItemGroup><ItemGroup> <ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="85" data-index="1356" class="character">"..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj<span data-raw-text="" "="" data-textnode-index="85" data-index="1440" class="character">"/> </ItemGroup>然后定義獲取產品方法的邏輯和實現,供產品api站點項目調用
publicTask<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context) { returnTask.FromResult(newGetProductResponse { //todo 具體的邏輯下面代碼僅為顯示 ProductName = <span data-raw-text="" "="" data-textnode-index="110" data-index="1730" class="character">"測試商品grpc<span data-raw-text="" "="" data-textnode-index="112" data-index="1739" class="character">" }) ; }選擇AAStore.ProductCatalog.Api產品api項目添加引用項目AAStore.ProductCatalog
<ItemGroup> <ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="121" data-index="1871" class="character">"..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj<span data-raw-text="" "="" data-textnode-index="121" data-index="1927" class="character">"/> </ItemGroup>新增ProductServices.cs并繼承ProductApiBase類,實現grpc服務
public classProductServices : ProductApi.ProductApiBase { public override Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context) { return newGrpcProductServices().GetProduct(request, context); } }由于AAStore.ProductCatalog.Api項目不是通過grpc模板項目創建的,所以在Startup類中手工添加gprc服務和中間件代碼:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddGrpc(); }app.UseEndpoints(endpoints => { endpoints.MapGrpcService<ProductServices>(); endpoints.MapControllers(); });最后在Program文件配置站點啟動監聽8081端口,我們并運行它
webBuilder.ConfigureKestrel(options => { // Setup a HTTP/2 endpoint without TLS. options.ListenLocalhost(8081, o => o.Protocols = HttpProtocols.Http2); });步驟3:Grpc客戶端實現-調用Grpc服務
選擇AAStore.Orde項目(具體見項目代碼結構圖),安裝Grpc.AspNetCore包,并且添加項目引用AAStore.ProductCatalog.DataContracts
<ItemGroup> <ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="171" data-index="3123" class="character">"..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj<span data-raw-text="" "="" data-textnode-index="171" data-index="3207" class="character">"/> </ItemGroup><ItemGroup> <PackageReference Include=<span data-raw-text="" "="" data-textnode-index="180" data-index="3268" class="character">"Grpc.AspNetCore<span data-raw-text="" "="" data-textnode-index="180" data-index="3284" class="character">"Version=<span data-raw-text="" "="" data-textnode-index="182" data-index="3294" class="character">"2.29.0<span data-raw-text="" "="" data-textnode-index="182" data-index="3301" class="character">"/> </ItemGroup>新建ProductGateway.cs,封裝產品微服務公開grpc服務的調用
publicclassProductGateway { privatereadonlyProductApiClient _client; publicProductGateway() { AppContext.SetSwitch(<span data-raw-text="" "="" data-textnode-index="206" data-index="3514" class="character">"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport<span data-raw-text="" "="" data-textnode-index="206" data-index="3573" class="character">", true); _client = newProductApiClient(GrpcChannel.ForAddress(<span data-raw-text="" "="" data-textnode-index="213" data-index="3648" class="character">"http://localhost:8081<span data-raw-text="" "="" data-textnode-index="213" data-index="3670" class="character">"));//TODO 根據動態配置 }publicasyncTask<GetProductResponse> GetProduct(GetProductRequest request) { returnawait_client.GetProductAsync(request); } }新建OrderService.cs,添加GetOrder方法,在其方法內調用產品微服務GetProduct方法
publicasyncTask<string> GetOrder() { varproductModel = await_productGateway.GetProduct(newGetProductRequest() { Id = 1}); return$<span data-raw-text="" "="" data-textnode-index="256" data-index="4081" class="character">"Order Service=>從產品微服務獲取產品信息:{productModel.ProductName}<span data-raw-text="" "="" data-textnode-index="259" data-index="4136" class="character">"; }然后在訂單控制器中調用
[Route(<span data-raw-text="" "="" data-textnode-index="264" data-index="4167" class="character">"api/[controller]<span data-raw-text="" "="" data-textnode-index="264" data-index="4184" class="character">")] [ApiController] publicclassOrderController: ControllerBase { privatereadonlyRestOrderService _restOrderService; publicOrderController() { _restOrderService = newRestOrderService(); } [HttpGet(template:<span data-raw-text="" "="" data-textnode-index="294" data-index="4451" class="character">"Get<span data-raw-text="" "="" data-textnode-index="294" data-index="4455" class="character">")] publicasyncTask<string> GetOrder() { returnawait_restOrderService.GetOrder(); } }至此,客戶端代碼已經完成,我們運行來看看
通過網關訪問訂單服務,查看調用結果
我們發現結果也是一樣的,以上演示了如何使用grpc進行服務間的調用,最后使用一張圖作結。
總結
以上是生活随笔為你收集整理的.NET Core微服务开发服务间调用篇-GRPC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux内核:容器底层cgroup如何
- 下一篇: 基于.NetCore3.1搭建项目系列