VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#中关于gRPC服务——高性能跨语言通信

第六部分:容器化与微服务开发
2. gRPC服务——高性能跨语言通信
实例介绍
之前做电商系统的商品库存服务时,用REST API实现,每次调用需要序列化/反序列化JSON,性能低,而且不支持流式通信,实时库存更新延迟高。换成gRPC后,使用Protocol Buffers序列化,性能提升50%,而且支持双向流式通信,实时库存更新vb.net教程C#教程python教程SQL教程access 2010教程
延迟从1秒降到100毫秒,跨语言调用也很方便,Java客户端直接调用C#服务,不需要编写额外的代码。这节就带你从零实现gRPC服务,包括.proto文件编写、服务端实现、客户端调用、流式通信、认证与授权、负载均衡,覆盖gRPC的核心场景。
需求分析
gRPC要解决“高性能通信、跨语言调用、流式通信、强类型契约、服务发现与负载均衡”的问题,具体需求如下:
1.高性能通信:使用HTTP/2协议,多路复用、二进制帧、头部压缩,性能比REST API高50%以上;
2.跨语言调用:支持C#、Java、Python、Go等多种语言,客户端和服务端可以用不同语言实现;
3.流式通信:支持单向流式、双向流式通信,适合实时数据传输(如库存更新、聊天、监控);
4.强类型契约:使用.proto文件定义服务和消息,自动生成客户端和服务端代码,类型安全;
5.服务发现与负载均衡:与Kubernetes、Consul等服务发现工具集成,实现负载均衡;
6.认证与授权:支持SSL/TLS加密、Token认证、OAuth2.0,保护服务安全;
7.错误处理:统一的错误模型,支持自定义错误码和错误消息;
8.拦截器:支持客户端和服务端拦截器,实现日志、监控、认证等横切关注点;
9.与ASP.NET Core集成:与ASP.NET Core无缝集成,使用ASP.NET Core的中间件、依赖注入等功能;
10.容器化部署:支持Docker容器化部署,与Kubernetes集成,实现弹性扩展;
代码实现
前置条件:.NET 8 SDK;Visual Studio 2022(17.8+)或VS Code;需安装以下NuGet包:
Grpc.AspNetCore:ASP.NET Core gRPC服务端包
Grpc.Net.Client:.NET gRPC客户端包
Google.Protobuf:Protocol Buffers序列化包
Grpc.Tools:gRPC代码生成工具
场景1:gRPC服务创建与.proto文件编写
创建gRPC服务项目,编写.proto文件定义服务和消息。
步骤1:创建gRPC服务项目
1.打开Visual Studio → 新建项目 → 搜索“gRPC服务” → 选择“gRPC服务”模板;
2.命名项目为GrpcInventoryService → 选择.NET 8框架;
3.点击“创建”,项目会自动生成.proto文件和服务端代码;
步骤2:编写.proto文件(Protos/inventory.proto)
proto

	syntax = "proto3";
	
	option csharp_namespace = "GrpcInventoryService.Protos";
	
	package inventory;
	
	// 库存服务定义
	service InventoryService {
	// 获取商品库存(一元RPC:客户端发送一个请求,服务端返回一个响应)
	rpc GetInventory (GetInventoryRequest) returns (GetInventoryResponse);
	
	// 更新商品库存(一元RPC)
	rpc UpdateInventory (UpdateInventoryRequest) returns (UpdateInventoryResponse);
	
	// 批量获取商品库存(客户端流式RPC:客户端发送多个请求,服务端返回一个响应)
	rpc BatchGetInventory (stream GetInventoryRequest) returns (BatchGetInventoryResponse);
	
	// 实时库存更新(服务端流式RPC:客户端发送一个请求,服务端返回多个响应)
	rpc SubscribeInventoryUpdates (SubscribeInventoryRequest) returns (stream InventoryUpdateResponse);
	
	// 双向流式RPC:客户端发送多个请求,服务端返回多个响应
	rpc BidirectionalInventoryUpdates (stream UpdateInventoryRequest) returns (stream InventoryUpdateResponse);
	}
	
	// 获取库存请求消息
	message GetInventoryRequest {
	string product_id = 1; // 商品ID
	}
	
	// 获取库存响应消息
	message GetInventoryResponse {
	string product_id = 1; // 商品ID
	int32 quantity = 2; // 库存数量
	string status = 3; // 库存状态(in_stock、low_stock、out_of_stock)
	}
	
	// 更新库存请求消息
	message UpdateInventoryRequest {
	string product_id = 1; // 商品ID
	int32 quantity_change = 2; // 库存变化量(正数表示增加,负数表示减少)
	}
	
	// 更新库存响应消息
	message UpdateInventoryResponse {
	string product_id = 1; // 商品ID
	int32 new_quantity = 2; // 更新后的库存数量
	bool success = 3; // 是否更新成功
	string message = 4; // 错误消息(如果更新失败)
	}
	
	// 批量获取库存响应消息
	message BatchGetInventoryResponse {
	repeated GetInventoryResponse inventories = 1; // 库存列表
	}
	
	// 订阅库存更新请求消息
	message SubscribeInventoryRequest {
	repeated string product_ids = 1; // 要订阅的商品ID列表
	}
	
	// 库存更新响应消息
	message InventoryUpdateResponse {
	string product_id = 1; // 商品ID
	int32 new_quantity = 2; // 更新后的库存数量
	string status = 3; // 库存状态
	string update_time = 4; // 更新时间
	}

场景2:gRPC服务端实现
实现gRPC服务端逻辑,处理客户端请求。
步骤1:服务端代码实现(Services/InventoryService.cs)
csharp

	using Grpc.Core;
	using GrpcInventoryService.Protos;
	
	namespace GrpcInventoryService.Services;
	
	public class InventoryService : Protos.InventoryService.InventoryServiceBase
	{
	// 模拟库存数据
	private readonly Dictionary<string, int> _inventory = new()
	{
	["PROD001"] = 100,
	["PROD002"] = 50,
	["PROD003"] = 10,
	["PROD004"] = 0
	};
	
	private readonly ILogger<InventoryService> _logger;
	
	public InventoryService(ILogger<InventoryService> logger)
	{
	_logger = logger;
	}
	
	// 实现获取商品库存方法
	public override Task<GetInventoryResponse> GetInventory(GetInventoryRequest request, ServerCallContext context)
	{
	_logger.LogInformation("获取商品库存请求:ProductId = {ProductId}", request.ProductId);
	
	// 检查商品是否存在
	if (!_inventory.TryGetValue(request.ProductId, out int quantity))
	{
	throw new RpcException(new Status(StatusCode.NotFound, $"商品 {request.ProductId} 不存在"));
	}
	
	// 确定库存状态
	string status = quantity switch
	{
	> 10 => "in_stock",
	> 0 => "low_stock",
	_ => "out_of_stock"
	};
	
	return Task.FromResult(new GetInventoryResponse
	{
	ProductId = request.ProductId,
	Quantity = quantity,
	Status = status
	});
	}
	
	// 实现更新商品库存方法
	public override Task<UpdateInventoryResponse> UpdateInventory(UpdateInventoryRequest request, ServerCallContext context)
	{
	_logger.LogInformation("更新商品库存请求:ProductId = {ProductId}, QuantityChange = {QuantityChange}",
	request.ProductId, request.QuantityChange);
	
	// 检查商品是否存在
	if (!_inventory.ContainsKey(request.ProductId))
	{
	return Task.FromResult(new UpdateInventoryResponse
	{
	ProductId = request.ProductId,
	NewQuantity = 0,
	Success = false,
	Message = $"商品 {request.ProductId} 不存在"
	});
	}
	
	// 更新库存
	int newQuantity = _inventory[request.ProductId] + request.QuantityChange;
	if (newQuantity < 0)
	{
	return Task.FromResult(new UpdateInventoryResponse
	{
	ProductId = request.ProductId,
	NewQuantity = _inventory[request.ProductId],
	Success = false,
	Message = "库存数量不能为负数"
	});
	}
	
	_inventory[request.ProductId] = newQuantity;
	
	// 触发库存更新事件(用于流式更新)
	OnInventoryUpdated?.Invoke(request.ProductId, newQuantity);
	
	return Task.FromResult(new UpdateInventoryResponse
	{
	ProductId = request.ProductId,
	NewQuantity = newQuantity,
	Success = true,
	Message = "库存更新成功"
	});
	}
	
	// 实现批量获取商品库存方法(客户端流式RPC)
	public override async Task<BatchGetInventoryResponse> BatchGetInventory(IAsyncStreamReader<GetInventoryRequest> requestStream, ServerCallContext context)
	{
	var response = new BatchGetInventoryResponse();
	
	// 读取客户端发送的所有请求
	while (await requestStream.MoveNext(context.CancellationToken))
	{
	var request = requestStream.Current;
	_logger.LogInformation("批量获取商品库存请求:ProductId = {ProductId}", request.ProductId);
	
	if (_inventory.TryGetValue(request.ProductId, out int quantity))
	{
	string status = quantity switch
	{
	> 10 => "in_stock",
	> 0 => "low_stock",
	_ => "out_of_stock"
	};
	
	response.Inventories.Add(new GetInventoryResponse
	{
	ProductId = request.ProductId,
	Quantity = quantity,
	Status = status
	});
	}
	else
	{
	response.Inventories.Add(new GetInventoryResponse
	{
	ProductId = request.ProductId,
	Quantity = 0,
	Status = "not_found"
	});
	}
	}
	
	return response;
	}
	
	// 实现实时库存更新方法(服务端流式RPC)
	public override async Task SubscribeInventoryUpdates(SubscribeInventoryRequest request, IServerStreamWriter<InventoryUpdateResponse> responseStream, ServerCallContext context)
	{
	_logger.LogInformation("订阅库存更新请求:ProductIds = {ProductIds}", string.Join(", ", request.ProductIds));
	
	// 注册库存更新事件处理程序
	void InventoryUpdatedHandler(string productId, int newQuantity)
	{
	if (request.ProductIds.Contains(productId))
	{
	// 发送库存更新响应
	var response = new InventoryUpdateResponse
	{
	ProductId = productId,
	NewQuantity = newQuantity,
	Status = newQuantity switch
	{
	> 10 => "in_stock",
	> 0 => "low_stock",
	_ => "out_of_stock"
	},
	UpdateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
	};
	
	// 异步发送响应
	_ = responseStream.WriteAsync(response);
	}
	}
	
	OnInventoryUpdated += InventoryUpdatedHandler;
	
	// 等待客户端取消订阅
	try
	{
	await Task.Delay(Timeout.Infinite, context.CancellationToken);
	}
	catch (TaskCanceledException)
	{
	_logger.LogInformation("客户端取消订阅库存更新");
	}
	finally
	{
	OnInventoryUpdated -= InventoryUpdatedHandler;
	}
	}
	
	// 实现双向流式RPC方法
	public override async Task BidirectionalInventoryUpdates(IAsyncStreamReader<UpdateInventoryRequest> requestStream, IServerStreamWriter<InventoryUpdateResponse> responseStream, ServerCallContext context)
	{
	_logger.LogInformation("双向流式库存更新请求开始");
	
	// 同时读取客户端请求和发送响应
	var readTask = Task.Run(async () =>
	{
	while (await requestStream.MoveNext(context.CancellationToken))
	{
	var request = requestStream.Current;
	_logger.LogInformation("双向流式更新库存请求:ProductId = {ProductId}, QuantityChange = {QuantityChange}",
	request.ProductId, request.QuantityChange);
	
	// 更新库存
	if (_inventory.TryGetValue(request.ProductId, out int currentQuantity))
	{
	int newQuantity = currentQuantity + request.QuantityChange;
	if (newQuantity >= 0)
	{
	_inventory[request.ProductId] = newQuantity;
	
	// 发送库存更新响应
	var response = new InventoryUpdateResponse
	{
	ProductId = request.ProductId,
	NewQuantity = newQuantity,
	Status = newQuantity switch
	{
	> 10 => "in_stock",
	> 0 => "low_stock",
	_ => "out_of_stock"
	},
	UpdateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
	};
	
	await responseStream.WriteAsync(response);
	}
	else
	{
	// 发送错误响应
	var response = new InventoryUpdateResponse
	{
	ProductId = request.ProductId,
	NewQuantity = currentQuantity,
	Status = "error",
	UpdateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
	};
	
	await responseStream.WriteAsync(response);
	}
	}
	else
	{
	// 发送错误响应
	var response = new InventoryUpdateResponse
	{
	ProductId = request.ProductId,
	NewQuantity = 0,
	Status = "not_found",
	UpdateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
	};
	
	await responseStream.WriteAsync(response);
	}
	}
	}, context.CancellationToken);
	
	await readTask;
	}
	
	// 库存更新事件
	public event Action<string, int>? OnInventoryUpdated;
	}

步骤3:注册gRPC服务(Program.cs)
csharp

	using GrpcInventoryService.Services;
	
	var builder = WebApplication.CreateBuilder(args);
	
	// 添加gRPC服务
	builder.Services.AddGrpc();
	
	var app = builder.Build();
	
	// 配置gRPC服务端点
	app.MapGrpcService<InventoryService>();
	
	// 配置HTTP/2支持(gRPC需要HTTP/2)
	app.UseHttpsRedirection();
	
	app.Run();

场景3:.NET gRPC客户端实现
创建.NET gRPC客户端,调用gRPC服务。
步骤1:创建gRPC客户端项目
1.打开Visual Studio → 新建项目 → 选择“控制台应用”模板;
2.命名项目为GrpcInventoryClient → 选择.NET 8框架;
3.安装NuGet包:Grpc.Net.Client、Google.Protobuf、Grpc.Tools;
4.将服务端的Protos/inventory.proto文件复制到客户端项目中,并设置“生成操作”为“Protobuf编译器”,“服务端”为“否”,“客户端”为“是”;
步骤2:客户端调用代码
csharp

	using Grpc.Core;
	using Grpc.Net.Client;
	using GrpcInventoryService.Protos;
	
	namespace GrpcInventoryClient;
	
	class Program
	{
	static async Task Main(string[] args)
	{
	// 创建gRPC客户端通道(使用HTTP/2)
	using var channel = GrpcChannel.ForAddress("https://localhost:5001");
	var client = new InventoryService.InventoryServiceClient(channel);
	
	// 调用一元RPC:获取商品库存
	await GetInventoryAsync(client, "PROD001");
	
	// 调用一元RPC:更新商品库存
	await UpdateInventoryAsync(client, "PROD001", -5);
	
	// 调用客户端流式RPC:批量获取商品库存
	await BatchGetInventoryAsync(client, new List<string> { "PROD001", "PROD002", "PROD003" });
	
	// 调用服务端流式RPC:订阅库存更新
	await SubscribeInventoryUpdatesAsync(client, new List<string> { "PROD001", "PROD002" });
	
	// 调用双向流式RPC:双向库存更新
	await BidirectionalInventoryUpdatesAsync(client, new List<UpdateInventoryRequest>
	{
	new UpdateInventoryRequest { ProductId = "PROD001", QuantityChange = 10 },
	new UpdateInventoryRequest { ProductId = "PROD002", QuantityChange = -5 },
	new UpdateInventoryRequest { ProductId = "PROD003", QuantityChange = 20 }
	});
	}
	
	// 调用获取商品库存方法
	static async Task GetInventoryAsync(InventoryService.InventoryServiceClient client, string productId)
	{
	try
	{
	var response = await client.GetInventoryAsync(new GetInventoryRequest { ProductId = productId });
	Console.WriteLine($"获取库存成功:商品ID={response.ProductId},数量={response.Quantity},状态={response.Status}");
	}
	catch (RpcException ex)
	{
	Console.WriteLine($"获取库存失败:{ex.Status.Detail}");
	}
	}
	
	// 调用更新商品库存方法
	static async Task UpdateInventoryAsync(InventoryService.InventoryServiceClient client, string productId, int quantityChange)
	{
	var response = await client.UpdateInventoryAsync(new UpdateInventoryRequest { ProductId = productId, QuantityChange = quantityChange });
	Console.WriteLine($"更新库存结果:商品ID={response.ProductId},新数量={response.NewQuantity},成功={response.Success},消息={response.Message}");
	}
	
	// 调用批量获取商品库存方法
	static async Task BatchGetInventoryAsync(InventoryService.InventoryServiceClient client, List<string> productIds)
	{
	using var call = client.BatchGetInventory();
	
	// 发送多个请求
	foreach (var productId in productIds)
	{
	await call.RequestStream.WriteAsync(new GetInventoryRequest { ProductId = productId });
	}
	
	// 完成请求发送
	await call.RequestStream.CompleteAsync();
	
	// 获取响应
	var response = await call.ResponseAsync;
	Console.WriteLine("批量获取库存结果:");
	foreach (var inventory in response.Inventories)
	{
	Console.WriteLine($"商品ID={inventory.ProductId},数量={inventory.Quantity},状态={inventory.Status}");
	}
	}
	
	// 调用订阅库存更新方法
	static async Task SubscribeInventoryUpdatesAsync(InventoryService.InventoryServiceClient client, List<string> productIds)
	{
	using var call = client.SubscribeInventoryUpdates(new SubscribeInventoryRequest { ProductIds = { productIds } });
	
	// 读取服务端发送的多个响应
	try
	{
	await foreach (var response in call.ResponseStream.ReadAllAsync())
	{
	Console.WriteLine($"库存更新通知:商品ID={response.ProductId},新数量={response.NewQuantity},状态={response.Status},时间={response.UpdateTime}");
	}
	}
	catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
	{
	Console.WriteLine("订阅库存更新被取消");
	}
	}
	
	// 调用双向流式RPC方法
	static async Task BidirectionalInventoryUpdatesAsync(InventoryService.InventoryServiceClient client, List<UpdateInventoryRequest> requests)
	{
	using var call = client.BidirectionalInventoryUpdates();
	
	// 发送请求
	var writeTask = Task.Run(async () =>
	{
	foreach (var request in requests)
	{
	await call.RequestStream.WriteAsync(request);
	await Task.Delay(1000); // 模拟延迟
	}
	await call.RequestStream.CompleteAsync();
	});
	
	// 读取响应
	var readTask = Task.Run(async () =>
	{
	await foreach (var response in call.ResponseStream.ReadAllAsync())
	{
	Console.WriteLine($"双向流式库存更新:商品ID={response.ProductId},新数量={response.NewQuantity},状态={response.Status},时间={response.UpdateTime}");
	}
	});
	
	await Task.WhenAll(writeTask, readTask);
	}
	}

场景4:跨语言调用——Java客户端实现
创建Java gRPC客户端,调用C# gRPC服务。
步骤1:创建Java Maven项目
1.打开IntelliJ IDEA → 新建Maven项目;
2.在pom.xml中添加gRPC依赖:
xml

	<dependencies>
	<dependency>
	<groupId>io.grpc</groupId>
	<artifactId>grpc-netty-shaded</artifactId>
	<version>1.64.0</version>
	</dependency>
	<dependency>
	<groupId>io.grpc</groupId>
	<artifactId>grpc-protobuf</artifactId>
	<version>1.64.0</version>
	</dependency>
	<dependency>
	<groupId>io.grpc</groupId>
	<artifactId>grpc-stub</artifactId>
	<version>1.64.0</version>
	</dependency>
	<dependency> <!-- Java 9+ 兼容 -->
	<groupId>org.apache.tomcat</groupId>
	<artifactId>annotations-api</artifactId>
	<version>6.0.53</version>
	<scope>provided</scope>
	</dependency>
	</dependencies>
	
	<build>
	<extensions>
	<extension>
	<groupId>kr.motd.maven</groupId>
	<artifactId>os-maven-plugin</artifactId>
	<version>1.7.1</version>
	</extension>
	</extensions>
	<plugins>
	<plugin>
	<groupId>org.xolstice.maven.plugins</groupId>
	<artifactId>protobuf-maven-plugin</artifactId>
	<version>0.6.1</version>
	<configuration>
	<protocArtifact>com.google.protobuf:protoc:3.25.3:exe:${os.detected.classifier}</protocArtifact>
	<pluginId>grpc-java</pluginId>
	<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.64.0:exe:${os.detected.classifier}</pluginArtifact>
	</configuration>
	<executions>
	<execution>
	<goals>
	<goal>compile</goal>
	<goal>compile-custom</goal>
	</goals>
	</execution>
	</executions>
	</plugin>
	</plugins>
	</build>

5.将服务端的inventory.proto文件复制到src/main/proto目录;
6.运行mvn compile,自动生成Java客户端代码;
步骤2:Java客户端调用代码
java

	package com.example.grpcinventoryclient;
	
	import io.grpc.ManagedChannel;
	import io.grpc.ManagedChannelBuilder;
	import io.grpc.StatusRuntimeException;
	import inventory.InventoryServiceGrpc;
	import inventory.InventoryOuterClass;
	
	import java.util.concurrent.TimeUnit;
	
	public class InventoryClient {
	private final InventoryServiceGrpc.InventoryServiceBlockingStub blockingStub;
	private final InventoryServiceGrpc.InventoryServiceStub asyncStub;
	
	public InventoryClient(ManagedChannel channel) {
	blockingStub = InventoryServiceGrpc.newBlockingStub(channel);
	asyncStub = InventoryServiceGrpc.newStub(channel);
	}
	
	// 调用获取商品库存方法
	public void getInventory(String productId) {
	InventoryOuterClass.GetInventoryRequest request = InventoryOuterClass.GetInventoryRequest.newBuilder()
	.setProductId(productId)
	.build();
	
	try {
	InventoryOuterClass.GetInventoryResponse response = blockingStub.getInventory(request);
	System.out.printf("获取库存成功:商品ID=%s,数量=%d,状态=%s%n",
	response.getProductId(), response.getQuantity(), response.getStatus());
	} catch (StatusRuntimeException e) {
	System.err.printf("获取库存失败:%s%n", e.getStatus().getDescription());
	}
	}
	
	public static void main(String[] args) throws InterruptedException {
	String target = "localhost:5001";
	
	// 创建gRPC通道
	ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
	.usePlaintext() // 开发环境使用明文,生产环境使用SSL/TLS
	.build();
	
	try {
	InventoryClient client = new InventoryClient(channel);
	client.getInventory("PROD001");
	} finally {
	// 关闭通道
	channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
	}
	}
	}

逐行讲解
场景1:.proto文件核心代码
1.syntax = "proto3":使用Protocol Buffers 3语法,比proto2更简洁,默认值处理更合理;
2.option csharp_namespace:指定生成的C#代码的命名空间;
3.package inventory:指定包名,避免不同服务的消息重名;
4.service InventoryService:定义gRPC服务,包含多个RPC方法;
5.rpc GetInventory (GetInventoryRequest) returns (GetInventoryResponse):定义一元RPC方法,客户端发送一个请求,服务端返回一个响应;
6.rpc BatchGetInventory (stream GetInventoryRequest) returns (BatchGetInventoryResponse):定义客户端流式RPC方法,客户端发送多个请求,服务端返回一个响应;
7.message GetInventoryRequest:定义请求消息,包含字段和字段编号(如string product_id = 1,字段编号从1开始,不能重复);
场景2:服务端核心代码
1.继承InventoryServiceBase:服务端类必须继承自动生成的InventoryServiceBase类,实现RPC方法;
2.RpcException:抛出gRPC异常,包含错误码和错误消息,客户端会收到对应的错误;
3.IAsyncStreamReader:客户端流式RPC中,用于读取客户端发送的多个请求;
4.IServerStreamWriter:服务端流式RPC中,用于向客户端发送多个响应;
5.ServerCallContext:包含RPC调用的上下文信息(如取消令牌、元数据);
场景3:客户端核心代码
1.GrpcChannel:创建gRPC客户端通道,指定服务端地址;
2.InventoryServiceClient:自动生成的客户端类,包含所有RPC方法;
3.async/await:异步调用RPC方法,避免阻塞主线程;
4.using var call = client.SubscribeInventoryUpdates(...):服务端流式RPC调用,返回一个可读取响应流的对象;
基础知识拓展

  1. gRPC与REST API对比
特性 gRPC REST API
通信协议 HTTP/2 HTTP/1.1
序列化 Protocol Buffers(二进制,高效) JSON/XML(文本,低效)
性能 高(比REST API高50%以上) 中
流式通信 支持客户端流式、服务端流式、双向流式 不支持(需要使用WebSocket)
类型安全 强类型,.proto文件定义,自动生成代码 弱类型,需要手动验证
跨语言支持 支持C#、Java、Python、Go等多种语言 支持所有语言,但需要手动编写客户端代码
错误处理 统一的错误模型,支持自定义错误码 依赖HTTP状态码,错误处理不统一
  1. Protocol Buffers优势
    高效序列化:二进制格式,比JSON小3-5倍,序列化速度快2-10倍;
    强类型:.proto文件定义消息结构,自动生成类型安全的代码;
    向后兼容:可以在不破坏旧客户端的情况下添加新字段;
    跨语言:支持多种语言,客户端和服务端可以用不同语言实现;
  2. gRPC服务类型
    一元RPC:客户端发送一个请求,服务端返回一个响应,适合简单的请求-响应场景;
    客户端流式RPC:客户端发送多个请求,服务端返回一个响应,适合批量处理场景;
    服务端流式RPC:客户端发送一个请求,服务端返回多个响应,适合实时数据推送场景;
    双向流式RPC:客户端发送多个请求,服务端返回多个响应,适合实时双向通信场景;
  3. gRPC认证与授权
    SSL/TLS加密:使用SSL/TLS加密通信,保护数据安全;
    Token认证:客户端在元数据中发送Token,服务端验证Token;
    OAuth2.0:与OAuth2.0集成,支持授权码、客户端凭证等授权方式;
    拦截器:使用服务端拦截器实现认证与授权,统一处理所有请求;
  4. gRPC服务发现与负载均衡
    服务发现:与Kubernetes、Consul等服务发现工具集成,客户端自动发现服务端地址;
    负载均衡:客户端负载均衡,根据负载均衡策略(如轮询、随机、最少连接)选择服务端;
    健康检查:服务端定期报告健康状态,客户端只向健康的服务端发送请求;
    总结
    gRPC的核心是高性能通信、跨语言调用、流式通信、强类型契约,让你轻松构建高性能的分布式系统,实现跨语言服务调用。关键要点:
    1..proto文件:定义服务和消息,自动生成客户端和服务端代码;
    2.服务端实现:继承自动生成的服务基类,实现RPC方法;
    3.客户端调用:使用自动生成的客户端类,调用RPC方法;
    4.流式通信:支持客户端流式、服务端流式、双向流式通信,适合实时数据传输;
    5.跨语言调用:支持多种语言,客户端和服务端可以用不同语言实现;
    6.安全:支持SSL/TLS加密、Token认证、OAuth2.0,保护服务安全;
    比如这个gRPC库存服务,使用Protocol Buffers序列化,性能提升50%,而且支持双向流式通信,实时库存更新延迟从1秒降到100毫秒,Java客户端直接调用C#服务,不需要编写额外的代码。掌握gRPC,你就能轻松构建高性能的分布式系统,实现跨语言服务调用!

本站原创,转载请注明出处:


相关教程