9.3 gRPC (高性能 RPC 框架) 9.3 gRPC (高性能 RPC 框架) gRPC (gRPC Remote Procedure Call) 是一个高性能、开源和通用的 RPC 框架,最初由 Google 开发。它使用 Protocol Buffers 作为接口定义语言 (IDL) 和消息交换格式,支持多种编程语言,并构建在 HTTP/2 之上,提供了诸多优势,例如: 高性能: 基于 HTTP/2,支持多路复用、头部压缩和双向流等特性,显著提高效率。 强类型: 使用 Protocol Buffers 定义服务接口,确保客户端和服务端之间的数据类型一致性。 跨语言: 支持多种编程语言,允许不同语言编写的服务相互调用。 代码生成: 自动生成客户端和服务端代码,简化开发流程。
gRPC (gRPC Remote Procedure Call) 是一个高性能、开源和通用的 RPC 框架,最初由 Google 开发。它使用 Protocol Buffers 作为接口定义语言 (IDL) 和消息交换格式,支持多种编程语言,并构建在 HTTP/2 之上,提供了诸多优势,例如:
高性能: 基于 HTTP/2,支持多路复用、头部压缩和双向流等特性,显著提高效率。
强类型: 使用 Protocol Buffers 定义服务接口,确保客户端和服务端之间的数据类型一致性。
跨语言: 支持多种编程语言,允许不同语言编写的服务相互调用。
代码生成: 自动生成客户端和服务端代码,简化开发流程。
流式传输: 支持客户端和服务端的流式传输,适用于需要实时通信的场景。
在 ASP.NET Core 中,gRPC 集成非常方便,可以轻松构建高性能的微服务。
Protocol Buffers (protobuf): 一种语言无关、平台无关、可扩展的序列化结构数据的方法,用于定义 gRPC 服务接口和消息格式。使用 .proto 文件定义服务和消息。
Service Definition: 在 .proto 文件中定义服务接口,包含服务名称、方法名称、请求消息类型和响应消息类型。
Messages: 在 .proto 文件中定义数据结构,用于在客户端和服务端之间传递数据。
gRPC Channels: 客户端与服务端建立的连接,用于发送和接收 gRPC 消息。
Stubs: 客户端生成的代码,用于调用 gRPC 服务。
Services: 服务端实现的接口,用于处理 gRPC 请求。
1. 创建 ASP.NET Core gRPC 项目:
可以使用 Visual Studio 或 .NET CLI 创建 gRPC 项目。
Visual Studio: 选择 "ASP.NET Core Web API" 项目模板,并在 "高级" 设置中选择 "启用 gRPC 支持"。
.NET CLI:
dotnet new grpc -o MyGrpcService cd MyGrpcService
2. 定义 Protocol Buffers 文件 (.proto):
在 Protos 目录下创建一个 .proto 文件,例如 greet.proto,定义服务和消息。
syntax = "proto3"; option csharp_namespace = "MyGrpcService"; package Greet; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply); rpc SayHelloStream (HelloRequest) returns (stream HelloReply); } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings. message HelloReply { string message = 1; }
3. 生成 gRPC 代码:
在项目文件中添加 <Protobuf> 元素,指定 .proto 文件,并配置生成 gRPC 服务代码。
<ItemGroup> <Protobuf Include="Protos\greet.proto" GrpcServices="Server" /> </ItemGroup>
构建项目后,将自动生成 gRPC 服务代码。
4. 实现 gRPC 服务:
创建一个类,继承自生成的服务基类,并实现服务方法。
using Grpc.Core; using MyGrpcService; using Microsoft.Extensions.Logging; using System.Threading.Tasks; namespace MyGrpcService.Services { 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) { _logger.LogInformation($"Received request from {context.Peer}"); return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); } public override async Task SayHelloStream(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context) { for (int i = 0; i < 5; i++) { await responseStream.WriteAsync(new HelloReply { Message = $"Hello {request.Name} - Stream {i+1}" }); await Task.Delay(1000); // Simulate some work } } } }
5. 配置 gRPC 服务:
在 Startup.cs (或 Program.cs 在 .NET 6+) 中,配置 gRPC 服务。
// Startup.cs (ASP.NET Core 3.1 or earlier) public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... other configurations app.UseRouting(); 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"); }); }); } // Program.cs (.NET 6 or later) var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddGrpc(); var app = builder.Build(); // Configure the HTTP request pipeline. app.MapGrpcService<GreeterService>(); app.MapGet("/", () => "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"); app.Run();
6. 创建 gRPC 客户端:
创建一个控制台应用程序或其他类型的项目,用于调用 gRPC 服务。
添加 Grpc.Net.Client 和 Google.Protobuf NuGet 包。
复制 .proto 文件到客户端项目。
在项目文件中添加 <Protobuf> 元素,指定 .proto 文件,并配置生成 gRPC 客户端代码 (GrpcServices="Client").
<ItemGroup> <PackageReference Include="Grpc.Net.Client" Version="2.51.0" /> <PackageReference Include="Google.Protobuf" Version="3.22.0" /> <Protobuf Include="Protos\greet.proto" GrpcServices="Client" /> </ItemGroup>
using Grpc.Net.Client; using MyGrpcService; using System; using System.Threading.Tasks; namespace GrpcClient { class Program { static async Task Main(string[] args) { // The port number must match the port of the gRPC server. using var channel = GrpcChannel.ForAddress("https://localhost:7000"); // Or http://localhost:5000 if not using HTTPS var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" }); Console.WriteLine("Greeting: " + reply.Message); Console.WriteLine("Streaming..."); using var streamingCall = client.SayHelloStream(new HelloRequest { Name = "StreamClient" }); await foreach (var response in streamingCall.ResponseStream.ReadAllAsync()) { Console.WriteLine("Streaming Greeting: " + response.Message); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
7. 运行 gRPC 服务和客户端:
先运行 gRPC 服务,然后运行 gRPC 客户端。客户端将调用服务,并在控制台输出结果。
拦截器 (Interceptors): 拦截器允许在 gRPC 请求和响应处理过程中添加自定义逻辑,例如身份验证、授权、日志记录等。
元数据 (Metadata): 元数据是与 gRPC 请求和响应关联的键值对,可以用于传递附加信息,例如身份验证令牌、跟踪 ID 等。
截止时间 (Deadlines): 截止时间允许客户端指定 gRPC 请求的超时时间,避免长时间等待。
错误处理 (Error Handling): gRPC 使用 Status Codes 和 Status Details 来表示错误,客户端可以根据错误信息进行处理。
1. 创建拦截器类:
using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; public class LoggingInterceptor : Interceptor { private readonly ILogger<LoggingInterceptor> _logger; public LoggingInterceptor(ILogger<LoggingInterceptor> logger) { _logger = logger; } public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation) { _logger.LogInformation($"Starting call. Type: {context.Method.Type}. Method: {context.Method.FullName}"); return base.AsyncUnaryCall(request, context, continuation); } public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation) { _logger.LogInformation($"Starting call. Type: {context.Method.Type}. Method: {context.Method.FullName}"); return base.BlockingUnaryCall(request, context, continuation); } public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ServerInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation) { _logger.LogInformation($"Starting server streaming call. Type: {context.Method.Type}. Method: {context.Method.FullName}"); return base.AsyncServerStreamingCall(request, context, continuation); } }
2. 注册拦截器:
在客户端代码中,注册拦截器。
using Grpc.Net.Client; using MyGrpcService; using System; using System.Threading.Tasks; using Grpc.Core; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; namespace GrpcClient { class Program { static async Task Main(string[] args) { // Configure Logging using var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); var logger = loggerFactory.CreateLogger<Program>(); // The port number must match the port of the gRPC server. var channel = GrpcChannel.ForAddress("https://localhost:7000", new GrpcChannelOptions { Interceptors = { new LoggingInterceptor(loggerFactory.CreateLogger<LoggingInterceptor>()) } }); var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" }); Console.WriteLine("Greeting: " + reply.Message); Console.WriteLine("Streaming..."); using var streamingCall = client.SayHelloStream(new HelloRequest { Name = "StreamClient" }); await foreach (var response in streamingCall.ResponseStream.ReadAllAsync()) { Console.WriteLine("Streaming Greeting: " + response.Message); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
优势:
高性能: 适合构建需要高吞吐量和低延迟的微服务。
强类型: 减少客户端和服务端之间的错误。
跨语言: 允许不同语言编写的服务相互调用。
流式传输: 适合实时通信场景。
适用场景:
微服务架构: 构建高性能的微服务。
移动应用后端: 为移动应用提供高性能的 API。
实时通信: 构建实时聊天、游戏等应用。
内部服务调用: 在企业内部系统之间进行高性能的服务调用.
gRPC 是一个强大的 RPC 框架,特别适合构建高性能、跨语言的微服务。 在 ASP.NET Core 中,gRPC 集成简单方便,可以显著提高应用程序的性能和可维护性。 通过使用 Protocol Buffers 定义服务接口,自动生成代码,以及利用 gRPC 的高级特性,可以构建高效、可靠的分布式系统。