介绍

通过应用服务调用,您的应用程序能够应用规范的gRPC或HTTP协定与其余应用程序牢靠、平安地通信。

为什么不间接用HttpClientFactory呢

先问几个问题:

  • 如何发现和调用不同服务的办法
  • 如何平安地调用其余服务,并对办法利用访问控制
  • 如何解决重试和瞬态谬误
  • 如何应用分布式跟踪指标来查看调用图来诊断生产中的问题

此时你会发现这些事件HttpClientFactory没有帮你实现,而在微服务中这些又是必不可少的能力,接下来看看服务调用都做了什么

服务调用如何工作的

先看一下两个服务之间的调用程序

  1. 服务A 向服务B发动一个HTTP/gRPC的调用。调用转到了本地的Dapr sidecar
  2. Dapr应用名称解析组件发现服务B的地位
  3. Dapr 将音讯转发至服务 B的 Dapr sidecar

    : Dapr sidecar之间的所有调用都通过gRPC来进步性能。 仅服务与 Dapr sidecar之间的调用能够是 HTTP或gRPC

  4. 服务B 的 Dapr sidecar将申请转发至服务B 上的特定端点 (或办法) 。 服务B 随后运行其业务逻辑代码
  5. 服务B 发送响应给服务A。 响应将转至服务B 的Dapr sidecar
  6. Dapr 转发响应至服务A 的 Dapr sidecar
  7. 服务 A 接管响应

命名空间作用域

默认状况下,调用同一个命名空间的其余服务能够间接应用AppID(假如是:nodeapp)

localhost:3500/v1.0/invoke/nodeapp/method/neworder

服务调用也反对跨命名空间调用,在所有受反对的宿主平台上,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

localhost:3500/v1.0/invoke/nodeapp.production/method/neworder

这在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文件

var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.MapPost("/", () => Console.WriteLine("Hello!"));app.MapGet("/Hello1", () =>{    Console.WriteLine("Hello World1!");    return $"\"Hello World1!\"";});app.MapPost("/Hello2", () => Console.WriteLine("Hello World2!"));app.Map("/Hello3", () => Console.WriteLine("Hello World3!"));app.Run();

此时一共有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关上命令行工具,并执行上面命令

dapr run --app-id assignment-server --app-port 5000 dotnet watch
仔细的小伙伴应该能够发现与上一篇的命令有一点点不同,dontet run变成了dotnet watch,这样会开启热重载,不便调试

调用服务:再关上一个新的命令行工具,并执行上面命令

dapr invoke --app-id assignment-server --method /dapr invoke --app-id assignment-server --method Hello1dapr invoke --app-id assignment-server --method Hello2dapr invoke --app-id assignment-server --method Hello3

能够发现4个命令都调用胜利了,然而Assignment.Server输入后果有点意外

== APP == Hello!== APP == Hello World2!== APP == Hello World3!

是的,没有Hello World1!,那怎么办呢?咱们把Hello1的命令改一下

dapr invoke --app-id assignment-server --method Hello1 --verb GET

invoke调用的输入除了App invoked successfully以外还多了一行Hello World1!

与此同时Assignment.Server的输入正确了

== APP == Hello World1!

除此之外invoke还有一些参数,比方--data,--data-file,喜爱钻研Dapr CLI的小伙伴能够持续尝试。不过个别状况下用SDK就能够了

创立Assignment.Client

HTTP服务调用

创立控制台应用程序我的项目,应用NuGet包管理器增加Dapr.Client SDK,并批改Program.cs文件

using Dapr.Client;var appId = "assignment-server";var client = new DaprClientBuilder().Build();await client.InvokeMethodAsync(appId, "/");var resp = await client.InvokeMethodAsync<string>(HttpMethod.Get, appId, "Hello1");Console.WriteLine($"Hello1 Response: {resp}");await client.InvokeMethodAsync(appId, "Hello2");await client.InvokeMethodAsync(appId, "Hello3");

看几个细节

  • DaprClient是从DaprClinetBuilder Build进去的

    还有一种形式应用DaprClient,通过DI

    首先都是须要增加Dapr.AspNetCore NuGet包

    而后开始有分支了,如果是以前Web API的形式能够在Startup.cs文件ConfigureServices办法退出一行代码

    services.AddControllers().AddDapr();

    如果应用Minimal API默认是没有Controllers的,那能够在var builder = WebApplication.CreateBuilder(args); 之后退出一行代码

    builder.Services.AddDaprClient();

    胜利的注入进来了,在构造函数或者[FromServices]里欢快的游玩吧

  • HttpMethod.Post 的我都没有指定,默认就是Post
  • HttpMethod.Get的时候,返回值会主动用Json反序列化

    不喜爱Json?能够通过 DaprClient.CreateInvokeHttpClient 结构 HttpClient,聪慧的你必定晓得前面怎么办了

注:

1. Minimal API虽香,但新,所以不是所有性能都反对,比方从参数中间接映射状态治理,要等Minimal API反对Model Binder当前且SDK也同步反对了才能够2. DaprClient是TCP的,也是线程平安的,能够大胆的复用,如果不必DI的话不须要频繁构建DaprClient

验证调用胜利

应用命令行工具关上目录dapr-study-room\Assignment04\Assignment.Client,而后执行命令

dotnet run

如果你不是用VS Code终端的PowerShell执行dapr run就可能遇到上面的谬误

即使你没有遇到也倡议理解一下如何反对非默认端口

An exception occurred while invoking method: '/' on app-id: 'assignment-server' ---> System.Net.Http.HttpRequestException: 因为指标计算机踊跃回绝,无奈连贯。 (127.0.0.1:3500) ---> System.Net.Sockets.SocketException (10061): 因为指标计算机踊跃回绝,无奈连贯。

因为下面应用dapr run的时候没有指定dapr http port,而默认client拜访的是3500端口

解决的方法有两种:

  1. 批改Assignment.Server启动参数,减少--dapr-http-port 3500,这个办法治标不治本,因为未来咱们可能启动多个服务

    dapr run --app-id assignment-server --app-port 5000 --dapr-http-port 3500 dotnet watch
  2. 批改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执行上面命令

    $Env:DAPR_HTTP_PORT = 51460dotnet run

再执行一次dotnet run就能够看到正确的输入后果了

Hello1 Response: Hello World1!

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/dap...

咱们正在口头,新的框架、新的生态

咱们的指标是自在的易用的可塑性强的功能丰富的强壮的

所以咱们借鉴Building blocks的设计理念,正在做一个新的框架MASA Framework,它有哪些特点呢?

  • 原生反对Dapr,且容许将Dapr替换成传统通信形式
  • 架构不限,单体利用、SOA、微服务都反对
  • 反对.Net原生框架,升高学习累赘,除特定畛域必须引入的概念,保持不造新轮子
  • 丰盛的生态反对,除了框架以外还有组件库、权限核心、配置核心、故障排查核心、报警核心等一系列产品
  • 外围代码库的单元测试覆盖率90%+
  • 开源、收费、社区驱动
  • 还有什么?咱们在等你,一起来探讨
通过几个月的生产我的项目实际,已实现POC,目前正在把之前的积攒重构到新的开源我的项目中

目前源码已开始同步到Github(文档站点在布局中,会缓缓欠缺起来):

MASA.BuildingBlocks

MASA.Contrib

MASA.Utils

MASA.EShop

BlazorComponent

MASA.Blazor

QQ群:7424099

微信群:加技术经营微信(MasaStackTechOps),备注来意,邀请进群

转载自:(鬼谷子)