4小时Dapr+.NET 5+K8S 的实战 https://ke.qq.com/course/4000292?tuin=1271860f
Dapr进阶虚拟机集群实战(非K8S) https://ke.qq.com/course/4002149?tuin=1271860f
服务调用是什么
在分布式应用程序中的服务之间进行调用会涉及到许多挑战。 例如:
- 维护其他服务的地址。
- 如何安全地调用服务。
- 在发生短暂的 暂时性错误 时如何处理重试。
- 分布式应用程序调用链路追踪。
服务调用构建块通过使用 Dapr 挎斗作为服务的 反向代理 来解决这些难题。
工作原理
由于调用经过Sidecar,Dapr 可以注入一些有其他行为:
- 失败时自动重试调用。
- 通过相互 (mTLS) 身份验证(包括自动证书滚动更新),在服务之间进行调用。
- 使用访问控制策略控制客户端可以执行的操作。
- 捕获服务间所有调用的跟踪和指标,以提供分布式调用链路追踪与诊断。
任何应用程序都可以通过使用 Dapr 中内置的本机 Invoke API 来调用 Dapr Sidecar。 可以通过 HTTP 或 gRPC 调用 API。 使用以下 URL 调用 HTTP API:
http://localhost:<dapr-port>/v1.0/invoke/<application-id>/method/<method-name>
<dapr-port>
Dapr 正在侦听的 HTTP 端口。<application-id>
要调用的服务的应用程序 ID。<method-name>
要在远程服务上调用的方法的名称。
项目演示
我们使用.NET5创建两个WebAPI项目:BackEnd和FrontEnd,通过FrontEnd调用BackEnd
指定BackEnd默认启动端口5000
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>().UseUrls("http://*:5000"); });
通过Dapr CLI启动BackEnd,指定sidecar端口为3511,默认为3500,指定app-port是5000,与BackEnd默认端口保持一致
dapr run --dapr-http-port 3511 --app-port 5000 --app-id backend dotnet .\BackEnd\bin\Debug\net5.0\BackEnd.dll
C:\demo\test\DaprBackEnd>dapr run --dapr-http-port 3511 --app-port 5000 --app-id backend dotnet .\BackEnd\bin\Debug\net5.0\BackEnd.dll Starting Dapr with id backend. HTTP Port: 3511. gRPC Port: 30204 time="2021-09-23T14:14:08.3785429+08:00" level=info msg="starting Dapr Runtime -- version 1.4.0 -- commit ed969edc72b3934fffb481f079b736f3588e373a" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.3831089+08:00" level=info msg="log level set to: info" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.3831089+08:00" level=info msg="metrics server started on :30205/" app_id=backend instance=chesterchen-lap scope=dapr.metrics type=log ver=1.4.0 time="2021-09-23T14:14:08.3861203+08:00" level=info msg="standalone mode configured" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.3861203+08:00" level=info msg="app id: backend" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.3871107+08:00" level=info msg="mTLS is disabled. Skipping certificate request and tls validation" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4115681+08:00" level=info msg="local service entry announced: backend -> 10.32.193.9:30209" app_id=backend instance=chesterchen-lap scope=dapr.contrib type=log ver=1.4.0 time="2021-09-23T14:14:08.4115681+08:00" level=info msg="Initialized name resolution to mdns" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4127024+08:00" level=info msg="loading components" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4160224+08:00" level=info msg="component loaded. name: pubsub, type: pubsub.redis/v1" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4160224+08:00" level=info msg="waiting for all outstanding components to be processed" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4187042+08:00" level=info msg="component loaded. name: statestore, type: state.redis/v1" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4187042+08:00" level=info msg="all outstanding components processed" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4192486+08:00" level=info msg="enabled gRPC tracing middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.grpc.api type=log ver=1.4.0 time="2021-09-23T14:14:08.4192486+08:00" level=info msg="enabled gRPC metrics middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.grpc.api type=log ver=1.4.0 time="2021-09-23T14:14:08.4192486+08:00" level=info msg="API gRPC server is running on port 30204" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4197888+08:00" level=info msg="enabled metrics http middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.http type=log ver=1.4.0 time="2021-09-23T14:14:08.4197888+08:00" level=info msg="enabled tracing http middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.http type=log ver=1.4.0 time="2021-09-23T14:14:08.4202954+08:00" level=info msg="http server is running on port 3511" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.420335+08:00" level=info msg="The request body size parameter is: 4" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.420335+08:00" level=info msg="enabled gRPC tracing middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.grpc.internal type=log ver=1.4.0 time="2021-09-23T14:14:08.4225403+08:00" level=info msg="enabled gRPC metrics middleware" app_id=backend instance=chesterchen-lap scope=dapr.runtime.grpc.internal type=log ver=1.4.0 time="2021-09-23T14:14:08.4230868+08:00" level=info msg="internal gRPC server is running on port 30209" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.4230868+08:00" level=info msg="application protocol: http. waiting on port 5000. This will block until the app is listening on that port." app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Now listening on: http://[::]:5000 == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Application started. Press Ctrl+C to shut down. == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Hosting environment: Production == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Content root path: C:\demo\test\DaprBackEnd time="2021-09-23T14:14:08.7252681+08:00" level=info msg="application discovered on port 5000" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1] == APP == Request starting HTTP/1.1 GET http://127.0.0.1:5000/dapr/config application/json - == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2] == APP == Request finished HTTP/1.1 GET http://127.0.0.1:5000/dapr/config application/json - - 404 0 - 17.3850ms time="2021-09-23T14:14:08.7693649+08:00" level=info msg="application configuration loaded" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:14:08.7699003+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" app_id=backend instance=chesterchen-lap scope=dapr.runtime.actor type=log ver=1.4.0 == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1] == APP == Request starting HTTP/1.1 GET http://127.0.0.1:5000/dapr/subscribe application/json - == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2] time="2021-09-23T14:14:08.7736383+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 387.518ms" app_id=backend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 == APP == Request finished HTTP/1.1 GET http://127.0.0.1:5000/dapr/subscribe application/json - - 404 0 - 0.1789ms time="2021-09-23T14:14:08.7888444+08:00" level=info msg="placement tables updated, version: 0" app_id=backend instance=chesterchen-lap scope=dapr.runtime.actor.internal.placement type=log ver=1.4.0 Updating metadata for app command: dotnet .\BackEnd\bin\Debug\net5.0\BackEnd.dll You're up and running! Both Dapr and your app logs will appear here.
现在修改FrontEnd里Demo,指定启动端口5001
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>().UseUrls("http://*:5001"); });
引入Nuget包 Dapr.Client,新建DaprController
1.使用 HttpClient调用HTTP服务
using Dapr.Client; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; namespace FrontEnd.Controllers { [ApiController] [Route("[controller]")] public class DaprController : ControllerBase { private readonly ILogger<DaprController> _logger; public DaprController(ILogger<DaprController> logger) { _logger = logger; } // 通过HttpClient调用BackEnd [HttpGet] public async Task<ActionResult> GetAsync() { using var httpClient = DaprClient.CreateInvokeHttpClient(); var result = await httpClient.GetAsync("http://backend/WeatherForecast"); var resultContent = string.Format("result is {0} {1}", result.StatusCode, await result.Content.ReadAsStringAsync()); return Ok(resultContent); } } }
GetAsync API中通过DaprClient.CreateInvokeHttpClient()新建了HttpClient,通过GetAsync方法调用了backend服务中的WeatherForecastAPI。
Sidecar使用可插接式名称解析组件来解析服务BackEnd的地址。在自承载模式下,Dapr 使用 mdn 来查找它。 在 Kubernetes 模式下运行时,Kubernetes DNS 服务将确定地址。
2.使用 DaprClient调用HTTP服务
// 通过DaprClient调用BackEnd [HttpGet("get2")] public async Task<ActionResult> Get2Async() { using var daprClient = new DaprClientBuilder().Build(); var result = await daprClient.InvokeMethodAsync<IEnumerable<WeatherForecast>>(HttpMethod.Get, "backend", "WeatherForecast"); return Ok(result); }
DaprController中新增API Get2Async
3.使用注入方式调用 DaprClient
首先引入Nuget包Dapr.AspNetCore,然后在Startup.cs注入Dapr
public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddDapr(); }
新建DaprDIController
using Dapr.Client; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; namespace FrontEnd.Controllers { [Route("[controller]")] [ApiController] public class DaprDIController : ControllerBase { private readonly ILogger<DaprDIController> _logger; private readonly DaprClient _daprClient; public DaprDIController(ILogger<DaprDIController> logger, DaprClient daprClient) { _logger = logger; _daprClient = daprClient; } [HttpGet()] public async Task<ActionResult> GetAsync() { var result = await _daprClient.InvokeMethodAsync<IEnumerable<WeatherForecast>>(HttpMethod.Get, "backend", "WeatherForecast"); return Ok(result); } } }
以上代码通过注入方式注入DaprClient
4.使用DaprClient同样可以调用GRPC
await daprClient.InvokeMethodGrpcAsync<Order, OrderConfirmation>("orderservice", "submitOrder", order);
与HTTP调用方式一致,不再为GRPC新建server
通过Dapr CLI启动FrontEnd,指定sidecar端口为3501,默认为3500,指定app-port是5001,与FrontEnd默认端口保持一致
dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll
C:\demo\test\DaprBackEnd>dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll Starting Dapr with id frontend. HTTP Port: 3501. gRPC Port: 1045 time="2021-09-23T14:15:24.5222236+08:00" level=info msg="starting Dapr Runtime -- version 1.4.0 -- commit ed969edc72b3934fffb481f079b736f3588e373a" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5269659+08:00" level=info msg="log level set to: info" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5269659+08:00" level=info msg="metrics server started on :1046/" app_id=frontend instance=chesterchen-lap scope=dapr.metrics type=log ver=1.4.0 time="2021-09-23T14:15:24.5302603+08:00" level=info msg="standalone mode configured" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5302904+08:00" level=info msg="app id: frontend" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5302904+08:00" level=info msg="mTLS is disabled. Skipping certificate request and tls validation" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.559128+08:00" level=info msg="local service entry announced: frontend -> 10.32.193.9:1051" app_id=frontend instance=chesterchen-lap scope=dapr.contrib type=log ver=1.4.0 time="2021-09-23T14:15:24.559128+08:00" level=info msg="Initialized name resolution to mdns" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.560108+08:00" level=info msg="loading components" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5641089+08:00" level=info msg="component loaded. name: pubsub, type: pubsub.redis/v1" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5641089+08:00" level=info msg="waiting for all outstanding components to be processed" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5671082+08:00" level=info msg="component loaded. name: statestore, type: state.redis/v1" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5671082+08:00" level=info msg="all outstanding components processed" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5671082+08:00" level=info msg="enabled gRPC tracing middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.grpc.api type=log ver=1.4.0 time="2021-09-23T14:15:24.5671082+08:00" level=info msg="enabled gRPC metrics middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.grpc.api type=log ver=1.4.0 time="2021-09-23T14:15:24.5671082+08:00" level=info msg="API gRPC server is running on port 1045" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5684039+08:00" level=info msg="enabled metrics http middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.http type=log ver=1.4.0 time="2021-09-23T14:15:24.5700491+08:00" level=info msg="enabled tracing http middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.http type=log ver=1.4.0 time="2021-09-23T14:15:24.5700491+08:00" level=info msg="http server is running on port 3501" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5705931+08:00" level=info msg="The request body size parameter is: 4" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5705931+08:00" level=info msg="enabled gRPC tracing middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.grpc.internal type=log ver=1.4.0 time="2021-09-23T14:15:24.5705931+08:00" level=info msg="enabled gRPC metrics middleware" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.grpc.internal type=log ver=1.4.0 time="2021-09-23T14:15:24.5711294+08:00" level=info msg="internal gRPC server is running on port 1051" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.5711294+08:00" level=info msg="application protocol: http. waiting on port 5001. This will block until the app is listening on that port." app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Now listening on: http://[::]:5001 == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Application started. Press Ctrl+C to shut down. == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Hosting environment: Production == APP == info: Microsoft.Hosting.Lifetime[0] == APP == Content root path: C:\demo\test\DaprBackEnd time="2021-09-23T14:15:24.8729143+08:00" level=info msg="application discovered on port 5001" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1] == APP == Request starting HTTP/1.1 GET http://127.0.0.1:5001/dapr/config application/json - == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2] == APP == Request finished HTTP/1.1 GET http://127.0.0.1:5001/dapr/config application/json - - 404 0 - 19.0408ms time="2021-09-23T14:15:24.9188354+08:00" level=info msg="application configuration loaded" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.9193692+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.actor type=log ver=1.4.0 == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1] == APP == Request starting HTTP/1.1 GET http://127.0.0.1:5001/dapr/subscribe application/json - == APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2] == APP == Request finished HTTP/1.1 GET http://127.0.0.1:5001/dapr/subscribe application/json - - 404 0 - 0.2000ms time="2021-09-23T14:15:24.9236093+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 393.349ms" app_id=frontend instance=chesterchen-lap scope=dapr.runtime type=log ver=1.4.0 time="2021-09-23T14:15:24.9393948+08:00" level=info msg="placement tables updated, version: 0" app_id=frontend instance=chesterchen-lap scope=dapr.runtime.actor.internal.placement type=log ver=1.4.0 Updating metadata for app command: dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll You're up and running! Both Dapr and your app logs will appear here.
Dapr CLI查看运行中的app
dapr list
APP ID HTTP PORT GRPC PORT APP PORT COMMAND AGE CREATED PID backend 3511 1033 5000 dotnet .\BackEnd\... 9s 2021-09-24 09:25.17 860 frontend 3501 1056 5001 dotnet .\FrontEnd... 7s 2021-09-24 09:25.19 5236
测试调用
1.浏览器地址栏输入
http://localhost:3501/v1.0/invoke/frontend/method/dapr
http://localhost:3501/v1.0/invoke/frontend/method/dapr/get2
http://localhost:3501/v1.0/invoke/frontend/method/DaprDI
可以看到正常响应
2.DaprCLI测试调用
打开cmd输入
dapr invoke --app-id frontend --verb "GET" --method dapr
也可以看到调用成功
C:\Users\chesterychen>dapr invoke --app-id frontend --verb "GET" --method dapr result is OK [{"date":"2021-09-24T14:20:51.2386681+08:00","temperatureC":47,"temperatureF":116,"summary":"Mild"},{"date":"2021-09-25T14:20:51.2386705+08:00","temperatureC":50,"temperatureF":121,"summary":"Mild"},{"date":"2021-09-26T14:20:51.2386707+08:00","temperatureC":34,"temperatureF":93,"summary":"Hot"},{"date":"2021-09-27T14:20:51.2386708+08:00","temperatureC":42,"temperatureF":107,"summary":"Bracing"},{"date":"2021-09-28T14:20:51.2386709+08:00","temperatureC":-19,"temperatureF":-2,"summary":"Warm"}] App invoked successfully
PS:单机运行的情况下,每个服务的sidecar是一个进程,名为daprd,下图两个分别是backend和frontend连个服务的
链路追踪
自承载的方式下,Dapr默认启动了zipkin容器,可以通过以下链接查看
http://localhost:9411/zipkin/