.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也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...
随机推荐
- Docker系列——InfluxDB+Grafana+Jmeter性能监控平台搭建(三)
在之前系列博文中,已经介绍完了数据采集和数据存储,那数据如何展示呢?所以今天就专门来讲下数据如何展示的问题. 以前博文参考: Docker系列--InfluxDB+Grafana+Jmeter性能监控 ...
- gitlab支持https最简单方法
gitlab支持https方法 使用gitlab内部nginx直接支持https 通过外部nginx代理(本次使用的方法) 访问流程外部nginx--->gitlab的gitlab_workho ...
- 【JVM】JVM中的垃圾收集器
垃圾收集器组合 Serial+Serial Old Serial+CMS ParNew+CMS ParNew+Serial Old Paralle Scavenge + Serial Old Para ...
- hdu4888 最大流(构造矩阵)
题意: 让你构造一个矩阵,满足每一行的和,和每一列的和都等于他给的,还要判断答案是否唯一,还有一点就是矩阵内所有的数字都是[0,k]范围的. 思路: 这个题目看完就让我想起了h ...
- Python模块化编程
目录 模块化 自定义模块 模块的内置属性 导入模块 安装第三方模块 查看模块的属性和方法 模块化 在Python中,一个.py文件就称之为一个模块(Module),为了避免模块名冲突,Python又引 ...
- Python脚本与Metasploit交互攻击
Metasploit是一款强大的漏洞扫描和利用工具,编写Python脚本与Metasploit进行交互,可以自动化的扫描和利用漏洞. 相关文章:Metasploit框架的使用 在脚本中,我们首选需要利 ...
- CVE-2013-2551:Internet Explore VML COALineDashStyleArray 整数溢出漏洞简单调试分析
0x01 2013 Pwn2Own 黑客大赛 在 Pwn2Own 的黑客大赛上,来自法国的 VUPEN 安全团队再一次利用 0day 漏洞攻破 Windows8 环境下的 IE10 浏览器,这一次问题 ...
- WPF中属性经动画处理后无法更改的问题
在WPF的Animation中,有一个属性为FillBehavior,用于指定时间线在其活动周期结束后但其父时间线仍处于活动周期或填充周期时的行为方式.如果希望动画在活动周期结束时保留其值,则将动画F ...
- JetBrains系列软件用法
IDEA JSON格式化 IDEA的JSON_Formatter插件,下载地址 安装方式:File->Settings->Plugins,然后选择INstall plugin from d ...
- maven工程添加servlet依赖
实现导入HttpServlet <!-- Servlet依赖--> <dependency> <groupId>javax.servlet</groupId& ...