手把手教你学 Dapr - 4. 服务调用
介绍
通过使用服务调用,您的应用程序可以使用标准的 gRPC 或 HTTP 协议与其他应用程序可靠、安全地通信。
为什么不直接用 HttpClientFactory 呢
先问几个问题:
如何发现和调用不同服务的方法
如何安全地调用其他服务,并对方法应用访问控制
如何处理重试和瞬态错误
如何使用分布式跟踪指标来查看调用图来诊断生产中的问题
此时你会发现这些事情 HttpClientFactory 没有帮你完成,而在微服务中这些又是必不可少的能力,接下来看看服务调用都做了什么
服务调用如何工作的
先看一下两个服务之间的调用顺序
服务 A 向服务 B 发起一个 HTTP/gRPC 的调用。调用转到了本地的 Dapr sidecar
Dapr 使用名称解析组件发现服务 B 的位置
Dapr 将消息转发至服务 B 的 Dapr sidecar
注: Dapr sidecar 之间的所有调用都通过 gRPC 来提高性能。 仅服务与 Dapr sidecar 之间的调用可以是 HTTP 或 gRPC
服务 B 的 Dapr sidecar 将请求转发至服务 B 上的特定端点 (或方法) 。 服务 B 随后运行其业务逻辑代码
服务 B 发送响应给服务 A。 响应将转至服务 B 的 Dapr sidecar
Dapr 转发响应至服务 A 的 Dapr sidecar
服务 A 接收响应
命名空间作用域
默认情况下,调用同一个命名空间的其他服务可以直接使用 AppID(假设是:nodeapp)
服务调用也支持跨命名空间调用,在所有受支持的宿主平台上,Dapr AppID 遵循 FQDN 格式,其中包括目标命名空间。
FQDN:(Fully Qualified Domain Name)全限定域名:同时带有主机名和域名的名称。(通过符号“.”)
例如:主机名是 bigserver,域名是 mycompany.com,那么 FQDN 就是 bigserver.mycompany.com
**注:**FQDN 是通过符号.
来拼接域名的,这也就解释了 AppID 为什么不能用符号.
,这里不记住的话,应该会有不少小伙伴会踩坑
比如.net 开发者习惯用 A.B.C
来命名项目,但 AppID 需要把.
换成-
且所有单词最好也变成小写 (a-b-c),建议把它变成约定遵守
比如调用命名空间:production,AppID:nodeapp
这在 K8s 集群中的跨名称空间调用中特别有用
服务间安全性
通过托管平台上的相互(mTLS)身份验证,包括通过 Dapr Sentry 服务的自动证书转移,可以确保 Dapr 应用程序之间的所有调用的安全。 下图显示了自托管应用程序的情况。
访问控制
应用程序可以控制哪些其他应用程序可以调用它们,以及通过访问策略授权它们做什么。 这使您能够限制具有个人信息的敏感应用程序不被未经授权的应用程序访问,并结合服务到服务的安全通信,提供了软多租户部署。
具体的访问控制后续章节会介绍
重试
在调用失败和瞬态错误的情况下,服务调用执行自动重试,并在回退时间段内执行。
**注:**自动重试,默认是开启的,可以关。但如果不关且业务又不支持幂等是很危险的。建议服务的接口要设计支持幂等,这在微服务里也是一个标配的选择。
导致重试的错误有:
网络错误,包括端点不可用和拒绝连接。
由于在调用/被调用的 Dapr sidecars 上更新证书而导致的身份验证错误。
每次呼叫重试的回退间隔为 1 秒,最多为 3 次。 通过 gRPC 与目标 Sidecar 连接的超时时间为 5 秒
可插拔的服务发现
Dapr 可以在各种托管平台上运行。 为了启用服务发现和服务调用,Dapr 使用可插拔的名称解析组件。 例如,K8s 名称解析组件使用 K8s DNS 服务来解析集群中运行的其他应用程序的位置。 自托管机器可以使用 mDNS 名称解析组件。 Consul 名称解析组件可以在任何托管环境中使用,包括 K8s 或自托管环境
划重点,自托管机器使用 mDNS,在开发环境中后面文章会推荐 VS 上的无缝开发体验,就是基于 mDNS 的
但它有点点小问题,我们已经解决了。你只需要像开发一个控制台程序一样,基于 Minimal API 开心的 F5 就可以了
建议还没有了解 Minimal API 的小伙伴可以研究起来了,真香
使用 mDNS 进行轮询负载均衡
一图胜千言,就使用 mDNS 轮着调用
可观测性的跟踪和指标
默认情况下,将跟踪应用程序之间的所有调用,并收集指标,以提供应用程序的洞察力和诊断,这在生产场景中尤其重要。 这为您提供了服务之间调用的调用图和指标。
服务调用 API 和 gRPC 代理
pythonapp 通过 Dapr sidecar 调用 nodeapp,通过服务调用的 API 及 gRPC 代理依然是上面见到的那个调用流程,做到了语言无关
使用 HTTP 调用服务
创建 Assignment.Server
创建ASP.NET Core空
项目,并修改launchSettings.json
,让启动 HTTP 的启动端口变为 5000
profiles.Assignment.Server.applicationUrl 的值改为 "https://localhost:6000;http://localhost:5000"
修改Program.cs
文件
此时一共有 4 个服务
/ :Post 方法,打印 Hello!
/Hello1:Get 方法,打印 Hello World1!,返回 Hello World1!
**注:**返回的类型要是 Json 字符串,方便 SDK 反序列化
/Hello2:Post 方法,打印 Hello World2!
/Hello3:不带后缀表示适配所有方法,打印 Hello World3!
先使用 Dapr CLI 来验证一下
运行Assignment.Server
:在目录dapr-study-room\Assignment04\Assignment.Server
打开命令行工具,并执行下面命令
细心的小伙伴应该可以发现与上一篇的命令有一点点不同,dontet run 变成了 dotnet watch,这样会开启热重载,方便调试
调用服务:再打开一个新的命令行工具,并执行下面命令
可以发现 4 个命令都调用成功了,但是Assignment.Server
输出结果有点意外
是的,没有Hello World1!
,那怎么办呢?我们把 Hello1 的命令改一下
invoke 调用的输出除了App invoked successfully
以外还多了一行Hello World1!
与此同时Assignment.Server
的输出正确了
除此之外invoke
还有一些参数,比如--data
,--data-file
,喜欢研究 Dapr CLI 的小伙伴可以继续尝试。不过一般情况下用 SDK 就可以了
创建 Assignment.Client
HTTP 服务调用
创建控制台应用程序
项目,使用 NuGet 包管理器添加Dapr.Client
SDK,并修改Program.cs
文件
看几个细节
DaprClient 是从
DaprClinetBuilder
Build 出来的还有一种方式使用 DaprClient,通过 DI
首先都是需要添加
Dapr.AspNetCore
NuGet 包然后开始有分支了,如果是以前 Web API 的方式可以在 Startup.cs 文件
ConfigureServices
方法加入一行代码
如果使用 Minimal API 默认是没有 Controllers 的,那可以在var builder = WebApplication.CreateBuilder(args);
之后加入一行代码
成功的注入进来了,在构造函数
或者[FromServices]
里愉快的玩耍吧
HttpMethod.Post 的我都没有指定,默认就是 Post
HttpMethod.Get 的时候,返回值会自动用 Json 反序列化
不喜欢 Json?可以通过 DaprClient.CreateInvokeHttpClient 构造 HttpClient,聪明的你肯定知道后面怎么办了
注:
验证调用成功
使用命令行工具打开目录dapr-study-room\Assignment04\Assignment.Client
,然后执行命令
如果你不是用 VS Code 终端的 PowerShell 执行 dapr run 就可能遇到下面的错误
即便你没有遇到也建议了解一下如何支持非默认端口
因为上面使用 dapr run 的时候没有指定 dapr http port,而默认 client 访问的是 3500 端口
解决的办法有两种:
修改
Assignment.Server
启动参数,增加--dapr-http-port 3500
,这个方法治标不治本,因为将来我们可能启动多个服务
修改
Assignment.Client
的环境变量首先执行
dapr list
查看端口,以下面为例,HTTP PORT 是51460
APP ID HTTP PORT GRPC PORT APP PORT COMMAND AGE CREATED PID
assignment-server 51460 51461 5000 dotnet watch 7s 2021-10-29 14:13.49 11676
修改
Assignment.Client
的启动参数,注意把51460
换成你自己的端口,使用PowerShell
执行下面命令
再执行一次dotnet run
就可以看到正确的输出结果了
gRPC 服务调用
篇幅太长了,举一反三吧。就是调用InvokeMethodGrpcAsync
,然后 dapr-http-port 换成 dapr-grpc-port,DAPR_HTTP_PORT 换成 DAPR_GRPC_PORT
查看跟踪
还记得 dapr init 的时候 docker 里有个 zipkin 吧,通过 zipkin 可以看一下调用跟踪,通过浏览器打开下面地址
http://localhost:9411/
此时页面是空的
根据步骤操作一下就可以看到了
随便点开一行数据尾部的 SHOW,就可以看到调用详情
本章源码
Assignment04
https://github.com/doddgu/dapr-study-room
我们正在行动,新的框架、新的生态
我们的目标是自由的
、易用的
、可塑性强的
、功能丰富的
、健壮的
。
所以我们借鉴 Building blocks 的设计理念,正在做一个新的框架MASA Framework
,它有哪些特点呢?
原生支持 Dapr,且允许将 Dapr 替换成传统通信方式
架构不限,单体应用、SOA、微服务都支持
支持.Net 原生框架,降低学习负担,除特定领域必须引入的概念,坚持不造新轮子
丰富的生态支持,除了框架以外还有组件库、权限中心、配置中心、故障排查中心、报警中心等一系列产品
核心代码库的单元测试覆盖率 90%+
开源、免费、社区驱动
还有什么?我们在等你,一起来讨论
经过几个月的生产项目实践,已完成 POC,目前正在把之前的积累重构到新的开源项目中
目前源码已开始同步到 Github(文档站点在规划中,会慢慢完善起来):
QQ 群:7424099
微信群:加技术运营微信(MasaStackTechOps),备注来意,邀请进群
MASA 技术团队:(鬼谷子)
版权声明: 本文为 InfoQ 作者【MASA技术团队】的原创文章。
原文链接:【http://xie.infoq.cn/article/5e33b02f60ff0a28b2a3dbcf4】。文章转载请联系作者。
评论