Dapr + .NET Core实战(二) 服务调用
服務(wù)調(diào)用是什么
在分布式應(yīng)用程序中的服務(wù)之間進(jìn)行調(diào)用會涉及到許多挑戰(zhàn)。例如:
維護(hù)其他服務(wù)的地址。
如何安全地調(diào)用服務(wù)。
在發(fā)生短暫的 暫時(shí)性錯誤 時(shí)如何處理重試。
分布式應(yīng)用程序調(diào)用鏈路追蹤。
服務(wù)調(diào)用構(gòu)建塊通過使用 Dapr 挎斗作為服務(wù)的 反向代理 來解決這些難題。
工作原理
由于調(diào)用經(jīng)過Sidecar,Dapr 可以注入一些有其他行為:
失敗時(shí)自動重試調(diào)用。
通過相互 (mTLS) 身份驗(yàn)證(包括自動證書滾動更新),在服務(wù)之間進(jìn)行調(diào)用。
使用訪問控制策略控制客戶端可以執(zhí)行的操作。
捕獲服務(wù)間所有調(diào)用的跟蹤和指標(biāo),以提供分布式調(diào)用鏈路追蹤與診斷。
任何應(yīng)用程序都可以通過使用?Dapr 中內(nèi)置的本機(jī) Invoke API?來調(diào)用 Dapr Sidecar??梢酝ㄟ^ HTTP 或 gRPC 調(diào)用 API。使用以下 URL 調(diào)用 HTTP API:
http://localhost:<dapr-port>/v1.0/invoke/<application-id>/method/<method-name><dapr-port>?Dapr 正在偵聽的 HTTP 端口。
<application-id>?要調(diào)用的服務(wù)的應(yīng)用程序 ID。
<method-name>?要在遠(yuǎn)程服務(wù)上調(diào)用的方法的名稱。
項(xiàng)目演示
我們使用.NET5創(chuàng)建兩個(gè)WebAPI項(xiàng)目:BackEnd和FrontEnd,通過FrontEnd調(diào)用BackEnd
指定BackEnd默認(rèn)啟動端口5000
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>().UseUrls("http://*:5000");});通過Dapr CLI啟動BackEnd,指定sidecar端口為3511,默認(rèn)為3500,指定app-port是5000,與BackEnd默認(rèn)端口保持一致
dapr run --dapr-http-port 3511 --app-port 5000 --app-id backend dotnet .\BackEnd\bin\Debug\net5.0\BackEnd.dllC:\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.現(xiàn)在修改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調(diào)用HTTP服務(wù)
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調(diào)用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方法調(diào)用了backend服務(wù)中的WeatherForecastAPI。
Sidecar使用可插接式名稱解析組件來解析服務(wù)BackEnd的地址。在自承載模式下,Dapr 使用?mdn?來查找它。在 Kubernetes 模式下運(yùn)行時(shí),Kubernetes DNS?服務(wù)將確定地址。
2.使用 DaprClient調(diào)用HTTP服務(wù)
// 通過DaprClient調(diào)用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.使用注入方式調(diào)用 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同樣可以調(diào)用GRPC
await daprClient.InvokeMethodGrpcAsync<Order, OrderConfirmation>("orderservice", "submitOrder", order);與HTTP調(diào)用方式一致,不再為GRPC新建server
通過Dapr CLI啟動FrontEnd,指定sidecar端口為3501,默認(rèn)為3500,指定app-port是5001,與FrontEnd默認(rèn)端口保持一致
dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dllC:\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查看運(yùn)行中的app
dapr listAPP ID HTTP PORT GRPC PORT APP PORT COMMAND AGE CREATED PIDbackend 3511 1033 5000 dotnet .\BackEnd\... 9s 2021-09-24 09:25.17 860frontend 3501 1056 5001 dotnet .\FrontEnd... 7s 2021-09-24 09:25.19 5236測試調(diào)用
1.瀏覽器地址欄輸入
http://localhost:3501/v1.0/invoke/frontend/method/daprhttp://localhost:3501/v1.0/invoke/frontend/method/dapr/get2http://localhost:3501/v1.0/invoke/frontend/method/DaprDI可以看到正常響應(yīng)
?2.DaprCLI測試調(diào)用
打開cmd輸入
dapr invoke --app-id frontend --verb "GET" --method dapr也可以看到調(diào)用成功
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 successfullyPS:單機(jī)運(yùn)行的情況下,每個(gè)服務(wù)的sidecar是一個(gè)進(jìn)程,名為daprd,下圖兩個(gè)分別是backend和frontend連個(gè)服務(wù)的
?鏈路追蹤
自承載的方式下,Dapr默認(rèn)啟動了zipkin容器,可以通過以下鏈接查看
http://localhost:9411/zipkin/總結(jié)
以上是生活随笔為你收集整理的Dapr + .NET Core实战(二) 服务调用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET 6 数组拷贝性能对比
- 下一篇: WPF DataGrid 通过自定义表头