.Net Core gRPC 实战(二)
概述
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 实战(二)的更多相关文章
- .Net Core gRPC 实战(一)
gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架. gRPC 的主要优点是: 现代高性能轻量级 RPC 框架. 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现. 可用 ...
- 【无私分享:ASP.NET CORE 项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 增加对多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且 ...
- 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本 ...
- .net core grpc consul 实现服务注册 服务发现 负载均衡(二)
在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...
- java版gRPC实战之二:服务发布和调用
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 【无私分享:ASP.NET CORE 项目实战(第八章)】读取配置文件(二) 读取自定义配置文件
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 我们在 读取配置文件(一) appsettings.json 中介绍了,如何读取appsettings.json. 但随之产生 ...
- ASP.NET Core gRPC 入门全家桶
一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...
- 【无私分享:ASP.NET CORE 项目实战】目录索引
简介 首先,我们的 [无私分享:从入门到精通ASP.NET MVC] 系列已经接近尾声,希望大家在这个过程中学到了一些思路和方法,而不仅仅是源码. 因为是第一次写博客,我感觉还是比较混乱的,其中 ...
- 【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...
随机推荐
- Java 高精度浮点数计算工具
说起编程中的高精度数值,我第一反应就是double类型了.的确,double阶码11位,尾数52位,几乎能应对任何苛刻的要求......然而,当我天真地尝试用double来算泰勒展开式的函数值,离散代 ...
- Ubuntu 20.04 简述环境配置&美化
不敢说是最好的,基本上是最全面的了~ 修改系统软件源 一开始是国外的源比较慢,建议换成国内的源,常用的有清华源.阿里源等. 清华源地址 Ubuntu 的软件源配置文件是 /etc/apt/source ...
- Centos7 安装RabbitMQ及配置(亲测)
Rabbit MQ Linux 安装 Centos7 如果是重装先把erlang和rabbitmq卸载干净,不然还会重装失败<rabbitmq和erlang卸载> 记得删除/var/lib ...
- 【CompletableFuture】CompletableFuture中join()和get()方法的区别
一.相同点: join()和get()方法都是用来获取CompletableFuture异步之后的返回值 二.区别: 1.join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者 ...
- IDA动态调试Android的DEX文件
Android程序的dex文件的动态调试确实是个大问题,网上也有一些教程但是不是特别的详细,今天用到了IDA动态调试Android的DEX文件,特此记录一下. IDA 6.6新添加了对dex文件的调试 ...
- hdu2371 矩阵乘法(求序列位置改变m次后的序列)
题意: 给你一个字符串,然后让你执行m次操作,每次操作把当前的字符串映射到他给你的位置序列的位置,比如给的是 3 1 2,第一步就是把原来的3的位置的字母变到1的位置,1的变到2的位置,2 ...
- Windows认证体系解读
目录 Windows认证方式 Windows本地认证 NTLM认证方式(工作组环境中) wiresharek抓包NTLMv2,使用Hashcat爆破 NTLM认证方式(域环境中) Kerberos认证 ...
- XCTF-ics-04
ics-04 题目描述 工控云管理系统新添加的登录和注册页面存在漏洞,请找出flag. 解题过程 拿dirsearch扫一波,没有什么有用的东西 注册个账号,登陆被提示普通用户登录成功,没什么用 登陆 ...
- [LeetCode每日一题]80. 删除有序数组中的重复项 II
[LeetCode每日一题]80. 删除有序数组中的重复项 II 问题 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度. 不要使用额外 ...
- 如何使用java搭建一款高性能的Mqtt集群broker!
SMQTT是一款开源的MQTT消息代理Broker, SMQTT基于Netty开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持 ...