【gRPC】 在.Net core中使用gRPC


最近在學習.net core的微服務體系架構。微服務之間的通信常常通過gRPC進行同步通信,但是需要注意的是,大多數微服務之間的通信是通過事件總線進行異步通信。在微軟介紹.net微服務體系架構的項目eShop中,微服務之間進行同步通信的場景很多,大多數都是HTTP/REST,目前只有自定義聚合器與微服務之間通信是使用的gRPC。整套微服務架構體系,其實除了客戶端與網關(BFF)之間,使用HTTP/REST,均可使用gRPC(只要網關支持HTTP/REST與gRPC的轉換)

  • BFF轉發外部請求
  • 微服務之間
  • 自定義聚合器與微服務

1.gRPC是什么?

A high-performance, open-source universal RPC framework

gRPC是一個高性能的通信協議,它基於HTTP/2protocol buffers。它是微服務之間進行同步通信的主要選擇。與之相對的,就是其他協議,如AMQP的異步通信隊列或者發布/訂閱模式。

RPC(remote procedure call 遠程過程調用)框架實際是提供了一套機制,使得應用程序之間可以進行通信,而且也遵從server/client模型。使用的時候客戶端調用server端提供的接口就像是調用本地的函數一樣.

與HTTP/JSON相比,gRPC的優勢:

  • 高性能:協議緩沖區是一種二進制的高性能序列化機制。根據語言的不同,實現協議緩沖區的速度比JSON序列化快8倍,而消息的大小可能比JSON序列化小60%-80%。
  • 支持數據流,說白了,還是快
  • 約定顯示,與語言無關:使用proto文件定義服務端與客戶端之間的約定

2.在.net core中使用gRPC

在.NET Core 3.0眾多更新中,其中有一個重要的更新就是對gRPC的原生支持。從.NET Core3.0開始,無論是開發工具還是框架中,都與gRPC進行了深度的集成,這讓使用gRPC的體驗如絲般順滑。

真的有這么絲滑嗎?

2.1 工具

工具集成-絲滑享受,主要體現在msbuild,開發者可以直接使用宇宙第一IDE:Vistual Studio或者.NET Core SDK命令dotnet build,通過.proto文件去生成需要的gRPC服務端和客戶端代碼。這里有兩個必要條件:

安裝工具包

Google.Protobuf,Grpc.Tools

Install-Package Google.Protobuf -Version 3.12.2
Install-Package Grpc.Tools -Version 2.29.0

.proto的引用

proto文件必須在.csproj中引用。在 中使用 標簽。

<ItemGroup>
   <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
   <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

其中GrpcServices屬性:指明生成的代碼是客戶端還是服務端,或者Both(這是默認值)。當編譯代碼時(無論是通過運行Visual StudioBuild還是dotnet build),所有代碼都將生成並放在obj文件夾中。這是微軟故意這樣做的,因為這些代碼不應該出現在源代碼控制存儲庫中,他們都是生成的,只要.proto文件在,他們都能隨時生成。

2.2 實際使用的技巧-親測有用

參考曉晨博客

主要目標

  • 讓客戶端和服務端共用一個Protos文件夾,避免重復
  • 使用MSBuild變量在csproj中添加Protobuf標簽,避免繁瑣修改csproj

服務端

 <ItemGroup>
    <Protobuf Include="..\Protos\*.proto" GrpcServices="Server" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" />
  </ItemGroup>

客戶端

  <ItemGroup>
    <Protobuf Include="..\Protos\*.proto" GrpcServices="Client" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" />
  </ItemGroup>
  • Include:加通配符的路徑,去指定proto文件的路徑

3.創建服務端

3.1 安裝包

創建gRPC服務端,需要包Grpc.AspNetCore

Install-Package Grpc.AspNetCore -Version 2.29.0

很幸運,VS2019已經為我們准備好服務端的模板。我們可以創建一個gRPC服務端項目。這個模板已經引入了Grpc.AspNetCore包。你可以在模板中搜到的。

3.2 引入proto文件

<ItemGroup>
    <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

當然這,模板已經為我們生成了。並且生成了GreeterService.cs

3.3 加入gRPC管道

  • gRPC添加到終結點路由中
app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<GreeterService>();

                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
            });

ASP.NET Core 中間件和功能共享路由管道,因此可以將應用配置為提供其他請求處理程序。 其他請求處理程序與已配置的 gRPC 服務並行工作。

  • 注冊服務
 public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }

當然這,模板已經為我們生成了,不要模板自己刀耕火種也是可以的。

4.創建客戶端

4.1 安裝包

創建gRPC客戶端,需要包Google.Protobuf,Grpc.ToolsGrpc.Net.Client

Install-Package Google.Protobuf -Version 3.12.2
Install-Package Grpc.Tools -Version 2.29.0
Install-Package Grpc.Net.Client -Version 2.29.0

4.2 引入與服務端相同的proto文件

  <ItemGroup>
    <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
  </ItemGroup>

4.3 編碼

static async Task Main(string[] args)
{
    Console.WriteLine("Hello gRPC!");
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
            
	var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var greeterClient = new Greeter.GreeterClient(channel);
    
    //https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0&WT.mc_id=DT-MVP-5003133
    var reply = await greeterClient.SayHelloAsync(new HelloRequest
    {
        Name = "Garfield"
    });
    Console.WriteLine("Greeter 服務返回數據: " + reply.Message);
    Console.ReadKey();

            
    //var counterClient = new Count.CounterClient(channel);
    //// This switch must be set before creating the GrpcChannel/HttpClient.
    //AppContext.SetSwitch(
    //    "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    //// The port number(5000) must match the port of the gRPC server.
    //var channel = GrpcChannel.ForAddress("http://localhost:5000");
    //var client = new Greet.GreeterClient(channel);
}

5.微服務中使用

如引言所述,gRPC主要用於微服務之間同步通信。

主要運用場景,已經根據業務划分的多個微服務無法滿足實際出現的業務場景,需要聯合多個微服務進行業務處理。沒錯,這就是微服務架構體系中的自定義聚合器,實際上聚合器也是一種微服務,負責聚合多個微服務提供較粒度更小的微服務更為強大的自定義微服務。至於使用方式,依然是引入Grpc.Net.Client包,此包本來就是HttpClient基礎上實現的,大可以把此當作一個gPRC的HttpClient使用。

6.配置無TLS的gRPC

6.1 服務端配置

gRPC只支持HTTP/2。通常,當客戶端連接到服務端時,連接使用HTTP1.1完成,只有當服務器和客戶端都支持HTTP/2時才提升為HTTP/2,這就是協議提升,實際上,同類似的, Websocket就是這樣通過http操作,走協議提升。這個協議提升使用協議協商執行,通常需要使用ALPN協議實現,這個協議要求必須TLS。

這意味着,在默認情況下,您需要啟用一個TLS端點,以便能夠使用gRPC。

但是,這里有一個但是,在內部的微服務中,可能是沒有啟用TLS的,也沒必要,因為大家都是自己人,取消TLS,提高效率。在這種情況下,你有兩個選擇:

  • 打開一個Kestrel,監聽HTTP/2
  • 打開兩個Kestrel,一個監聽HTTP1.1,另一個監聽HTTP/2

如果您的服務器除了支持gRPC客戶端還必須支持HTTP1.1客戶端,則需要第二個選項。下面的代碼就是展示了第二種方法(Program.cs):

WebHost.CreateDefaultBuilder(args)
    .ConfigureKestrel(options =>
    {
        options.Listen(IPAddress.Any, 5000, listenOptions =>
        {
            listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
        });
         //Setup a HTTP/2 endpoint without TLS.
        options.Listen(IPAddress.Any, 5001, listenOptions =>
        {
            listenOptions.Protocols = HttpProtocols.Http2;
        });
    })
  • 5000:提供http web api
  • 5001:提供gRPC

6.2 在.NET Core客戶端調用

但是,這還不夠,我們需要告訴gRPC客戶端,客戶端可以直接連接到HTTP/2端點,而不需要TLS,口頭或者文檔說明。

在默認情況下.NET Core不允許gRPC客戶端連接到非TLS(non-TLS)端點-不安全的gRPC的服務,十有八九都會報異常

Unhandled exception. System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

那么怎么辦,就需要如下代碼:

// This switch must be set before creating the GrpcChannel/HttpClient.
AppContext.SetSwitch(
    "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

// The port number(5000) must match the port of the gRPC server.
var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new Greet.GreeterClient(channel);

上述設置只能在客戶端開始時設置一次。

7.配置TLS的gRPC

毫無疑問,微服務場景之外的gRPC服務還是需要TLS的。

7.1 方法一:appsetting.json

{
  "Kestrel": {
    "Endpoints": {
      "HttpsInlineCertFile": {
        "Url": "https://localhost:5001",
        "Protocols": "Http2",
        "Certificate": {
          "Path": "<path to .pfx file>",
          "Password": "<certificate password>"
        }
      }
    }
  }
}

7.2 方法二:Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.Listen(IPAddress.Any, 5001, listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http2;
                    listenOptions.UseHttps("<path to .pfx file>", 
                        "<certificate password>");
                });
            });
            webBuilder.UseStartup<Startup>();
        });

8.寫在末尾

Azure App Service 和IIS目前都還不支持gRPC. 另外Http.Sys也不支持gRPC所依賴的HTTP響應。詳情請看github issues

參考鏈接

https://grpc.io/

https://www.cnblogs.com/shanyou/p/3452938.html

https://blog.csdn.net/yangguosb/article/details/80592777

https://docs.microsoft.com/zh-cn/aspnet/core/grpc/aspnetcore?view=aspnetcore-3.1&tabs=visual-studio

https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.1

https://www.cnblogs.com/stulzq/p/11581967.html


作者:Garfield

同步更新至個人博客:http://www.randyfield.cn/

本文版權歸作者所有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系287572291@qq.com


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM