概述

gRPC 客户端必须使用与服务相同的连接级别安全性。  如调用服务时通道和服务的连接级别安全性不一致,gRPC 客户端就会抛出错误。

gRPC 配置使用HTTP

gRPC 客户端传输层安全性 (TLS) 是在创建 gRPC 通道时服务器地址以https开头配置的。若要配置为http协议做如下修改

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
GrpcChannel.ForAddress("http://localhost:5000")

关于通道和客户端的说明

  • 创建通道成本高昂。 重用 gRPC 调用的通道可提高性能。
  • gRPC 客户端是使用通道创建的。 gRPC 客户端是轻型对象,无需缓存或重用。

配置截止时间

建议配置 gRPC 调用的截止时间,因为它限制调用时间的上限,阻止异常运行的服务持续运行并耗尽服务器资源。 截止时间对于构建可靠应用非常有效。

进行调用时,使用 CallOptions.Deadline 配置截止时间。

如果超过了截止时间,客户端和服务将有不同的行为:

  • 客户端将立即中止基础的 HTTP 请求并引发 DeadlineExceeded 错误。 客户端可以选择捕获错误并向用户显示超时消息。
  • 服务器将中止正在执行的 HTTP 请求,并引发 ServerCallContext.CancellationToken。 尽管中止了 HTTP 请求,gRPC 调用仍将继续运行直到方法完成。 将取消令牌传递给异步方法,使其随调用一同被取消。 例如,向异步数据库查询和 HTTP 请求传递取消令牌。 传递取消令牌让取消的调用可以在服务器上快速完成,并为其他调用释放资源。

客户端代码示例:

try
{
var response = await client.SayHelloAsync(
new HelloRequest { Name = "World" },
deadline: DateTime.UtcNow.AddSeconds(5)); // Greeting: Hello World
Console.WriteLine("Greeting: " + response.Message);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.DeadlineExceeded)
{
Console.WriteLine("Greeting timeout.");
}

服务器代码示例:

var response = await client.GetUserAsync(
new UserRequest { Id = request.Id },
deadline: context.Deadline);

注册 gRPC 客户端

在 Startup类的ConfigureServices方法中,使用 AddGrpcClient 扩展方法指定 gRPC客户端类和服务地址。

services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
});

ASP.NET Core MVC 控制器和 gRPC 服务等通过构造函数等方式自动注入。

配置 HttpHandler

 .ConfigurePrimaryHttpMessageHandler(() => new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler()));

配置通道和拦截器

通道

通道(Channel)是.Net Core 3.X引入的类型,Channel是线程安全的,Channel的预期用例是多线程场景,可以实现多线程之间通信。类似Golang的chan类型。

通道相关文章:https://webmote.blog.csdn.net/article/details/115361367

gRPC配置通道示例:

services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.ConfigureChannel(o =>
{
var credentials = CallCredentials.FromInterceptor((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
}); o.Credentials = ChannelCredentials.Create(new SslCredentials(), credentials);
});

拦截器

具有面向切面的思想,可以在调用服务的时候进行一些统一处理, 很适合在这里处理验证、日志等流程。

Interceptor类是gRPC服务拦截器的基类,是一个抽象类

各个方法作用如下:

方法名称

作用

BlockingUnaryCall

拦截阻塞调用

AsyncUnaryCall

拦截异步调用

AsyncServerStreamingCall

拦截异步服务端流调用

AsyncClientStreamingCall

拦截异步客户端流调用

AsyncDuplexStreamingCall

拦截异步双向流调用

UnaryServerHandler

用于拦截和传入普通调用服务器端处理程序

ClientStreamingServerHandler

用于拦截客户端流调用的服务器端处理程序

ServerStreamingServerHandler

用于拦截服务端流调用的服务器端处理程序

DuplexStreamingServerHandler

用于拦截双向流调用的服务器端处理程序

在实际使用中,可以根据自己的需要来使用对应的拦截方法。

本文示例为创建一个客户端拦截器ClientLoggerInterceptor,该类继承Interceptor。按需实现方法,这里我客户端调用的是SayHelloAsync方法则实现对应的AsyncUnaryCall方法。

注册拦截器:

运行效果图:

服务器端拦截器同理,继承Interceptor类实现对应方法。

服务器端注入方式:

services.AddGrpc(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});

调用取消

可以使用 EnableCallContextPropagation() 对 gRPC 服务中工厂所创建的 gRPC 客户端进行配置,以自动将截止时间和取消令牌传播到子调用。

手动传播截止时间可能会很繁琐。 截止时间需要传递给每个调用,很容易不小心错过。 gRPC 客户端工厂提供自动解决方案。 指定 EnableCallContextPropagation

  • 自动将截止时间和取消令牌传播到子调用。
  • 这是确保复杂的嵌套 gRPC 场景始终传播截止时间和取消的一种极佳方式。
services
.AddGrpcClient<User.UserServiceClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation();

如果客户端在 gRPC 调用的上下文之外使用,EnableCallContextPropagation 将引发错误。 此错误旨在提醒你没有要传播的调用上下文。 如果要在调用上下文之外使用客户端,请使用 SuppressContextNotFoundErrors 在配置客户端时禁止显示该错误:

services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

配置 gRPC 重试策略

重试策略在创建 gRPC 通道时配置

var defaultMethodConfig = new MethodConfig
{
Names = { MethodName.Default },
RetryPolicy = new RetryPolicy
{
MaxAttempts = 5,
InitialBackoff = TimeSpan.FromSeconds(1),
MaxBackoff = TimeSpan.FromSeconds(5),
BackoffMultiplier = 1.5,
RetryableStatusCodes = { StatusCode.Unavailable }
}
}; var channel = GrpcChannel.ForAddress("http://localhost:5000",
new GrpcChannelOptions
{
LoggerFactory = loggerFactory,
ServiceConfig = new ServiceConfig
{
MethodConfigs = { defaultMethodConfig }
}
});

重试策略可以按方法配置,而方法可以使用 Names 属性进行匹配。 此方法配置有 MethodName.Default,因此它将应用于此通道调用的所有 gRPC 方法。

gRPC 重试选项

下表描述了用于配置 gRPC 重试策略的选项:

选项 描述
MaxAttempts 最大调用尝试次数,包括原始尝试。 此值受 GrpcChannelOptions.MaxRetryAttempts(默认值为 5)的限制。 必须为该选项提供值,且值必须大于 1。
InitialBackoff 重试尝试之间的初始退避延迟。 介于 0 与当前退避之间的随机延迟确定何时进行下一次重试尝试。 每次尝试后,当前退避将乘以 BackoffMultiplier。 必须为该选项提供值,且值必须大于 0。
MaxBackoff 最大退避会限制指数退避增长的上限。 必须为该选项提供值,且值必须大于 0。
BackoffMultiplier 每次重试尝试后,退避将乘以该值,并将在乘数大于 1 的情况下以指数方式增加。 必须为该选项提供值,且值必须大于 0。
RetryableStatusCodes 状态代码的集合。 具有匹配状态的失败 gRPC 调用将自动重试。 有关状态代码的更多信息,请参阅状态代码及其在 gRPC 中的用法。 至少需要提供一个可重试的状态代码。

配置 gRPC hedging 策略

Hedging 是一种备选重试策略。 Hedged gRPC 调用可以在服务器上执行多次,并获取第一个成功的结果。

重要的是,务必仅针对可安全执行多次且不会造成负面影响的方法启用 hedging。且hedging 策略不能与重试策略结合使用。

Hedging 具有以下优缺点:

  • Hedging 的优点是,它可能更快地返回成功的结果。 它允许同时进行多个 gRPC 调用,并在出现第一个成功的结果时完成。
  • Hedging 的一个缺点是它可能会造成浪费。 进行了多个调用并且这些调用全部成功。 仅使用第一个结果放弃其余结果。

Hedging 策略的配置类似于重试策略:

var defaultMethodConfig = new MethodConfig
{
Names = { MethodName.Default },
HedgingPolicy = new HedgingPolicy
{
MaxAttempts = 5,
NonFatalStatusCodes = { StatusCode.Unavailable }
}
}; var channel = GrpcChannel.ForAddress("http://localhost:5000", new GrpcChannelOptions
{
LoggerFactory = loggerFactory,
ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

gRPC hedging 选项

下表描述了用于配置 gRPC hedging 策略的选项:

选项 描述
MaxAttempts Hedging 策略将发送的调用数量上限。 MaxAttempts 表示所有尝试的总数,包括原始尝试。 此值受 GrpcChannelOptions.MaxRetryAttempts(默认值为 5)的限制。 必须为该选项提供值,且值必须大于 2。
HedgingDelay 第一次调用立即发送,但后续 hedging 调用将按该值延迟发送。 如果延迟设置为零或 null,那么所有所有 hedged 调用都将立即发送。 默认值为 0。
NonFatalStatusCodes 指示其他 hedge 调用仍可能会成功的状态代码集合。 如果服务器返回非致命状态代码,hedged 调用将继续。 否则,将取消未完成的请求,并将错误返回到应用。 有关状态代码的更多信息,请参阅状态代码及其在 gRPC 中的用法

Github

本文示例代码:https://github.com/MayueCif/GrpcDemo

.Net Core gRPC 实战(二)的更多相关文章

  1. .Net Core gRPC 实战(一)

    gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架. gRPC 的主要优点是: 现代高性能轻量级 RPC 框架. 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现. 可用 ...

  2. 【无私分享:ASP.NET CORE 项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 增加对多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且 ...

  3. 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本 ...

  4. .net core grpc consul 实现服务注册 服务发现 负载均衡(二)

    在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...

  5. java版gRPC实战之二:服务发布和调用

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. 【无私分享:ASP.NET CORE 项目实战(第八章)】读取配置文件(二) 读取自定义配置文件

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 我们在 读取配置文件(一) appsettings.json 中介绍了,如何读取appsettings.json. 但随之产生 ...

  7. ASP.NET Core gRPC 入门全家桶

    一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...

  8. 【无私分享:ASP.NET CORE 项目实战】目录索引

    简介 首先,我们的  [无私分享:从入门到精通ASP.NET MVC]   系列已经接近尾声,希望大家在这个过程中学到了一些思路和方法,而不仅仅是源码. 因为是第一次写博客,我感觉还是比较混乱的,其中 ...

  9. 【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...

随机推荐

  1. Summary: DOM modification techniques

    Modifying an existing element We covered various ways that you can modify aspects of an existing ele ...

  2. Sublime插件安装和使用

    Sublime插件安装和使用 插件安装的方式: 插件安装方式一:直接安装 下载插件安装包,然后把安装解压到packages目中,按成安装(菜单->首选项->浏览插件) 插件安装方法二:使用 ...

  3. 数据库函数-常用的MySQL函数

    1.date_sub() 时间的加减 备注:record 为datetime类型 select record_time as date, order_area as orderArea, order_ ...

  4. .NET 5学习笔记(12)——WinUI 3 Project Reunion 0.5

    2021年3月的时候,Win UI 3终于来到了第一个稳定的支持版本,可用于创建发布到Micosoft Store的应用.据某软的说法,这个叫WinUI 3 Project Reunion 0.5的版 ...

  5. Windows PR提权

    目录 提权利用的漏洞 PR提权 提权利用的漏洞 Microsoft Windows RPCSS服务隔离本地权限提升漏洞 RPCSS服务没有正确地隔离 NetworkService 或 LocalSer ...

  6. SQL Server 数据库基本使用技巧

    use master; #显示数据库 select top 3 * from spt_values; #显示去前3行 select * from test where id2 like '%1010% ...

  7. Windows核心编程 第三章 内核对象

    第3章内核对象 在介绍Windows API的时候,首先要讲述内核对象以及它们的句柄.本章将要介绍一些比较抽象的概念,在此并不讨论某个特定内核对象的特性,相反只是介绍适用于所有内核对象的特性. 首先介 ...

  8. LeetCode---84. 柱状图中最大的矩形(hard)

    题目:84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度.每个柱子彼此相邻,且宽度为 1 . 求在该柱状图中,能够勾勒出来的矩形的最大面积. 示例: 输入: [2,1,5 ...

  9. Sublim text3汉化

    Sublime text3汉化步骤: 一.打开已安装好的Sublime text3 二.打开后点击"Preferences",在弹出的选项中找到package Control. 三 ...

  10. myysql 不能远程访问的解决办法

    1.通过navicat或者命令行,将user表中原来host=localhost的改为host=% 命令行方式: mysql> update user set host = '%' where ...