.NET CORE 构建 gRPC服务

239

1. gRPC 概述

gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架

2. gRPC 的主要优点

  1. 现代高性能轻量级 RPC 框架。

  2. 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现。

  3. 可用于多种语言的工具,以生成强类型服务器和客户端。

  4. 支持客户端、服务器和双向流式处理调用。

  5. 使用 Protobuf 二进制序列化减少对网络的使用。

Protobuf 二进制序列化是一种将结构化数据编码为二进制格式的过程,以便于存储或网络传输。这种格式相比于文本格式(如JSON或XML),通常具有更小的体积和更快的解析速度

3. gRPC 适用场景

  1. 效率至关重要的轻量级微服务

  2. 需要多种语言用于开发的 Polyglot 系统

  3. 需要处理流式处理请求或响应的点对点实时服务

4. .proto文件

gRPC 使用协定优先方法进行 API 开发。 在 .proto 文件中定义服务和消息

// 指明版本,使用proto3的语法
syntax = "proto3";

// 将 greet.proto 文件中的命名空间更新为项目的命名空间
option csharp_namespace = "GRPCS.Protos";

// 指定包名
package greet;

// 服务定义
service Greeter {
  // 方法定义
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// 请求消息定义
message HelloRequest {
  // 请求消息参数定义
  string name = 1;
}

// 响应消息定义
message HelloReply {
  // 响应消息参数定义
  string message = 1;
}

消息定义中的每个字段都有一个唯一的编号。 消息序列化为 Protobuf 时,字段编号用于标识字段。 序列化一个小编号比序列化整个字段名称要快。 因为字段编号标识字段,所以在更改编号时务必小心

5. 根据 .proto文件 生产C#资产

通过在项目中包含 .proto 文件,可自动生成用于服务、客户端和消息的 .NET 类型

  <!--将 gRPC 服务添加到 ASP.NET Core 应用,gRPC 需要 Grpc.AspNetCore 包-->
  <ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.67.0" />
  </ItemGroup>
  <!--将 .proto 文件添加到 <Protobuf> 项目组-->
  <ItemGroup>
    <Protobuf Include="**/*.proto" OutputDir="Protos" CompileOutputs="false" GrpcServices="Both" />
  </ItemGroup>

默认情况下,<Protobuf> 引用将生成具体的客户端和服务基类。可使用引用元素的 GrpcServices 特性来限制 C# 资产生成。有效 GrpcServices 选项如下:

  • Both (如果不存在,则为默认值,继生成服务端资产,也生成客户端资产)

  • Server(仅生成服务器资产)

  • Client (仅生成客户端资产)

  • None

需要工具包 Grpc.Tools 才能从 .proto 文件生成 C# 资产。服务端和客户端项目都需要此包。

Grpc.AspNetCore 包中包含对 Grpc.Tools 的引用。

6. 基于生成的 C# 资产,编写具体服务端逻辑实现

工具包会生成表示在所包含 .proto 文件中定义的消息的 C# 类型。对于服务器端资产,会生成抽象服务基类型。

基类型包含 .proto 文件中所含的所有 gRPC 调用的定义。

创建一个派生自此基类型并为 gRPC 调用实现逻辑的具体服务实现。

    /// <summary>
    /// 继承服务定义而生成的抽象服务基类型
    /// </summary>
    public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 重写服务定义而生成的方法
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }

如果服务由 ASP.NET Core gRPC 托管,则应使用 MapGrpcService 方法将其添加到路由管道

app.MapGrpcService<GreeterService>();

若是使用的Startup启动类:则在启动类内使用 MapGrpcService 方法添加到路由管道

// 使用MapControllers
app.UseEndpoints(endpoints =>
{
   endpoints.MapGrpcService<GreeterService>();
});

7. 基于生成的C#资产,编写具体客户端逻辑实现

对于客户端资产,会生成一个具体客户端类型。 .proto 文件中的 gRPC 调用会转换为具体类型中的方法,可以进行调用。

using Grpc.Net.Client;
using GRPCS.Protos;

using var channel = GrpcChannel.ForAddress("https://localhost:7220");
var greeterClient = new Greeter.GreeterClient(channel);
var sayHelloReply =await greeterClient.SayHelloAsync(new HelloRequest() { Name="张三" });
Console.WriteLine("Greeting: " + sayHelloReply.Message);

8. 测试RPC服务

使用 gRPCurl 和 gRPCui 测试 gRPC 服务

设置 gRPC 反射 , gRPC ASP.NET Core 包含 Grpc.AspNetCore.Server.Reflection 包,因此具有对 gRPC 反射的内置支持。

  • 在应用中配置反射: 添加 Grpc.AspNetCore.Server.Reflection 包引用。

  • 在 Program.cs 中注册反射: AddGrpcReflection 用于注册启用反射的服务。

  • MapGrpcReflectionService 用于添加反射服务终结点。

builder.Services.AddGrpc();
builder.Services.AddGrpcReflection();

var app = builder.Build();

app.MapGrpcService<GreeterService>();

IWebHostEnvironment env = app.Environment;

if (env.IsDevelopment())
{
    app.MapGrpcReflectionService();
}

gRPCurl 是一种开源命令行工具,可提供与 gRPC 服务的交互, gRPCui 基于 gRPCurl,并为 gRPC 添加开源交互式 Web UI

2025-03-17-kltoqtsl.png

使用Bloomrpc客户端

下载Bloomrpc客户端

https://github.com/bloomrpc/bloomrpc/releases/tag/1.5.3

2025-03-17-upbsreup.png

9. 收集和链路追踪

使用 DiagnosticSource (诊断源)的最简单方法是在应用中配置遥测库,如 DiagnosticSource 或 OpenTelemetry。 该库将与其他应用遥测一起处理有关 gRPC 调用的信息。 可以在托管服务(如 Application Insights)中查看跟踪,或运行自己的分布式跟踪系统。 OpenTelemetry 支持将跟踪数据导出到 Jaeger 和 Zipkin。

https://github.com/open-telemetry/opentelemetry-dotnet

https://opentelemetry.io/

10. 参考资料

https://learn.microsoft.com/zh-cn/aspnet/core/grpc/?view=aspnetcore-8.0https://learn.microsoft.com/zh-cn/aspnet/core/grpc/protobuf?view=aspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/grpc/protobuf?view=aspnetcore-9.0#scalar-value-typeshttps://learn.microsoft.com/zh-cn/aspnet/core/grpc/test-tools?view=aspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/grpc/protobuf?view=aspnetcore-9.0#nullable-typeshttps://protobuf.dev/programming-guides/proto3/#simple