首頁 > 軟體

用 FieldMask 提高 C# gRpc 的服務效能

2022-03-02 19:02:16

前言:

想象一下,有一個服務提供個多個使用者端呼叫,但不是所有使用者端都需要全部的返回引數:

​比如商品列表服務返回商品的所有資訊,而訂單服務呼叫商品列表服務,但它其實只需要商品的編碼和名稱就夠了。​

當然,我們可以為這個需求單獨建立一個服務,但是這樣不太靈活,比如又需要商品的編碼和分類的時候怎麼辦?

但是,大而全的服務方法會導致計算和傳輸成本可能很高,如果我們能夠了解響應中哪些欄位不需要提供給呼叫者,從而避免進行不必要的計算和傳輸,這對提高服務效能通常是非常有益的。

在實現 gRPC 服務時,我們可以使用​protobuf FieldMask ​實現上述功能。

一.FieldMask

預設情況下,gRPC 使用 protobuf 作為其介面定義語和資料序列化協定。

FieldMask 是一個 protobuf 訊息,包含一個名為 paths 的欄位,用於指定用於指定讀取操作返回或更新操作修改的欄位:

message FieldMask {
  repeated string paths = 1;
}

下面,讓我們看一個例子,如何在C# gRpc 服務中使用它。

二、Demo

​1.定義 .proto 檔案​

在 .proto 檔案中定義服務和訊息:

syntax = "proto3";

option csharp_namespace = "GrpcService2";
import "google/protobuf/field_mask.proto";

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;
  google.protobuf.FieldMask field_mask = 2;
}

// The response message containing the greetings.
message HelloReply {
  string message1 = 1;
  string message2 = 2;
  string message3 = 3;
  string message4 = 4;
  string message5 = 5;
}

關鍵點是下面2句:

// 參照 field_mask 訊息
import "google/protobuf/field_mask.proto";

//定義請求欄位
google.protobuf.FieldMask field_mask = 2;

​2.實現伺服器端​

伺服器端程式碼如下,返回了5個欄位:

public class GreeterService : Greeter.GreeterBase
{
    private readonly ILogger<GreeterService> _logger;
    public GreeterService(ILogger<GreeterService> logger)
    {
        _logger = logger;
    }

    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        var reply = new HelloReply
        {
            Message1 = "Hello " + request.Name + ",這是第1條訊息",
            Message2 = "Hello " + request.Name + ",這是第2條訊息",
            Message3 = "Hello " + request.Name + ",這是第3條訊息",
            Message4 = "Hello " + request.Name + ",這是第4條訊息",
            Message5 = "Hello " + request.Name + ",這是第5條訊息"
        };

        return Task.FromResult(reply);
    }
}

​3.實現使用者端​

使用者端程式碼如下:

using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

FieldMask fieldMask = new FieldMask();
fieldMask.Paths.AddRange(new string[] { "message2", "message4" });

var request = new HelloRequest { Name = "My IO" };
request.FieldMask = fieldMask;

var reply = await client.SayHelloAsync(request);
            Console.WriteLine($@"Greeting: 
{reply.Message1}
{reply.Message2}
{reply.Message3}
{reply.Message4}
{reply.Message5}
" );

傳入了 FieldMask,這裡只需要 message2message4 欄位。

執行程式,發現有問題,還是返回了所有欄位:

​4.修改伺服器端​

這其實是在伺服器端沒有判斷 fieldMask,修改伺服器端程式碼:

var mergedReply = new HelloReply();
request.FieldMask.Merge(reply, mergedReply);

return Task.FromResult(mergedReply);

結論:

在本文中,我們看到了如何使用 FieldMask ,這裡僅僅是控制不返回欄位,大家可以自行實現其他邏輯。

到此這篇關於用 FieldMask 提高 C# gRpc 的服務效能的文章就介紹到這了,更多相關用 FieldMask 提高 C# gRpc 的服務效能內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com