在單體應用中,相互呼叫都是在一個程式內部呼叫,也就是說呼叫發生在本機內部,因此也被叫做本地方法呼叫;在微服務中,服務之間呼叫就變得比較複雜,需要跨網路呼叫,他們之間的呼叫相對於與本地方法呼叫,可稱為遠端過程呼叫,簡稱RPC(Remote procedure call)。
看過上篇API閘道器篇,知道案例中包含商品、訂單兩個微服務,本文將會演示如何採用開源的,高效能rpc框架(grpc),通過訂單微服務呼叫產品微服務內的介面。沒有看過上篇文章不影響,我先提供下專案程式碼結構圖,方便你閱讀。下面將會一步一步分享如何使用Grpc進行服務之間呼叫。
步驟1:首先定義服務鍥約-proto檔案
1.建立類庫(.NET Standard),作為服務契約專案,命名為-AAStore.ProductCatalog.DataContracts如圖:
2.安裝三個nuget包
Google.Protobuf
Grpc
Grpc.Tools
3.開始定義proto檔案:product.api.proto
syntax = "proto3"; option csharp_namespace = "AAStore.ProductCatalog.Api.V1"; package AAStore; service ProductApi{ rpc GetProduct(GetProductRequest) returns (GetProductResponse); } //請求訊息體 message GetProductRequest{ int32 Id=1; } //返回訊息體 message GetProductResponse{ string productName=1; }
Grpc協議使用Protobuf簡稱proto檔案來定義介面名、呼叫引數以及返回值型別。比如product.api.proto檔案,定義一個介面GetProduct方法,它的請求結構體是GetProductRequest,包含一個int型別的id屬性,它的返回結構體GetProductResponse包含一個輸出string型別的產品名稱屬性。
4.新增product.api.proto檔案到專案中,雙擊專案或者右鍵-》編輯專案檔案,新增一下程式碼
<ItemGroup> <ProjectReference Include="..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj" /> </ItemGroup>
然後build專案,此時gprc程式碼已經生成了,在obj檔案專案,如圖
步驟2:Grpc服務端實現
選擇專案AAStore.ProductCatalog(詳情見專案程式碼結構圖)安裝包Grpc.AspNetCore,同時新增引用專案AAStore.ProductCatalog.DataContracts
<ItemGroup> <PackageReference Include="Grpc.AspNetCore" Version="2.29.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj" /> </ItemGroup>
然後定義獲取產品方法的邏輯和實現,供產品api站點專案呼叫
public class GrpcProductServices { public Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context) { return Task.FromResult(new GetProductResponse { //todo 具體的邏輯 下面程式碼僅為顯示 ProductName = "測試商品grpc" }) ; } }
選擇AAStore.ProductCatalog.Api產品api專案新增引用專案AAStore.ProductCatalog
<ItemGroup> <ProjectReference Include="..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj" /> </ItemGroup>
新增ProductServices.cs並繼承ProductApiBase類,實現grpc服務
public class ProductServices : ProductApi.ProductApiBase { public override Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context) { return new GrpcProductServices().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="..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj" />
</ItemGroup>
新建ProductGateway.cs,封裝產品微服務公開grpc服務的呼叫
public class ProductGateway { private readonly ProductApiClient _client; public ProductGateway() { AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); _client = new ProductApiClient(GrpcChannel.ForAddress("http://localhost:8081"));//TODO 根據動態配置 } public async Task<GetProductResponse> GetProduct(GetProductRequest request) { return await _client.GetProductAsync(request); } }
新建OrderService.cs,新增GetOrder方法,在其方法內呼叫產品微服務GetProduct方法
public async Task<string> GetOrder() { var productModel = await _productGateway.GetProduct(new GetProductRequest() { Id = 1 }); return $"Order Service=>從產品微服務獲取產品資訊:{productModel.ProductName}"; }
然後在訂單控制器中呼叫
[Route("api/[controller]")] [ApiController] public class OrderController : ControllerBase { private readonly RestOrderService _restOrderService; public OrderController() { _restOrderService = new RestOrderService(); } [HttpGet(template:"Get")] public async Task<string> GetOrder() { return await _restOrderService.GetOrder(); } }
至此,客戶端程式碼已經完成,我們執行來看看
通過閘道器訪問訂單服務,檢視呼叫結果
我們發現結果也是一樣的,以上演示瞭如何使用grpc進行服務間的調用,最後使用一張圖作結。