【.Net技术栈梳理】05-gRPC

文章目录

  • [1. gRPC 是什么?](#1. gRPC 是什么?)
  • [2. 核心概念与工作原理](#2. 核心概念与工作原理)
    • [2.1 接口定义先行:.proto 文件](#2.1 接口定义先行:.proto 文件)
    • [2.2 代码生成:protoc 编译器](#2.2 代码生成:protoc 编译器)
    • [2.3 通信模式](#2.3 通信模式)
  • [3 为什么选择 gRPC?优势与劣势](#3 为什么选择 gRPC?优势与劣势)
  • [4 gRPC 与 REST 的对比](#4 gRPC 与 REST 的对比)
  • [5 在 .NET 中使用 gRPC 的简单示例](#5 在 .NET 中使用 gRPC 的简单示例)

gRPC。这是一个极其重要的现代通信技术,尤其在高性能、分布式系统和微服务架构中扮演着核心角色。

1. gRPC 是什么?

gRPC 是一个高性能、开源、通用的** RPC(Remote Procedure Call)框架**,由 Google 开发并基于其多年的内部技术积累(最初是 Stubby)。

  • 核心思想:让你能够像调用本地方法一样调用远程服务器上的方法,而无需关心底层的网络通信、序列化/反序列化等复杂细节。
  • 官方定义:gRPC 是一个现代的、基于 HTTP/2 的 RPC 框架,它可以在任何环境中运行。
  • 关键特性
    • 跨语言:这是其最大优势之一。它支持所有主流编程语言(C++, Java, Python, Go, C#, Node.js, Ruby, Dart 等),这意味着一个用 C# 编写的服务端可以被 Go 或 Python 的客户端轻松调用。
    • 基于 Protocol Buffers (protobuf):默认使用 protobuf 作为接口定义语言(IDL) 和底层的消息序列化/反序列化协议。protobuf 是二进制格式,性能极高(序列化后体积小、速度快),远胜于 JSON/XML。
    • 基于 HTTP/2:这是其高性能的基石。HTTP/2 提供了多路复用、头部压缩、服务器推送等特性,使得 gRPC 连接更高效、延迟更低。

2. 核心概念与工作原理

2.1 接口定义先行:.proto 文件

gRPC 的核心是契约先行的开发模式。首先需要在一个 .proto 文件中定义服务接口和消息结构。

yaml 复制代码
// 1. 指定 protobuf 的语法版本
syntax = "proto3";

// 2. 可选,指定生成的 C# 代码的命名空间
option csharp_namespace = "GrpcServiceDemo";

// 3. 定义服务。一个服务包含多个可远程调用的方法。
service Greeter {
  // 定义一个 RPC 方法,名为 SayHello
  // 它接收一个 HelloRequest 消息,并返回一个 HelloReply 消息
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// 4. 定义消息类型(相当于数据传输对象 DTO)
message HelloRequest {
  // 字段定义:类型 字段名 = 唯一的字段编号;
  string name = 1;
}

message HelloReply {
  string message = 1;
}
  • service: 定义了你的远程服务,里面包含多个 RPC 方法。
  • rpc: 定义了一个远程方法。你必须指定其请求和响应的消息类型。
  • message: 定义了在网络上传输的数据结构。每个字段都有一个唯一的编号,这个编号用于在二进制流中识别字段,比使用字段名高效得多。
  • 字段规则: string name = 1; 中的 1 是字段编号,一旦确定就不能更改。proto3 中字段默认是单数的,还有 repeated(类似数组)等规则。

2.2 代码生成:protoc 编译器

定义好 .proto 文件后,需要使用 Protocol Buffers 编译器(protoc) 配合对应语言的 gRPC 插件来生成代码。

  • 生成内容
    • 客户端存根(Stub): 客户端代码中会生成一个类,它包含了所有在 .proto 中定义的 RPC 方法。你调用这个存根的方法,它就会帮你处理网络通信,向服务器发送请求并接收响应。
    • 服务端骨架(Skeleton): 服务端代码中会生成一个抽象的基类,其中包含了所有 RPC 方法的虚方法。你的任务就是继承这个基类,并重写这些方法,实现具体的业务逻辑。

例如,对于 C#,使用 Grpc.Tools NuGet 包,它会在编译时自动帮你生成上述代码。

2.3 通信模式

gRPC 支持四种主要的通信模式:

  1. 一元 RPC(Unary RPC)

    • 最简单的模式:客户端发送一个 请求,服务端返回一个响应。
    • rpc SayHello (HelloRequest) returns (HelloReply);
  2. 服务端流式 RPC(Server streaming RPC)

    • 客户端发送一个请求,服务端返回一个流,包含多条消息。
    • 适用于服务器需要向客户端推送大量数据的场景,如实时日志、股票报价、文件分块传输。
    • rpc LotsOfReplies (HelloRequest) returns (stream HelloReply);
  3. 客户端流式 RPC(Client streaming RPC)

    • 客户端发送一个流,包含多条消息,服务端返回一个响应。
    • 适用于客户端需要向服务器上传大量数据的场景,如传感器数据上传、大文件上传。
    • rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply);
  4. 双向流式 RPC(Bidirectional streaming RPC)

    • 客户端和服务端都使用一个读写流来发送一系列消息。这两个流是独立操作的,因此它们可以以任意顺序读写。
    • 适用于真正的实时对话场景,如聊天应用、游戏指令同步、遥测数据交换。
    • rpc BidiHello (stream HelloRequest) returns (stream HelloReply);

3 为什么选择 gRPC?优势与劣势

优势

  1. 极高的性能

    • 序列化:Protobuf 是二进制格式,序列化/反序列化速度极快,生成的数据包体积非常小。
    • 协议:基于 HTTP/2,支持多路复用(多个请求/响应可以在同一个 TCP 连接上同时交错进行),避免了 HTTP/1.1 的队头阻塞问题,减少了连接开销。
    • 代码生成:强类型的客户端和服务端代码减少了运行时错误,并且调用就像本地方法一样直观高效。
  2. 严格的 API 契约

    • .proto 文件是服务 API 的唯一真相来源。它充当了清晰的、语言无关的契约,便于前后端、不同团队之间协作,并大大减少了编写无聊的样板代码的工作量。
  3. 流式处理能力

    • 内置支持四种流模式,非常适合处理大规模数据集和实时通信场景,这是传统 REST API 难以优雅实现的。
  4. 超时、截止时间(Deadlines)和取消

    • gRPC 客户端可以指定一个 RPC 在多久时间内必须完成。如果超时,服务器可以自行中止操作,避免资源浪费。
  5. 内置认证和加密

    • 原生支持基于 SSL/TLS 的通道加密。同时提供了丰富的认证机制插件,如 token-based 认证。

劣势与挑战

  1. 对浏览器支持有限

    • 浏览器无法直接强制要求使用 HTTP/2 和操纵底层网络,因此无法直接调用 gRPC 服务。这是 gRPC-Web 要解决的问题,它需要一个代理来将 HTTP/1.1 的请求转换为 gRPC 的 HTTP/2 请求。
  2. 可调试性稍差

    • 由于传输的是二进制数据,不能像 JSON 那样直接用 curl 命令或浏览器开发者工具来直观地查看和调试请求/响应内容。通常需要额外的工具(如 grpcurl)来进行调试。
  3. 学习曲线

    • 需要学习 .proto 语法和一套新的工具链(protoc),与传统的基于 JSON 的 REST API 开发模式有所不同。

4 gRPC 与 REST 的对比

特性 gRPC REST (通常指 JSON over HTTP/1.1)
协议 HTTP/2 通常是 HTTP/1.1
有效载荷 Protocol Buffers (二进制) JSON (文本)
契约 强制、严格(.proto 文件) 松散、可选 (OpenAPI/Swagger 是事后生成)
性能 (二进制、多路复用、头部压缩) 较低 (文本、队头阻塞)
流式处理 一流支持 (四种模式) 难以实现 (通常靠 SSE 或 WebSockets)
代码生成 一流、内置、跨语言支持 需要第三方工具 (如 NSwag, AutoRest)
浏览器支持 需要 gRPC-Web 和代理 原生支持

总结

如果在构建内部服务 (尤其是微服务)、对性能有极高要求 、或者需要流式通信 ,gRPC 是绝佳的选择。如果你在构建面向公众的 API,需要最大程度的兼容性和可调试性,REST with JSON 可能仍然是更安全的选择。

5 在 .NET 中使用 gRPC 的简单示例

  1. 创建服务端

    • 使用 Visual Studio 模板创建 gRPC Service 项目。

    • 它已经包含了示例 .proto 文件和一个服务实现。

    • 实现生成的抽象类中的方法:

      csharp 复制代码
      public class GreeterService : Greeter.GreeterBase
      {
          public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
          {
              return Task.FromResult(new HelloReply
              {
                  Message = "Hello " + request.Name
              });
          }
      }```
  2. 创建客户端

    • 在客户端项目中,通过 NuGet 添加 Grpc.Net.Client 和 Google.Protobuf。

    • 将服务端的 .proto 文件复制到客户端项目(通常作为链接添加),并配置其生成客户端代码。

    • 调用服务:

      csharp 复制代码
      // 创建通道(管理到服务端的连接)
      using var channel = GrpcChannel.ForAddress("https://localhost:7001");
      
      // 创建客户端(生成的代码)
      var client = new Greeter.GreeterClient(channel);
      
      // 像调用本地方法一样调用远程方法!
      var reply = await client.SayHelloAsync(new HelloRequest { Name = "World" });
      Console.WriteLine("Greeting: " + reply.Message);

总结

gRPC 是一个强大的、现代的 RPC 框架,它通过契约先行、基于 HTTP/2 和 Protobuf 的设计,提供了卓越的性能、跨语言支持和丰富的流式处理能力。它是构建高性能、分布式系统(如微服务、服务网格)的理想选择,尽管在面向浏览器时存在一些挑战,但 gRPC-Web 正在努力解决这个问题。对于 .NET 开发者来说,其工具链集成非常完善,上手和使用体验都非常流畅。


相关推荐
波波0078 小时前
每日一题:中间件是如何工作的?
中间件·.net·面试题
无风听海9 小时前
.NET 10之可空引用类型
数据结构·.net
码云数智-园园9 小时前
基于 JSON 配置的 .NET 桌面应用自动更新实现指南
.net
无风听海9 小时前
.NET 10 之dotnet run的功能
.net
岩屿9 小时前
Ubuntu下安装Docker并部署.NET API(二)
运维·docker·容器·.net
码云数智-大飞9 小时前
.NET 中高效实现 List 集合去重的多种方法详解
.net
easyboot9 小时前
使用tinyply.net保存ply格式点云
.net
张人玉9 小时前
WPF 多语言实现完整笔记(.NET 4.7.2)
笔记·.net·wpf·多语言实现·多语言适配
波波0071 天前
Native AOT 能改变什么?.NET 预编译技术深度剖析
开发语言·.net
Crazy Struggle2 天前
.NET 中如何快速实现 List 集合去重?
c#·.net